SMS Blog

Use Azure Automation Runbook to deploy Nessus Agent via Terraform

Problem

All Virtual Machines (VMs) in the Azure environment must have Nessus Agent installed and registered to a newly created Nessus Manager without direct SSH or RDP access to any of the VMs.

Solution

Use an existing Azure Automation Account to deploy the Nessus Agent via a runbook. The runbook will add a Virtual Machine extension that will have the necessary steps to install and register the Nessus Agent based on the Operating System. This solution can be used to install pretty much anything on a Windows or Linux Virtual Machine.

What is an Azure Automation Account?

An Azure Automation Account is a cloud-based management service provided by Microsoft, designed to help automate, orchestrate, and manage repetitive tasks and processes within the Azure environment. It serves as a centralized location for storing various automation assets, such as runbooks, credentials, and integration modules, enabling users to streamline their automation efforts and improve operational efficiency.

In this case, an existing Azure Automation Account that was previously created is being used for this effort. If you don’t have an existing one, you can create a new one strictly for this purpose. There are a couple of requirements that are needed to make this work.

  • Associate a User-assigned Managed Identity with at a minimum, the “Virtual Machine Contributor” Azure role to all subscriptions in your tenant.
  • The Azure Automation Account must be linked to the same Log Analytics workspace that your VMs are linked. In this environment this task was previously taken care of to accomplish another effort. To associate VMs to a Log Analytics workspace, you will need the OMS or the MMA agent. See the link below as there are many ways to tackle this.

As mentioned above, if you don’t already have an Automation Account, you will need to create one. Below is an example of creating an Azure Automation Account with Terraform.

