Deploy Qualys Cloud Agent with Azure Policy¶
Qualys Cloud Agent is available as an Azure VM extension1. This makes mass-deployment of the agent with Azure Policy very enjoyable. This post will go through the components of the DeployIfNotExists
policy, remediation and troubleshooting.
Prerequisites¶
- Qualys License Code
- Windows and Linux Azure VMs for testing
- Read how VM extensions for Windows2 and Linux3 work
- Policy Definitions from the repo -
- Knowledge about ARM templates5 and
DeployIfNotExists
policies4
Extension infos to be used in policies:
Windows | Linux | |
---|---|---|
Agent name/type | QualysAgent |
QualysAgentLinux |
Publisher | Qualys |
Qualys |
typeHandlerVersion | 3.1 |
1.6 |
autoUpgradeMinorVersion | true |
true |
Policy Definitions¶
The JSON definitions in the Github Repo can be converted to Azure Policy Defintions with Powershell:
New-AzPolicyDefinition -Name 'Policyname' -DisplayName 'Displayname of the policy' -Policy './difne-linux-qualys.json'
Policy Evaluation¶
VMs can be tagged with noqualysagent : true
to be ignored by this policy. The ignore tag key and value can be configured in policy parameters.
Info
The osType
VM property is evaluated for agent install, this should be filtered by the supported OS list6 from Qualys.
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType",
"equals": "Windows"
},
{
"anyOf": [
{
"field": "[concat('tags[', parameters('excludetagname'), ']')]",
"exists": false
},
{
"field": "[concat('tags[', parameters('excludetagname'), ']')]",
"notEquals": "[parameters('excludetagvalue')]"
}
]
}
]
}
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"field": "Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType",
"like": "Linux*"
},
{
"anyOf": [
{
"field": "[concat('tags[', parameters('excludetagname'), ']')]",
"exists": false
},
{
"field": "[concat('tags[', parameters('excludetagname'), ']')]",
"notEquals": "[parameters('excludetagvalue')]"
}
]
}
]
}
Policy Effect¶
Please read about the DeployIfNotExists
policy effect and the properties used4
With existenceCondition
we can check for child resources of Microsoft.Compute/virtualMachines
, such as Microsoft.Compute/virtualMachines/extensions
. If the condition is met (i.e. the extension is already successfully installed), the ARM template deployment will be skipped.
evaluationDelay
specifies the time after VM deployment until the policy triggers.
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "QualysAgent",
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"//(1)!
],
"evaluationDelay": "AfterProvisioning",
"existenceCondition": {
"allOf": [
{
"field": "Microsoft.Compute/virtualMachines/extensions/type",
"equals": "QualysAgent"
},
{
"field": "Microsoft.Compute/virtualMachines/extensions/publisher",
"equals": "Qualys"
},
{
"field": "Microsoft.Compute/virtualMachines/extensions/provisioningState",
"equals": "Succeeded"
}
]
},
"deployment": {
...
}
}
}
- The property
roleDefinitionIds
is described here
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "QualysAgentLinux",
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"//(1)!
],
"evaluationDelay": "AfterProvisioning",
"existenceCondition": {
"allOf": [
{
"field": "Microsoft.Compute/virtualMachines/extensions/type",
"equals": "QualysAgentLinux"
},
{
"field": "Microsoft.Compute/virtualMachines/extensions/publisher",
"equals": "Qualys"
},
{
"field": "Microsoft.Compute/virtualMachines/extensions/provisioningState",
"equals": "Succeeded"
}
]
},
"deployment": {
...
}
}
}
- The property
roleDefinitionIds
is described here
ARM Template Deployment¶
Qualys also provides an ARM template for agent deployment on Github. That template can be slightly modified and used to deploy the agent with the policy.
"deployment": {
"properties": {
"mode": "incremental",
"parameters": {//(1)!
"vmName": {
"value": "[field('name')]"
},
"location": {
"value": "[field('location')]"
},
"licensecode": {
"value": "[parameters('licensecode')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmName": {
"type": "string"
},
"location": {
"type": "string"
},
"licensecode": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2019-07-01",
"name": "[concat(parameters('vmName'), '/QualysAgent')]",//(2)!
"type": "Microsoft.Compute/virtualMachines/extensions",
"location": "[parameters('location')]",
"properties": {
"publisher": "Qualys",
"type": "QualysAgent",
"autoUpgradeMinorVersion": true,
"typeHandlerVersion": "3.1",
"settings": {
"LicenseCode": "[parameters('licensecode')]"
},
"protectedSettings": {}
}
}
]
}
}
}
- Parameters passed from the policy to the ARM template
- The
name
property has to be{vmName}/QualysAgent
.vmName
will be passed by the policy through parameters (see full policy definition) to the template
"deployment": {
"properties": {
"mode": "incremental",
"parameters": {//(1)!
"vmName": {
"value": "[field('name')]"
},
"location": {
"value": "[field('location')]"
},
"licensecode": {
"value": "[parameters('licensecode')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmName": {
"type": "string"
},
"location": {
"type": "string"
},
"licensecode": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2019-07-01",
"name": "[concat(parameters('vmName'), '/QualysAgentLinux')]",//(2)!
"type": "Microsoft.Compute/virtualMachines/extensions",
"location": "[parameters('location')]",
"properties": {
"publisher": "Qualys",
"type": "QualysAgentLinux",
"autoUpgradeMinorVersion": true,
"typeHandlerVersion": "1.6",
"settings": {
"LicenseCode": "[parameters('licensecode')]"
},
"protectedSettings": {}
}
}
]
}
}
}
- Parameters passed from the policy to the ARM template
- The
name
property has to be{vmName}/QualysAgentLinux
.vmName
will be passed by the policy through parameters (see full policy definition) to the template
Policy Assignment¶
Important
After assigning the Policy Definition, the policy will evaluate newly created resources based on the defined criteria and deploy the agent if the conditions are met. Existing resources have to be remediated with a remediation task manually.
Even when the extension is manually uninstalled after deployment, the policy will not remediate (reinstall the extension) automatically. A remediation task has to be used, the VM will be marked as non-compliant though
Create the Policy Assignment¶
- Create the assignment and set scope
- Specify required parameters
- Specify managed identity, don't create a remediation task yet
Managed Identity and RBAC¶
DeployIfNotExists
policies require a managed identity to be created. The managed identity is assigned the permissions defined in the roleDefinitionIds
property.
In this case, /providers/microsoft.authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c
is the ID of the built-in Virtual Machine Contributor
role, see AzRoleAdvertizer - Virtual Machine Contributor
RBAC custom roles can also be created and used, the minimum permissions needed are:
Microsoft.Resources/deployments/read
Microsoft.Resources/deployments/write
Microsoft.Resources/deployments/validate/action
Microsoft.Resources/deployments/operations/read
Microsoft.Resources/deployments/operationstatuses/read
Microsoft.Compute/virtualMachines/extensions/read
Microsoft.Compute/virtualMachines/extensions/write
Remediation Task¶
-
To remediate existing resources, create a remediation task. Choose the policy assignment to remediate:
-
The task should show the resources that need remediation on the bottom, if the evaluation has not happened, check the
Re-evaluate resource compliance before remediating
. The remediation task with re-evaluation enabled takes about ~15-30min longer to complete -
When the task is completed, it shows succeeded and failed resources
Deployment Success¶
- Extension status is
Provisioning Succeeded
:
- Server is visible in the Qualys Portal:
Troubleshooting Deployment Errors¶
Deployment errors are displayed in the remediation task. In the example below, Rocky Linux
is not supported by the agent. Besides not supported OS versions, VMs that are powered off will fail.
If encountering problems with the agent, you might want to take a look at the agent logs
Example: Rocky Linux not supported
Checking the install script mentioned in the error message shows the following regex:
The install script (/var/lib/waagent/Qualys.QualysAgentLinux-1.6.1.4/bin/avme_install.sh
) will check for /etc/redhat-release
and match to a regex. This regex does currently not include Rocky Linux
. The problem will be fixed in December 2023 according to Qualys
Deploy extension with AzCLI¶
List VM extensions available:
➜ az vm extension image list --publisher Qualys --latest -o table
Name Publisher Version
-------------------------------- ----------------------------- ---------
QualysAgentGL Qualys.WindowsAgent.GrayLabel 1.0.0.2
LinuxAgent.AzureSecurityCenter Qualys 1.0.0.17
QualysAgentGL Qualys.LinuxAgent.GrayLabel 1.0.0.2
QualysAgent Qualys 3.1.3.34
QualysAgentLinux Qualys 1.6.1.4
WindowsAgent.AzureSecurityCenter Qualys 1.0.0.21
Install extension with AzCLI:
➜ az vm extension set --publisher Qualys --name QualysAgentLinux --settings '{"LicenseCode": "LICENSECODE"}' --ids "/subscriptions/SUBSCRIPTIONID/resourceGroups/RGNAME/providers/Microsoft.Compute/virtualMachines/VMNAME"
{
"autoUpgradeMinorVersion": true,
"enableAutomaticUpgrade": null,
"forceUpdateTag": null,
"id": "/subscriptions/SUBSCRIPTIONID/resourceGroups/RGNAME/providers/Microsoft.Compute/virtualMachines/VMNAME/extensions/QualysAgentLinux",
"instanceView": null,
"location": "westeurope",
"name": "QualysAgentLinux",
"protectedSettings": null,
"protectedSettingsFromKeyVault": null,
"provisioningState": "Succeeded",
"publisher": "Qualys",
"resourceGroup": "RGNAME",
"settings": {
"LicenseCode": "LICENSECODE"
},
"suppressFailures": null,
"tags": null,
"type": "Microsoft.Compute/virtualMachines/extensions",
"typeHandlerVersion": "1.6",
"typePropertiesType": "QualysAgentLinux"
}
Agent Logs¶
Agent logs can be found in C:\WindowsAzure\Logs\Qualys.QualysAgent\3.1.3.34\Asclog.txt
Agent installer is located in C:\Packages\Plugins\Qualys.QualysAgent\3.1.3.34\
Agent Logs: /var/log/qualys/qualys-cloud-agent.log
Extension Logs: /var/log/azure/Qualys.QualysAgentLinux/lxagent.log
Install directory: /usr/local/qualys/cloud-agent/bin
Install script: /var/lib/waagent/Qualys.QualysAgentLinux-1.6.1.4/bin/avme_install.sh
Config files: /etc/qualys/cloud-agent/