Image Vulnerability Scanning Using Azure Defender Image
More Info:
Scan images being deployed to Amazon EKS for vulnerabilities.
Risk Level
Medium
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS AKS
- CIS Critical Security Controls v8
- CMMC 2.0
- CSA Cloud Controls Matrix v4
- DPDPA
- Digital Operational Resilience Act (EU)
- Essential 8
- ISO/IEC 27017
- ISO/IEC 27018
- ISO/IEC 27701
- KSA PDPL
- MAS Technology Risk Management (Singapore)
- MITRE ATT&CK (Cloud)
- NIS2 Directive
- NIST SP 800-171
- NYDFS 23 NYCRR 500
- SWIFT Customer Security Controls Framework
- Sarbanes-Oxley IT General Controls
- UK NCSC Cyber Assessment Framework
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify AKS-related container registries
- On any machine with Azure CLI access:
For each AKS cluster, determine which ACRs it uses (from your IaC, workload manifests, or by listing ACRs in the same subscription/resource group):az aks list -o tableaz acr list --subscription <SUBSCRIPTION_ID> -o table
- On any machine with Azure CLI access:
-
Check Microsoft Defender for Cloud pricing tier for Container Registries
- On any machine with Azure CLI access, per subscription used by the AKS clusters:
az account set --subscription <SUBSCRIPTION_ID>az security pricing show --name ContainerRegistry -o table
- If
pricingTieris notStandard, MDC image scanning is not enabled at the subscription level.
- On any machine with Azure CLI access, per subscription used by the AKS clusters:
-
Check per-registry MDC image scanning setting
- On any machine with Azure CLI access, for each identified ACR:
az resource show \--ids /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>/providers/Microsoft.ContainerRegistry/registries/<REGISTRY_NAME> \--api-version 2019-05-01 \--query "properties"
- Review the output for an
enabled(or similar) property related to Defender/image scanning. If it is nottrue(or the property is absent), per-registry image scanning is not explicitly enabled.
- On any machine with Azure CLI access, for each identified ACR:
-
Decide on enabling Microsoft Defender image scanning (cost/risk review)
- Review Defender for Cloud Container Registry pricing and your expected image volume.
- Decide, per subscription/registry, whether to:
- Enable Defender for Cloud at the subscription level (recommended baseline), and/or
- Enable/confirm image scanning per ACR, or
- Use/retain a third‑party image scanning solution instead (e.g., integrated into your CI/CD or registry).
-
Apply configuration changes (if enabling MDC scanning)
- To enable MDC Container Registry coverage at the subscription level (do this once per subscription you choose to protect):
az account set --subscription <SUBSCRIPTION_ID>az security pricing create --name ContainerRegistry --tier Standard
- To explicitly enable image scanning for a specific ACR:
az resource update \--ids /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>/providers/Microsoft.ContainerRegistry/registries/<REGISTRY_NAME> \--set properties.enabled=true
- To enable MDC Container Registry coverage at the subscription level (do this once per subscription you choose to protect):
-
Verify configuration and document decision
- Re-run the checks to confirm:
az security pricing show --name ContainerRegistry -o tableaz resource show \--ids /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>/providers/Microsoft.ContainerRegistry/registries/<REGISTRY_NAME> \--api-version 2019-05-01 \--query "properties"
- If you use a third‑party scanner instead of MDC, record which tool, where scans run (CI, registry, or runtime), and how you enforce that only scanned images are deployed to AKS, as evidence for this manual control.
- Re-run the checks to confirm:
Using kubectl
kubectl cannot configure Microsoft Defender for Cloud or any image vulnerability scanning settings on Azure Container Registries; those are managed at the cloud provider / subscription and registry resource level. Use the Azure portal, Azure CLI, or your IaC tooling to enable MDC image scanning as described in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Audit AKS image vulnerability scanning configuration (CIS AKS 5.1.1)
#
# Requirements (run on: any machine with kubectl + az CLI access):
# - kubectl configured to talk to the AKS cluster
# - Azure CLI logged in: az login
# - Permission to read ACR and Defender for Cloud settings:
# Microsoft.ContainerRegistry/registries/read
# Microsoft.Security/pricings/read
set -euo pipefail
# -------- CONFIG: SET THESE EXPLICITLY --------
SUBSCRIPTION_ID="<SUBSCRIPTION_ID>"
# If your cluster uses managed identities for ACR, you may not know all ACRs.
# Option 1 (recommended): restrict by resource group that holds your AKS + ACR
AKS_RG="<AKS_RESOURCE_GROUP>"
# Option 2: set to "" to scan ALL ACRs in the subscription
# AKS_RG=""
if [[ "${SUBSCRIPTION_ID}" == "<SUBSCRIPTION_ID>" ]] || [[ "${AKS_RG}" == "<AKS_RESOURCE_GROUP>" ]]; then
echo "ERROR: Edit this script and set SUBSCRIPTION_ID and AKS_RG (or consciously set AKS_RG=\"\")." >&2
exit 1
fi
az account set --subscription "${SUBSCRIPTION_ID}"
echo "=== 1. List unique image registries used by workloads in the cluster ==="
# This gathers all image fields from pods, extracts the registry hostname
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.spec.containers[*].image}{" "}{.spec.initContainers[*].image}{"\n"}{end}' \
| tr ' ' '\n' \
| sed '/^$/d' \
| awk -F/ '{print $1}' \
| sort -u | sed '/^$/d' > /tmp/aks_image_registries.txt
echo "Registries detected in cluster images:"
cat /tmp/aks_image_registries.txt
echo
echo "NOTE: Only Azure Container Registry (ACR) instances can be evaluated via Azure Defender for Cloud."
echo " Non-ACR registries (e.g., docker.io, gcr.io, ghcr.io, private) will be listed but not checked."
echo
echo "=== 2. Discover ACR registries in the subscription (optionally filtered by resource group) ==="
if [[ -n "${AKS_RG}" ]]; then
az acr list -g "${AKS_RG}" -o table
ACR_JSON=$(az acr list -g "${AKS_RG}" -o json)
else
az acr list -o table
ACR_JSON=$(az acr list -o json)
fi
echo
# Build a simple mapping of loginServer -> ACR resourceId
echo "=== 3. Map cluster registries to ACR resources and check Defender settings ==="
echo
# Check Defender for ContainerRegistry pricing tier (on/off at subscription level)
echo "Defender for Cloud 'ContainerRegistry' pricing for subscription ${SUBSCRIPTION_ID}:"
DEFENDER_PRICING=$(az security pricing show --name "ContainerRegistry" -o json || echo "{}")
echo "${DEFENDER_PRICING}" | jq '.name, .pricingTier' 2>/dev/null || echo " Unable to read pricing (insufficient permissions?)."
echo
echo "Interpretation:"
echo " - pricingTier == \"Standard\" -> MDC image scanning is ENABLED at subscription level."
echo " - pricingTier == \"Free\" -> MDC image scanning is DISABLED at subscription level."
echo
# Helper: lookup ACR by loginServer
lookup_acr() {
local login_server="$1"
echo "${ACR_JSON}" | jq -r --arg ls "${login_server}" '.[] | select(.loginServer==$ls) | .id' || true
}
echo "=== 4. Per-registry status relative to MDC image scanning ==="
echo
while read -r reg; do
[[ -z "${reg}" ]] && continue
echo "Registry: ${reg}"
# Check if this registry is an ACR (matches loginServer of an ACR resource)
ACR_ID="$(lookup_acr "${reg}")"
if [[ -z "${ACR_ID}" ]]; then
echo " Type : NON-ACR or unknown (e.g., Docker Hub or other public/private registry)"
echo " MDC Status : Not applicable (MDC ACR image scanning cannot be configured here)"
echo " Review action :"
echo " - Ensure a third-party image scanning solution is in place for this registry, OR"
echo " - Mirror critical images into an ACR with MDC enabled."
echo
continue
fi
echo " Type : Azure Container Registry"
echo " ACR ResourceId : ${ACR_ID}"
# Pull ACR properties to see if per-registry image scanning is explicitly enabled
ACR_PROPS=$(az resource show --ids "${ACR_ID}" -o json || echo "{}")
# Some regions/tenants expose properties.dataEndpointEnabled / policies;
# the authoritative benchmark remediation references `properties.enabled`,
# which we will read as-is if present.
ACR_ENABLED=$(echo "${ACR_PROPS}" | jq -r '.properties.enabled // "unknown"' 2>/dev/null || echo "unknown")
echo " ACR properties.enabled (per benchmark remediation) : ${ACR_ENABLED}"
echo " Interpretation:"
echo " - If subscription pricingTier != \"Standard\":"
echo " -> MDC image scanning for Container Registries is effectively DISABLED globally."
echo " - If pricingTier == \"Standard\" and this ACR is in use by workloads:"
echo " -> This registry is EXPECTED to be protected by MDC image scanning."
echo " - If ACR properties.enabled is \"false\" (when present):"
echo " -> Benchmark remediation suggests setting this to true via az resource update."
echo
done < /tmp/aks_image_registries.txt
echo "=== 5. What output indicates a problem (to review manually) ==="
cat <<'EOF'
Look for any of the following:
1) Defender for Cloud pricing:
- pricingTier == "Free"
-> MDC image scanning for Container Registries is NOT enabled at the subscription level.
-> This is non-compliant with CIS AKS 5.1.1 when you rely on MDC as the scanner.
2) Cluster registry usage:
- Registries used by workloads that are:
- NON-ACR (e.g., docker.io, ghcr.io, gcr.io), AND
- Not covered by an alternative approved image-scanning solution.
-> Requires a manual review decision: either configure a third-party scanner,
or mirror these images into ACR with MDC enabled.
3) Per-ACR properties (when .properties.enabled is exposed):
- properties.enabled == "false" for an ACR that is in active use by the cluster.
-> Benchmark remediation suggests enabling image scanning for that registry.
Because this is a MANUAL check, after identifying these signals you must:
- Confirm business/technical decisions on where and how images are scanned.
- Accept, mitigate, or remediate gaps as per your organization's risk policy.
EOF