resource "azurerm_automation_account" "aa_account" {
location = "<azure region>"
name     = "<name of account>"
resource_group_name = var.rg
identity {
  identity_ids = ["<Your Managed identity ids>"]
  type         = "UserAssigned
}

What is an Azure Automation Runbook?

An Azure Automation Runbook is a set of tasks or operations that you can automate within the Azure environment. It is essentially a collection of PowerShell or Python script(s) that perform various actions, such as managing resources, configuring systems, or handling other operational tasks. Azure Automation Runbooks are commonly used for automating repetitive tasks, scheduling maintenance activities, and orchestrating complex workflows within Azure.

PowerShell 5.x was the scripting language used for this task, in part because Terraform does not currently support Powershell 7.1 as a runbook type. (e.g. https://github.com/hashicorp/terraform-provider-azurerm/issues/14089).

Terraform

Terraform is the current Infrastructure As Code tool for this environment therefore it used in this scenario. Below is a snippet of the main.tf

Let’s take a look at the Terraform code:

resource "azurerm_automation_runbook" "nessus_install" {
  name                    = var.runbook_name
  location                = data.azurerm_resource_group.ops.location
  resource_group_name     = data.azurerm_automation_account.ops.resource_group_name
  automation_account_name = data.azurerm_automation_account.ops.name
  log_verbose             = true
  log_progress            = true
  description             = var.runbook_description
  runbook_type            = var.runbook_type
  tags                    = var.default_tags
  content = templatefile("${path.module}/runbook/nessus.ps1", {
    umi                         = data.azurerm_user_assigned_identity.identity.client_id
    tenantid                    = var.tenant_id
    scriptnamelinux             = var.scritpname_linux
    scriptnamewindows           = var.scritpname_win
    storageaccountcontainer     = data.azurerm_storage_container.sa.name
    storageaccountresourcegroup = data.azurerm_resource_group.sa.name
    storageaccountname          = var.sa_acct
    workbookname                = var.runbook_name
    storageaccountsub           = data.azurerm_subscription.sa.subscription_id
    client_id                   = data.azurerm_user_assigned_identity.identity.client_id
    vms_to_exclude              = join(",", [for vm in local.vms_file_content : "\"${vm}\""])
    defaultsub                  = ""
  })
}

resource "azurerm_automation_job_schedule" "nessus_install" {
  resource_group_name     = data.azurerm_automation_account.ops.resource_group_name
  automation_account_name = data.azurerm_automation_account.ops.name
  schedule_name           = azurerm_automation_schedule.nessus_install.name
  runbook_name            = azurerm_automation_runbook.nessus_install.name

}

resource "azurerm_automation_schedule" "nessus_install" {
  name                    = var.nessus_schedule
  resource_group_name     = data.azurerm_automation_account.ops.resource_group_name
  automation_account_name = data.azurerm_automation_account.ops.name
  frequency               = var.schedule_frequency
  timezone                = var.timezone
  start_time              = var.start_time
  description             = var.schedule_description
  week_days               = var.week_days
  expiry_time             = var.expiry_time
}

azurerm_automation_runbook:  This section defines the Azure Automation Runbook, including its name, location, resource group, and related configurations. The templatefile is using several inputs that allow you to modify your variables and have your script configured with the desired output. The script utilizes a PowerShell script file named `nessus.ps1`, which is responsible for orchestrating the Nessus installation process and covered in the next section.

azurerm_automation_job_schedule: Here, we set up an Azure Automation Job Schedule, which determines the frequency and timing of the execution of the Nessus installation process.

azurerm_automation_schedule: This section specifies the details of the schedule, including the frequency, time zone, start time, and expiry time for the Nessus installation process. This needs to be run on a weekly basis to incorporate any new VMs that get created in any subscription.

If you choose to use the code as-is, the variables used in the templatefile are explained below.

    umi  = User Managed Identity that is associated with the Azure Automation Account
    tenantid                    = The Tenant ID 
    scriptnamelinux             = Name of Linux shell script
    scriptnamewindows           = Name of Windows script
    storageaccountcontainer     = Name of the Storage Account where the scripts reside
    storageaccountresourcegroup = Name of the Resource Group where the Storage Account resides
    storageaccountname          = Name of the Storage Account
    workbookname                = Name of the Runbook you are creating
    storageaccountsub           = The Subscription ID of the Storage Account
    vms_to_exclude              = join(",", [for vm in local.vms_file_content : "\"${vm}\""])
    defaultsub                  = "" # If you want to loop through all active subscriptions leave this as-is, if not put in the subscription you want to this script to run against

vms_to_exclude variable was configured so you can skip VMs by name if you choose. An issue occurred where a VM’s resources were pegged and the script would eventually error out waiting for the VM to finish. So this logic was inserted to mitigate that. A flat txt file “vms.txt” is used for this purpose, you can just list all VMs in this file, one per line.

Powershell

Let’s take a look at the Powershell script that is being called nessus.ps1

Disable-AzContextAutosave -Scope Process

$AzureContext = (Connect-AzAccount -Identity -Environment AzureUSGovernment -AccountId ${umi}).context
$TenantId = '${tenantid}'
$scriptNameLinux = '${scriptnamelinux}'
$scriptNameWindows = '${scriptnamewindows}'
$storageAccountContainer = '${storageaccountcontainer}'
$storageAccountResourceGroup = '${storageaccountresourcegroup}'
$storageAccountName = '${storageaccountname}'
$defaultSubscriptionId = '${defaultsub}'

$settingsLinux = @{
    "fileUris"         = @("https://$storageAccountName.blob.core.usgovcloudapi.net/$storageAccountContainer/$scriptNameLinux")
    "commandToExecute" = "bash $scriptNameLinux"
} | ConvertTo-Json

$settingsWindows = @{
    "fileUris"         = @("https://$storageAccountName.blob.core.usgovcloudapi.net/$storageAccountContainer/$scriptNameWindows")
    "commandToExecute" = "powershell -NonInteractive -ExecutionPolicy Unrestricted -File $scriptNameWindows"
} | ConvertTo-Json

$storageKey = (Get-AzStorageAccountKey -Name $storageAccountName -ResourceGroupName $storageAccountResourceGroup)[0].Value

$protectedSettingsLinux = @{
    "storageAccountName" = $storageAccountName
    "storageAccountKey"  = $storageKey
} | ConvertTo-Json

$protectedSettingsWindows = @{
    "storageAccountName" = $storageAccountName
    "storageAccountKey"  = $storageKey
} | ConvertTo-Json

$currentAZContext = Get-AzContext

if ($currentAZContext.Tenant.id -ne $TenantId) {
    Write-Output "This script is not authenticated to the needed tenant. Running authentication."
    Connect-AzAccount -TenantId $TenantId
}
else {
    Write-Output "This script is already authenticated to the needed tenant - reusing authentication."
}

$subs = @()

if ($defaultSubscriptionId -eq "") {
    $subs = Get-AzSubscription -TenantId $TenantId | Where-Object { $_.State -eq "Enabled" }
}
else {
    if ($defaultSubscriptionId.IndexOf(',') -eq -1) {
        $subs = Get-AzSubscription -TenantId $TenantId -SubscriptionId $defaultSubscriptionId
    }
    else {
        $defaultSubscriptionId = $defaultSubscriptionId -replace '\s', ''
        $subsArray = $defaultSubscriptionId -split ","
        foreach ($subsArrayElement in $subsArray) {
            $currTempSub = Get-AzSubscription -TenantId $TenantId -SubscriptionId $subsArrayElement
            $subs += $currTempSub
        }
    }
}



$excludeVmNamesArray = (${vms_to_exclude})


foreach ($currSub in $subs) {
    Set-AzContext -subscriptionId $currSub.id -Tenant $TenantId

    if (!$?) {
        Write-Output "Error occurred during Set-AzContext. Error message: $( $error[0].Exception.InnerException.Message )"
        Write-Output "Trying to disconnect and reconnect."
        Disconnect-AzAccount
        Connect-AzAccount -TenantId $TenantId -SubscriptionId $currSub.id
        Set-AzContext -subscriptionId $currSub.id -Tenant $TenantId
    }

    $VMs = Get-AzVM

    foreach ($vm in $VMs) {
        if ($excludeVmNamesArray -contains $vm.Name) {
            Write-Output "Skipping VM $($vm.Name) as it is excluded."
            continue
        }

        $status = (Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status).Statuses[1].DisplayStatus

        if ($status -eq "VM running") {
            Write-Output "Processing running VM $( $vm.Name )"

            $extensions = (Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name).Extensions

            foreach ($ext in $extensions) {
                if ($null -ne $vm.OSProfile.WindowsConfiguration) {
                    if ($ext.VirtualMachineExtensionType -eq "CustomScriptExtension") {
                        Write-Output "Removing CustomScriptExtension with name $( $ext.Name ) from VM $( $vm.Name )"
                        Remove-AzVMExtension -ResourceGroupName $vm.ResourceGroupName -VMName $vm.Name -Name $ext.Name -Force
                        Write-Output "Removed CustomScriptExtension with name $( $ext.Name ) from VM $( $vm.Name )"
                    }
                }
                else {
                    if ($ext.VirtualMachineExtensionType -eq "CustomScript") {
                        Write-Output "Removing CustomScript extension with name $( $ext.Name ) from VM $( $vm.Name )"
                        Remove-AzVMExtension -ResourceGroupName $vm.ResourceGroupName -VMName $vm.Name -Name $ext.Name -Force
                        Write-Output "Removed CustomScript extension with name $( $ext.Name ) from VM $( $vm.Name )"
                    }
                }
            }

            if ($vm.StorageProfile.OsDisk.OsType -eq "Windows") {
                Write-Output "Windows VM detected: $( $vm.Name )"
                $settingsOS = $settingsWindows
                $protectedSettingsOS = $protectedSettingsWindows
                $publisher = "Microsoft.Compute"
                $extensionType = "CustomScriptExtension"
                $typeHandlerVersion = "1.10"
            }
            elseif ($vm.StorageProfile.OsDisk.OsType -eq "Linux") {
                Write-Output "Linux VM detected: $( $vm.Name )"
                $settingsOS = $settingsLinux
                $protectedSettingsOS = $protectedSettingsLinux
                $publisher = "Microsoft.Azure.Extensions"
                $extensionType = "CustomScript"
                $typeHandlerVersion = "2.1"
            }
            $customScriptExtensionName = "NessusInstall"

            Write-Output "$customScriptExtensionName installation on VM $( $vm.Name )"

            Set-AzVMExtension -ResourceGroupName $vm.ResourceGroupName `
                -Location $vm.Location `
                -VMName $vm.Name `
                -Name $customScriptExtensionName `
                -Publisher $publisher `
                -ExtensionType $extensionType `
                -TypeHandlerVersion $typeHandlerVersion `
                -SettingString $settingsOS `
                -ProtectedSettingString $protectedSettingsOS

            Write-Output "---------------------------"
        }
        else {
            Write-Output "VM $( $vm.Name ) is not running, skipping..."
        }
    }

    Set-AzContext -SubscriptionId $defaultSubscriptionId -Tenant $TenantId
}

This particular environment is in the AzureGOV region but could be modified to use any region.

The script is designed to automate the deployment of custom scripts/extensions to multiple Azure VMs across different subscriptions. It provides flexibility for both Linux and Windows VMs and ensures that any existing custom script extensions are removed before deployment; this is because you cannot have an extension with the same name.

OS Scripts

Now lets look at the windows script that the “nessus.ps1” calls

$installerUrl = "<URL to the msi>"


$NESSUS_GROUP="<Name of your Nessus Group>"

$NESSUS_KEY="<Name of Nessus Key>"

$NESSUS_SERVER="<FQDN of Nessus Server>"

$NESSUS_PORT="<Port if different from standard 8834>"

$installerPath = "C:\TEMP\nessusagent.msi"

$windows_package_name = "'Nessus Agent (x64)'"

$installed = Get-WmiObject -Query "SELECT * FROM Win32_Product WHERE Name = $windows_package_name" | Select-Object Name

function Test-Admin {

    $currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())

    $currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)

}

 

