What are Attestations in Azure Policy?

What are Attestations in Azure Policy?

With regular policies in Azure you may be familiar with some common concepts such as effect, enforcement mode, resources being compliant or non-compliant and so on and so forth.

It can be a policy that states Public network access should be disabled and if the resource has its public endpoint enabled then the policy is non-compliant and vice versa if it is disabled and only using private link then it is compliant. Not super difficult to wrap ones head around. These policies usually have an effect such as Deny to prohibit the creation of resources that do not match the criteria of the policy. You also have DeployIfNotExists which you can use together with a managed identity to remediate resources to ensure they follow suit. And you may have even seen and used policies with the Modify effect which can update your resources, also using a managed identity.

You have Audit which will just report on the resource and informing you if it is compliant or not but will not actually deny any changes made to existing or new resources that are effected by the policy. There are more, you can find all of them HERE

And then we have the manual effect policy which I recently learned about. These manual effect policies are actually quite interesting, usually found in regulatory compliance initiatives such as NIST, PCI DSS and ISO. Their default compliance state is Unknown instead of compliant or non-compliant. It can be controls that could be called Complete security training for the team

This means that you could potentially use these controls like this:

1. Every team needs to complete some basic training in Security, Azure & Terraform

2. They complete this training and supply evidence of this in some way. We create a policy attestation resource that can look something like this:

"properties": {
  "policyAssignmentId": "/subscriptions/{subscriptionID}/providers/microsoft.authorization/policyassignments/{assignmentID}",
  "policyDefinitionReferenceId": "{definitionReferenceID}",
  "complianceState": "Compliant",
  "expiresOn": "2023-07-14T00:00:00Z",
  "owner": "{AADObjectID}",
  "comments": "This subscription has passed a security audit. See attached details for evidence",
  "evidence": [
    {
      "description": "The results of the security audit.",
      "sourceUri": "https://gist.github.com/contoso/9573e238762c60166c090ae16b814011"
    },
    {
      "description": "Description of the attached evidence document.",
      "sourceUri": "https://contoso.blob.core.windows.net/contoso-container/contoso_file.docx"
    },
  ],
  "assessmentDate": "2022-11-14T00:00:00Z",
  "metadata": {
    "departmentId": "{departmentID}"
  }
}

Source: https://learn.microsoft.com/en-us/azure/governance/policy/concepts/attestation-structure#request-body

The policy becomes compliantinstead of Unknown, sort of like a super complex to-do list.

They can expire so you can make the attestation only valid for 1 year for example, then it expires and training has to be refreshed.

This is maybe way too complicated in the real world but that is at least what I think Microsoft is trying to achieve with these manual effect policies. Have you used them?

More about attestations

Attestations in Azure are resources that are not listed anywhere. You can only administer them though the ARM API, AZ CLI or Azure Powershell. This however makes it possible for us to declare them in code in order to keep track of them.

We will complete the following objectives:

  • Assign a manual effect policy with Terraform
  • We will self-attest to the policy that it should be marked completed or compliant
  • We will create the attestation resource in Terraform

We have covered Azure Policy extensively on this blog but incase you want a visual representation of what we will create and how Azure Policy works then see this image:

The definition controls what the policy can govern, the assignment ensures its followed & the scope is where the assignment exists

First we need to create our base Terraform code, this will contain:

  • The Terraform block and provider version
  • Provider blocks and configuration (AzureRM & AzAPI)
  • A policy definition & policy assignment resource
terraform {
  required_providers {
    azapi = {
      source  = "Azure/azapi"
      version = "2.2.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.18.0"
    }
    azuread = {
      source  = "hashicorp/azuread"
      version = "3.1.0"
    }
  }
}

provider "azapi" {}

provider "azurerm" {
  features {}
  subscription_id = var.azure_subscription_id
}

data "azurerm_subscription" "current" {}

