Search code examples
azurecategoriespolicyazure-diagnostics

How to audit logging categories in Diagnostic settings via Azure policy?


I have a policy to audit when a diagnostic settings with a specific configuration for a particular Azure service does not exist. This would be applied to several services (Event Hub, Key Vault, Postgres Single Server), to ensure a pre-defined logging configuration is in place.

The problem I'm facing is at auditing that specific logging categories are selected in each diagnostic settings. Using Postgres as an example, which has these logging categories:

  • PostgreSQLLogs
  • QueryStoreRuntimeStatistics
  • QueryStoreWaitStatistics

And say that I want to enforce only "PostgreSQLLogs" is selected in my DS. Using the policy alias "Microsoft.Insights/diagnosticSettings/logs[*].enabled" this would imply a configuration like: [true, false, false]. So, this is the value that I should set-up in my policy to audit it for compliance. But whichever value I try in my policy will either not be accepted by Azure or not fulfilling my objective.

The following is my policy rule code:

"policyRule": {
  "if": {
    "equals": "Microsoft.DBforPostgreSQL/servers",
    "field": "type"
  },
  "then": {
    "details": {
      "type": "Microsoft.Insights/diagnosticSettings",
      "existenceCondition": {
        "allOf": [
          {
            "field": "Microsoft.Insights/diagnosticSettings/logs[*].enabled",
            "equals": "[ true, false, false ]"
          },
          {
            "field": "Microsoft.Insights/diagnosticSettings/logs[*].category",
            "equals": "['PostgreSQLLogs']"
          },
          {
            "field": "Microsoft.Insights/diagnosticSettings/workspaceId",
            "matchInsensitively": "[parameters('my_logAnalytics')]"
          }
        ]
      }
    },
    "effect": "AuditIfNotExists"
  }

Which generates this error when saved in the Portal:

readyState: 4 responseText: {"error":{"code":"InvalidPolicyParameters","message":"A function or parameter in policy 'e8b95433-42c5-4ed4-8a0c-1e7ad5ac2572' could not be validated. If using template functions, try following the tips in: https://aka.ms/policy-avoiding-template-failures. The inner exception 'Unable to parse language expression ' true, false, false ': expected token 'LeftParenthesis' and actual 'Comma'.'."}} status: 400 statusText: error

Quoting the elements of the array will raise the same error:

        {
          "field": "Microsoft.Insights/diagnosticSettings/logs[*].enabled",
          "equals": "[ 'true','false','false' ]"
        },

And when I try something like this, it will be accepted:

        {
          "field": "Microsoft.Insights/diagnosticSettings/logs[*].enabled",
          "equals": "[ 'true' ]"
        },

But this is not what I am looking for because it flags my resource as not compliant with the following message (see screenshot):

Reason for non-compliance: Current value must be equal to the target value
Field: Microsoft.Insights/diagnosticSettings/logs[*].enabled
Path: properties.logs[*].enabled
Current value: [true,false,false]
Target value: "true"

Solution

  • If I understand correctly, you want to check each value of the logs array and test whether .enabled is true when .category is PostgresSQLLogs. You really need to use a count here - "this evaluates each [*] alias array member for a condition expression and sums the true results". You can use a complex expression in the condition:

          "existenceCondition": {
            "allOf": [
              {
                "count": {
                  "field": "Microsoft.Insights/diagnosticSettings/logs[*]",
                  "where": {
                    "allOf": [
                      {
                        "field": "Microsoft.Insights/diagnosticSettings/logs[*].enabled",
                        "equals": "True"
                      },
                      {
                        "field": "Microsoft.Insights/diagnosticSettings/logs[*].category",
                        "equals": "PostgresSQLLogs"
                      }
                    ]
                  }
                },
                "greater": 0
              },
              {
                "field": "Microsoft.Insights/diagnosticSettings/workspaceId",
                "matchInsensitively": "[parameters('my_logAnalytics')]"
              }
            ]
          }
    

    You would need a similar count block inside the outer "allOf" for the other category values.