if ((Test-Admin) -eq $false) {

    if ($elevated) {

    }

    else {

        Start-Process powershell.exe -Verb RunAs -ArgumentList ('-noprofile -file "{0}" -elevated' -f ($myinvocation.MyCommand.Definition))

    }

    exit

}

 
'running with full privileges'

if ($installed) {

    Write-Output "Nessus Agent is already installed. Exiting."

}

else {

    Write-Output "Downloading Nessus Agent MSI installer..."

    Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath


    Write-Output "Installing Nessus Agent..."

    Start-Process -FilePath msiexec.exe -ArgumentList '/i C:\TEMP\nessusagent.msi NESSUS_GROUPS="$NESSUS_GROUP" NESSUS_SERVER="$NESSUS_SERVER" NESSUS_KEY='$NESSUS_KEY' /qn' -Wait

    $installed = Get-WmiObject -Query "SELECT * FROM Win32_Product WHERE Name = $windows_package_name" | Select-Object Name


    if ($installed) {

        Write-Output "Nessus Agent has been successfully installed."

    }

    else {

        Write-Output "Failed to install Nessus Agent."

    }

}

 
if (Test-Path $installerPath) {

    Remove-Item -Path $installerPath -Force

}

 
Function Start-ProcessGetStream {


    [CmdLetBinding()]

    Param(

        [System.IO.FileInfo]$FilePath,

        [string[]]$ArgumentList

    )


    $pInfo = New-Object System.Diagnostics.ProcessStartInfo

    $pInfo.FileName = $FilePath

    $pInfo.Arguments = $ArgumentList

    $pInfo.RedirectStandardError = $true

    $pInfo.RedirectStandardOutput = $true

    $pinfo.UseShellExecute = $false

    $pInfo.CreateNoWindow = $true

    $pInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden


    $proc = New-Object System.Diagnostics.Process

    $proc.StartInfo = $pInfo


    Write-Verbose "Starting $FilePath"

    $proc.Start() | Out-Null

    Write-Verbose "Waiting for $($FilePath.BaseName) to complete"

    $proc.WaitForExit()

    $stdOut = $proc.StandardOutput.ReadToEnd()

    $stdErr = $proc.StandardError.ReadToEnd()

    $exitCode = $proc.ExitCode

 

    Write-Verbose "Standard Output: $stdOut"

    Write-Verbose "Standard Error: $stdErr"

    Write-Verbose "Exit Code: $exitCode"


    [PSCustomObject]@{

        "StdOut"   = $stdOut

        "Stderr"   = $stdErr

        "ExitCode" = $exitCode

    }

}