resource "azurerm_policy_definition" "this" {
  name         = "Azure-Attestation-Custom"
  policy_type  = "Custom"
  mode         = "All"
  display_name = "Everyone needs to prove their love for Azure before this can be attested to"
  description  = "What the title says..."

  parameters = jsonencode({
    effect = {
      type  = "String"
      value = "Manual"
    }
  })

  policy_rule = jsonencode({
    if = {
      field  = "type",
      equals = "Microsoft.Resources/subscriptions"
    },
    then = {
      effect = "[parameters('effect')]"
    }
  })
}

resource "azurerm_subscription_policy_assignment" "this" {
  name                 = azurerm_policy_definition.this.name
  subscription_id      = data.azurerm_subscription.current.id
  policy_definition_id = azurerm_policy_definition.this.id
  display_name         = azurerm_policy_definition.this.display_name
  description          = azurerm_policy_definition.this.description
  parameters = jsonencode({
    effect = {
      value = "Manual"
    }
  })
}

I also create a variables.tf

variable "azure_subscription_id" {
  type        = string
  default     = "Your-Subscription-ID"
  description = "Azure Subscription ID"
}

variable "environment" {
  type        = string
  description = "Environment"
}

variable "location" {
  type        = string
  description = "Location"
}

variable "location_short" {
  type        = string
  description = "Location Short"
}

And a dev.tfvars file:

environment    = "dev"
location       = "swedencentral"
location_short = "se"

I will deploy running the following commands

terraform init
terraform apply -var-file variables/dev.tfvars -auto-approve

Normally you would run terraform plan as well to preview the changes, I felt confident here ;)

I had to re-deploy once, hence why the "Apply complete" mesage may look different for you than for me

Review the attestation

So after a while we will have our new policy with its Unknown compliant state as such:

So lets assume that the team here, called the ChatGPT team, needs to prove their love for Azure, which they have. They sent us this message:

From ChatGPT:

Dearest Microsoft Azure,


From the moment I spun up my first virtual machine, you captivated my heart with your endless cloud capabilities and effortless scalability. You make my dreams of boundless innovation come true, always ready to expand and adapt at my slightest request. My love for your clean interfaces and resilient architecture grows every time I deploy a new service. Thank you for consistently lifting my ideas into the cloud and reminding me there’s no limit to what we can create together.

It brings a tear to my eye, everytime...

Creating the attestation

So let us create the attestation. Since we can use the ARM API, Powershell or CLI we have the option to use the azapi provider in Terraform.

resource "azapi_resource" "this" {
  type      = "Microsoft.PolicyInsights/attestations@2024-10-01"
  name      = "ChatGPT-Loves-Azure"
  parent_id = "/subscriptions/${var.azure_subscription_id}"
  body = {
    properties = {
      assessmentDate  = "2025-12-09T00:00:00Z"
      comments        = "The ChatGPT team has proven their love for Azure"
      complianceState = "Compliant" # Or Non-Compliant
      evidence = [
        {
          description = "The love letter submitted by the ChatGPT team"
          sourceUri   = "The URI location of the evidence, could be a blob storage URL"
        }
      ]
      expiresOn                   = "2026-12-09T00:00:00Z" # A year later from the assessmentDate property
      owner                       = data.azuread_client_config.this.object_id
      policyAssignmentId          = azurerm_subscription_policy_assignment.this.id
    }
  }
}
Running: terraform apply -var-file variables/dev.tfvars -auto-approve

We can verify that the attestation resource exists by querying with az cli

And finally, if we head to the policy compliance section of the Azure portal we should no longer see the Unknown policy compliance state

The compliance status has been updated, awesome!

Conclusion

Today we again reviewed the structure of Azure Policies. We also created a policy assignment with Terraform with the manual effect. We created an attestation that will be valid for one year and in that time we can be sure that the ChatGPT team will love Azure!

Hope you enjoyed todays post.

References

Azure Policy definitions effect basics - Azure Policy
Azure Policy definitions effect basics determine how compliance is managed and reported.
Details of the Azure Policy attestation structure - Azure Policy
Describes the components of the Azure Policy attestation JSON object.

About me

About me
If you have landed on my page you will have already understood my passion for tech, but obviously there is more to life than that. Here I will try and outline a few of my other hobbies. Strength training I am a person who loves to move around and challenge