Skip to content

Tutorial 04: Azure Policy for AKS

This tutorial enables Azure Policy for Kubernetes and validates how policy guardrails can enforce baseline controls such as allowed images, label requirements, and restricted pod settings.

Prerequisites

  • Azure subscription with permission to create AKS, networking, and monitoring resources
  • Azure CLI, kubectl, and a shell environment capable of exporting variables
  • Existing or planned variable set for $RG, $CLUSTER_NAME, $LOCATION, and any lab-specific names
  • A Log Analytics workspace resource ID stored in $WORKSPACE_ID for Container Insights validation
  • Awareness that all commands use long flags only so they are easy to read and automate later

Architecture Diagram

flowchart TD
    DEV[kubectl apply] --> API[AKS API server]
    API --> POLICY[Azure Policy add-on]
    POLICY --> GATEKEEPER[Gatekeeper constraints]
    GATEKEEPER --> DECISION{Compliant?}
    DECISION -->|Yes| ADMIT[Admit workload]
    DECISION -->|No| DENY[Deny and record violation]

Step-by-Step Instructions

Step 1: Enable Azure Policy add-on

az aks enable-addons \
    --resource-group "$RG" \
    --name "$CLUSTER_NAME" \
    --addons azure-policy
Command Purpose
az aks enable-addons Enable the Azure Policy add-on.
--resource-group Resource group that contains the AKS cluster.
--name Name of the AKS cluster.
--addons Add-on to enable, azure-policy.

This step is important because it establishes the control point for enable azure policy add-on. After running it, pause and verify the Azure resource state before moving on so you do not compound errors later in the lab.

Step 2: Assign a built-in AKS policy initiative

az policy assignment create \
    --name aks-baseline-lab \
    --scope "$CLUSTER_ID" \
    --policy-set-definition "/providers/Microsoft.Authorization/policySetDefinitions/<policy-set-id>"
Command Purpose
az policy assignment create Assign a policy set to the cluster scope.
--name Name of the policy assignment.
--scope Resource scope the assignment applies to.
--policy-set-definition Policy set definition to assign.

This step is important because it establishes the control point for assign a built-in aks policy initiative. After running it, pause and verify the Azure resource state before moving on so you do not compound errors later in the lab.

Step 3: Create a test namespace and non-compliant manifest

kubectl create namespace governance-lab

kubectl apply \
    --filename privileged-pod.yaml

This step is important because it establishes the control point for create a test namespace and non-compliant manifest. After running it, pause and verify the Azure resource state before moving on so you do not compound errors later in the lab.

Step 4: Review policy states and violations

az policy state list \
    --resource "$CLUSTER_ID" \
    --query "[].{policyDefinitionName:policyDefinitionName,complianceState:complianceState}" \
    --output table

kubectl get constrainttemplates \
    --output wide
Command Purpose
az policy state list List policy compliance states for the cluster.
--resource Resource ID of the AKS cluster.
--query Selects policy definition names and compliance states.
--output Output format for the result.
kubectl get constrainttemplates List Gatekeeper constraint templates.

This step is important because it establishes the control point for review policy states and violations. After running it, pause and verify the Azure resource state before moving on so you do not compound errors later in the lab.

Step 5: Correct the manifest and redeploy

kubectl apply \
    --filename compliant-pod.yaml

This step is important because it establishes the control point for correct the manifest and redeploy. After running it, pause and verify the Azure resource state before moving on so you do not compound errors later in the lab.

Validation Steps

Use the following validation flow after the deployment steps complete:

  • Confirm the AKS cluster and all required node pools are visible with kubectl get nodes --output wide.
  • Confirm the Azure resource provisioning state is Succeeded for any new network, gateway, identity, or policy resource.
  • Run at least one Container Insights query to prove telemetry is flowing before you declare the lab complete.
  • Capture screenshots or exported JSON only after sanitizing identifiers such as subscription IDs or object IDs.

Example validation commands:

kubectl get pods \
    --all-namespaces \
    --output wide
az aks show \
    --resource-group "$RG" \
    --name "$CLUSTER_NAME" \
    --query "{name:name,provisioningState:provisioningState,kubernetesVersion:kubernetesVersion}" \
    --output json
Command Purpose
az aks show Show core cluster properties.
--resource-group Resource group that contains the AKS cluster.
--name Name of the AKS cluster.
--query Selects name, provisioning state, and version.
--output Output format for the result.
az monitor log-analytics query \
    --workspace "$WORKSPACE_ID" \
    --analytics-query "KubeNodeInventory | where TimeGenerated > ago(15m) | summarize Nodes=dcount(Computer) by ClusterName" \
    --timespan "PT15M"
Command Purpose
az monitor log-analytics query Query node inventory counts by cluster.
--workspace Log Analytics workspace to query.
--analytics-query KQL query text to execute.
--timespan Time range for the query.

Cleanup Instructions

Delete lab resources when you are finished to avoid unnecessary spend. If the lab created shared resources that other exercises still need, remove only the lab-specific objects first.

az group delete \
    --name "$RG" \
    --yes \
    --no-wait
Command Purpose
az group delete Delete the lab resource group and its resources.
--name Name of the resource group to delete.
--yes Skip the confirmation prompt.
--no-wait Return without waiting for deletion to finish.

If you created secondary resource groups, Application Gateway, or user-assigned identities, delete those resources as part of the same cleanup workflow or document why they remain.

See Also

Sources