Function Get-NessusStatsFromStdOut {

 

    Param(

        [string]$stdOut

    )

 

    $stats = @{}

 

 

 

    $StdOut -split "`r`n" | ForEach-Object {

        if ($_ -like "*:*") {

            $result = $_ -split ":"

            $stats.add(($result[0].Trim() -replace "[^A-Za-z0-9]", "_").ToLower(), $result[1].Trim())

        }

    }


    Return $stats

}


Function Get-DateFromEpochSecond {

    Param(

        [int]$seconds

    )

 

    $utcTime = (Get-Date 01.01.1970) + ([System.TimeSpan]::fromseconds($seconds))

    Return Get-Date $utcTime.ToLocalTime() -Format "yyyy-MM-dd HH:mm:ss"

}

 
Try {

    $nessusExe = Join-Path $env:ProgramFiles -ChildPath "Tenable\Nessus Agent\nessuscli.exe" -ErrorAction Continue

}

Catch {

    Throw "Cannot find NessusCli.exe, installing..."

}

 

Write-Output "Getting Agent Status..."

$agentStatus = Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList "agent status"

 

If ($agentStatus.stdOut -eq "" -and $agentStatus.StdErr -eq "") {

    Throw "No Data Returned from NessusCli, linking now"

    Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList 'agent link --key=$NESSUS_KEY --groups="$NESSUS_GROUP" --host=$NESSUS_SERVER --port=$NESSUS_PORT'

}

elseif ($agentStatus.StdOut -eq "" -and $agentStatus.StdErr -ne "") {

    Throw "StdErr: $($agentStatus.StdErr)"

}

elseif (-not($agentStatus.stdOut -like "*Running: *")) {

    Throw "StdOut: $($agentStatus.StdOut)"

}

else {

    $stats = Get-NessusStatsFromStdOut -stdOut $agentStatus.StdOut

    If ($stats.linked_to -eq '$NESSUS_SERVER' -and $stats.link_status -ne 'Not linked to a manager') {

        Write-Output "Connected to $NESSUS_SERVER"

    }

    else {

        Write-Output "Connecting..."

        Start-ProcessGetStreams -FilePath "C:\Program Files\Tenable\Nessus Agent\nessuscli.exe" -ArgumentList 'agent link --key=$NESSUS_KEY --groups="$NESSUS_GROUP" --host=$NESSUS_SERVER --port=$NESSUS_PORT'

    }


    If ($stats.last_connection_attempt -as [int]) { $stats.last_connection_attempt = Get-DateFromEpochSeconds $stats.last_connection_attempt }

    If ($stats.last_connect -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_connect }

    If ($stats.last_scanned -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_scanned }

}

 
#$stats | Out-Host

This script streamlines the process of installing and linking the Nessus Agent to the specified Nessus server, automating various steps and ensuring the seamless deployment and integration of the agent within the intended environment.

Now lets look at the linux script that the “nessus.ps1” calls:

#!/bin/bash

exec 3>&1 4>&2

trap 'exec 2>&4 1>&3' 0 1 2 3

exec 1>/tmp/nessus-install-log.out 2>&1

 

PACKAGE_NAME="nessusagent"

ACTIVATION_CODE="<Your Nessus Activation Key/Code>"

NESSUS_HOST="<fqdn of your Nessus Manager>"

NESSUS_AGENT="/opt/nessus_agent/sbin/nessuscli"

NESSUS_PORT="<port # if different from 8834>"

NESSUS_GROUP="<name of your group>"

base_url="<url to your Storage Account>"

debian_filename="NessusAgent-10.3.1-ubuntu1404_amd64.deb" # 

redhat_7_filename="NessusAgent-10.3.1-es7.x86_64.rpm" # Redhat EL7 filename

redhat_8_filename="NessusAgent-10.3.1-es8.x86_64.rpm" # Redhat EL8 filename

 

 

if_register_agent() {

  if  "$NESSUS_AGENT" agent status | grep -q "Linked to: $NESSUS_HOST"; then

    echo "Nessus Agent is already linked to Nessus Manager."

  else

    $NESSUS_AGENT agent link --host="$NESSUS_HOST" --port="$NESSUS_PORT" --key="$ACTIVATION_CODE" --groups="$NESSUS_GROUP"

    if [ $? -eq 0 ]; then

        echo "Nessus Agent linked successfully."

        else

          echo "Failed to link Nessus Agent. Check your activation code or permissions."

          exit 1

    fi

  fi

}

 

is_package_installed_debian() {

  if  dpkg -l | grep -i "ii  $PACKAGE_NAME"; then

    if_register_agent

    return 0

  else

    return 1

  fi

}

 

is_package_installed_redhat() {

  if  rpm -qa | grep -i "$PACKAGE_NAME" > /dev/null; then

    if_register_agent

    return 0

  else

    return 1

  fi

}

 

install_package_debian() {

  echo "$PACKAGE_NAME is not installed on $ID. Installing it now..." &&

  sleep 20 &&

   wget -qP /tmp $base_url$debian_filename &&

  sleep 20 &&

   dpkg -i /tmp/"$debian_filename" &&

  sleep 20 &&

   $NESSUS_AGENT agent link --host="$NESSUS_HOST" --port="$NESSUS_PORT" --key="$ACTIVATION_CODE" --groups="$NESSUS_GROUP" &&

  sleep 20 &&

   systemctl enable nessusagent --now &&

  sleep 20 &&

   $NESSUS_AGENT agent status |  tee /tmp/nessus_agent_status &&

   sleep 20 &&

   rm -f /tmp/"$debian_filename"

   exit

}

 

 

install_package_redhat_v7() {

  echo "$PACKAGE_NAME is not installed on $ID-$VERSION_ID Installing it now..."

  yum -y install wget &&

  sleep 20 &&

   wget -qP /tmp $base_url$redhat_7_filename &&

  sleep 20 &&

   rpm -ivh /tmp/"$redhat_7_filename" &&

  sleep 20 &&

   $NESSUS_AGENT agent link --host="$NESSUS_HOST" --port="$NESSUS_PORT" --key="$ACTIVATION_CODE" --groups="$NESSUS_GROUP" &&

  sleep 20 &&

   systemctl enable nessusagent --now &&

  sleep 20 &&

   $NESSUS_AGENT agent status |  tee /tmp/nessus_agent_status &&

   rm -f /tmp/"$redhat_7_filename"

   exit

}

 

install_package_redhat_v8() {

  echo "$PACKAGE_NAME is not installed on $ID-$VERSION_ID. Installing it now..."

  sleep 20 &&

   wget -qP /tmp $base_url$redhat_8_filename &&

  sleep 20 &&

   rpm -ivh /tmp/"$redhat_8_filename" &&

  sleep 20 &&

   $NESSUS_AGENT agent link --host="$NESSUS_HOST" --port="$NESSUS_PORT" --key="$ACTIVATION_CODE" --groups="$NESSUS_GROUP" &&

  sleep 20 &&

   systemctl enable nessusagent --now &&

  sleep 20 &&

   $NESSUS_AGENT agent status |  tee /tmp/nessus_agent_status &&

   rm -f /tmp/"$redhat_8_filename"

   exit

}

 

check_debian_based() {

  lowercase_id=$(echo "$ID" | tr '[:upper:]' '[:lower:]')

  if [[ "$lowercase_id" == *debian* || "$lowercase_id" == *ubuntu* ]]; then

    if is_package_installed_debian; then

      echo "$PACKAGE_NAME is already installed on $ID."

      exit 0

    else

      install_package_debian

    fi

  fi

}

 

check_redhat_based() {

  lowercase_id=$(echo "$ID" | tr '[:upper:]' '[:lower:]')

  if [[ "$lowercase_id" == *centos* || "$lowercase_id" == *rhel* || "$lowercase_id" == *ol* || "$lowercase_id" == *el* ]]; then

    if is_package_installed_redhat; then

      echo "$PACKAGE_NAME is already installed on $ID."

      exit 0

    else

      if [[ "$VERSION_ID" == 7 ]]; then

        echo "Red Hat $ID version 7 detected."

        install_package_redhat_v7

      elif [[ "$VERSION_ID" == 8 ]]; then

        echo "Red Hat $ID version 8 detected."

        install_package_redhat_v8

      else

        echo "Unsupported version: $VERSION_ID"

        exit 1

      fi

    fi

  fi

}

 

if [ -f /etc/os-release ]; then

  . /etc/os-release

  check_debian_based

  check_redhat_based

else

  echo "Unsupported Linux distribution."

  exit 1

fi

This script is pretty much the same as the one above except it is for linux distributions. It will determine the OS type and install the necessary agent package and register the agent to the appropriate Nessus Manager.

Example of the variables.tf

variable "default_tags" {
  description = "A map of tags to add to all resources"
  type        = map(string)
  default = {
  }
}

variable "tenant_id" {
  description = "Azure AD Tenate ID of the Azure subscription"
  type        = string
}

variable "nessus_schedule" {
  description = "Name of the Schedule in Automation Account"
  type        = string
  default     = "nessus-automation-schedule"
}

variable "timezone" {
  description = "Name of the Timezone"
  type        = string
  default     = "America/New_York"
}

variable "schedule_description" {
  description = "Schedule Description"
  type        = string
  default     = "This is schedule to download and install Nessus"
}

variable "week_days" {
  description = "Schedule Description"
  type        = list(string)
  default     = ["Monday", "Wednesday", "Saturday"]
}

variable "scritpname_linux" {
  default     = "nessus-linux.sh"
  description = "Name of Linux script"
  type        = string
}

variable "scritpname_win" {
  default     = "nessus-windows.ps1"
  description = "Name of Windows script"
  type        = string
}

variable "sa_container" {
  description = "Name of the Storage Account Container"
  type        = string
}

variable "sa_rg" {
  description = "Name of the Storage Account Resource Group"
  type        = string
}

variable "sa_sub" {
  description = "Subscription ID where the Storage Account lives"
  type        = string
}


variable "sa_acct" {
  description = "Name of the Storage Account"
  type        = string
}

locals {
  vms_file_content = split("\n", file("${path.module}/vms.txt"))
}

variable "schedule_frequency" {
  description = "Job frequency"
  type        = string
  default     = "Week"
}

variable "runbook_name" {
  description = "Name of the runbook"
  type        = string
  default     = "nessus_agent_install"
}

variable "runbook_type" {
  description = "Name of the language used"
  type        = string
  default     = "PowerShell"
}

variable "runbook_description" {
  description = "Description of the Runbook"
  type        = string
  default     = "This runbook will Download and Install the Nessus Agent"
}

variable "start_time" {
  description = "When to start the runbook schedule"
  type        = string
  default     = "2024-10-07T06:00:15+02:00"
}

variable "expiry_time" {
  description = "When to start the runbook schedule"
  type        = string
  default     = "2027-10-07T06:00:15+02:00"
}

variable "identity_sub" {
  description = "Subscription where MI lives"
  type        = string
}


All the above code can be found at the link below.

https://github.com/rdeberry-sms/nessus_aa_runboook

Leave a Comment