> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Enable Image Vulnerability Scanning With Microsoft Defender

### More Info:

Enable Microsoft Defender for Cloud image scanning (or a third-party provider) on your Azure Container Registry to detect vulnerabilities in stored container images before they are deployed.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS AKS

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify target subscription(s) and registry(ies)**
           * On any machine with Azure CLI access:
             ```bash theme={null}
             az account show --output table
             az acr list --output table
             ```
           * Decide which ACRs are in scope for the cluster (e.g., those referenced in your deployment manifests, Helm charts, or imagePullSecrets).

        2. **Check whether Microsoft Defender for Cloud is enabled for Container Registries**
           * On any machine with Azure CLI access:
             ```bash theme={null}
             az security pricing show --name ContainerRegistry --output table
             ```
           * If `pricingTier` is `Standard`, MDC is enabled for Container Registries at the subscription level; if `Free`, MDC image scanning is not active.

        3. **Check whether image scanning is enabled on each target ACR**
           * For each in-scope registry (replace placeholders with real values):
             ```bash theme={null}
             az resource show \
               --ids /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>/providers/Microsoft.ContainerRegistry/registries/<REGISTRY_NAME> \
               --output json | jq '.properties.enabled'
             ```
           * Review the `true`/`false` value; `true` indicates image scanning is enabled on that registry.

        4. **Decide on the protection model (MDC vs. third-party)**
           * If you already use a third-party scanner (e.g., integrated via CI/CD or ACR tasks), gather evidence (tool config, sample scan reports, and how they cover all ACR images/tags).
           * Compare its coverage and SLAs to MDC’s capabilities; decide if MDC should be enabled, used in combination, or if the third-party solution alone is sufficient for your risk appetite.

        5. **Enable or adjust configuration where required**
           * If you decide to enable MDC for Container Registries at subscription level (incurs cost):
             ```bash theme={null}
             az security pricing create --name ContainerRegistry --tier Standard --output table
             ```
           * If you need to enable image scanning on a specific registry:
             ```bash theme={null}
             az resource update \
               --ids /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>/providers/Microsoft.ContainerRegistry/registries/<REGISTRY_NAME> \
               --set properties.enabled=true \
               --output json
             ```
           * If you decide not to enable MDC (because of cost or reliance on a third-party solution), document the justification and attach evidence of the alternative scanning.

        6. **Verify and document the final state**
           * Re-run:
             ```bash theme={null}
             az security pricing show --name ContainerRegistry --output table
             ```
           * And for each in-scope registry:
             ```bash theme={null}
             az resource show \
               --ids /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>/providers/Microsoft.ContainerRegistry/registries/<REGISTRY_NAME> \
               --output json | jq '.properties.enabled'
             ```
           * Record outputs, decisions (MDC vs. third-party), and any exclusions as part of your security and compliance documentation.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot enable Microsoft Defender for Cloud image scanning or configure Azure Container Registry; this must be done in the Azure portal, Azure CLI, or your IaC targeting the subscription/registry configuration. Refer to the Manual Steps section for the exact Azure-side commands and review process.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Purpose:
        #   Enumerate container images used in the AKS cluster and report whether
        #   Microsoft Defender for Cloud (MDC) image scanning is enabled on the
        #   backing Azure Container Registries (ACR), where detectable from the CLI.
        #
        # Requirements:
        #   - Run on any machine with:
        #       * kubectl configured for the target cluster
        #       * Azure CLI (`az`) installed and logged in
        #   - You must have permission to:
        #       * List all pods in the cluster
        #       * Read ACR resources and Security pricing in the subscription(s)
        #
        # NOTE:
        #   This script ONLY reports state. It does NOT and CANNOT auto-remediate
        #   this CIS MANUAL control.

        set -euo pipefail

        echo "=== Step 1: Discover all unique container image registries used in the cluster ===" >&2

        # Collect all images from all namespaces and deduplicate
        IMAGES=$(
          kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{range .spec.initContainers[*]}{.image}{"\n"}{end}{end}' 2>/dev/null \
          | sed '/^$/d' \
          | sort -u
        )

        if [ -z "${IMAGES}" ]; then
          echo "No images found in cluster (no pods or no containers)." >&2
          exit 0
        fi

        echo "Discovered images:"
        echo "${IMAGES}" | sed 's/^/  - /'

        # Extract registry hostname from each image (e.g. myregistry.azurecr.io from myregistry.azurecr.io/ns/app:tag)
        REGISTRIES=$(
          echo "${IMAGES}" \
          | awk -F/ '
              # image formats:
              #   registry/namespace/name:tag
              #   registry/name:tag
              #   name:tag   (Docker Hub implicit)
              {
                if (NF == 1) {
                  # No explicit registry (Docker Hub or other implicit) – report as "<implicit>"
                  print "<implicit>"
                } else {
                  print $1
                }
              }
            ' \
          | sort -u
        )

        echo
        echo "=== Step 2: Identify Azure Container Registries (ACR) among used registries ===" >&2
        echo "All registries in use:"
        echo "${REGISTRIES}" | sed 's/^/  - /'

        # Filter registries that look like ACR (ends with .azurecr.io)
        ACR_REGISTRIES=$(
          echo "${REGISTRIES}" | grep '\.azurecr\.io$' || true
        )

        if [ -z "${ACR_REGISTRIES}" ]; then
          echo
          echo "No Azure Container Registries (.azurecr.io) detected in current workloads."
          echo "If you expect ACR usage or use third-party image scanning, review that configuration manually."
          exit 0
        fi

        echo
        echo "Azure Container Registries detected in workloads:"
        echo "${ACR_REGISTRIES}" | sed 's/^/  - /'

        echo
        echo "=== Step 3: Map ACR registries to Azure resources and check MDC pricing ===" >&2

        # List all ACR resources accessible via Azure CLI
        ACR_LIST_JSON=$(az acr list --query '[].{name:name, loginServer:loginServer, id:id}' -o json)

        # Check MDC pricing for ContainerRegistry at subscription scope
        # Note: This returns the plan at the *current* az account subscription.
        SUBSCRIPTION_ID=$(az account show --query id -o tsv)
        MDC_PRICING_JSON=$(az security pricing show --name ContainerRegistry -o json || echo '{}')

        MDC_TIER=$(echo "${MDC_PRICING_JSON}" | jq -r '.pricingTier // empty')

        echo
        echo "Current subscription: ${SUBSCRIPTION_ID}"
        if [ -z "${MDC_TIER}" ] || [ "${MDC_TIER}" = "null" ]; then
          echo "MDC pricing for ContainerRegistry could not be determined (no plan or insufficient permissions)."
        else
          echo "MDC ContainerRegistry pricing tier for this subscription: ${MDC_TIER}"
        fi

        echo
        echo "=== Step 4: Per-registry report ==="
        printf "%-30s %-40s %-12s %-8s\n" "REGISTRY" "ACR_RESOURCE_ID" "MDC_TIER" "STATUS"
        printf "%-30s %-40s %-12s %-8s\n" "--------" "--------------" "--------" "------"

        # For each used ACR registry, try to find its resource and report
        while read -r REG; do
          [ -z "${REG}" ] && continue
          # Extract ACR name from login server: <name>.azurecr.io
          ACR_NAME="${REG%%.azurecr.io}"

          # Find matching ACR resource
          ACR_ID=$(echo "${ACR_LIST_JSON}" | jq -r --arg login "${REG}" '.[] | select(.loginServer==$login) | .id' | head -n1)

          if [ -z "${ACR_ID}" ] || [ "${ACR_ID}" = "null" ]; then
            printf "%-30s %-40s %-12s %-8s\n" "${REG}" "NOT_FOUND" "-" "REVIEW"
            continue
          fi

          # Check if MDC image scanning is enabled on this registry, if property exists
          # NOTE: This property name comes from the benchmark example; real environments may differ.
          ACR_JSON=$(az resource show --ids "${ACR_ID}" -o json || echo '{}')
          ENABLED_PROP=$(echo "${ACR_JSON}" | jq -r '.properties.enabled // empty')

          STATUS="UNKNOWN"
          if [ -n "${ENABLED_PROP}" ] && [ "${ENABLED_PROP}" != "null" ]; then
            if [ "${ENABLED_PROP}" = "true" ]; then
              STATUS="OK"
            else
              STATUS="PROBLEM"
            fi
          else
            # Fall back to subscription-level MDC tier if available
            if [ "${MDC_TIER}" = "Standard" ]; then
              STATUS="POSSIBLY_OK"
            else
              STATUS="PROBLEM"
            fi
          fi

          printf "%-30s %-40s %-12s %-8s\n" "${REG}" "${ACR_ID}" "${MDC_TIER:-"-"}" "${STATUS}"
        done <<< "${ACR_REGISTRIES}"

        cat <<'EOF'

        How to interpret STATUS:

        - OK
          - Registry-level image scanning appears enabled (properties.enabled == true).
        - POSSIBLY_OK
          - Registry does not expose a clear 'enabled' flag, but subscription-level MDC
            pricing for ContainerRegistry is set to Standard. Review in Azure Portal
            (Defender for Cloud -> Environment settings -> [Subscription] -> Defender plans).
        - PROBLEM
          - Registry is found, but:
              * properties.enabled is false, or
              * MDC pricing tier is not Standard and no other scanning is detected.
          - This indicates the CIS control is likely NOT met for this registry.
        - REVIEW
          - Registry used in workloads but no matching ACR resource was found in the
            current Azure context. This may mean:
              * It is in another subscription/tenant, or
              * It is a non-ACR registry (e.g., Docker Hub, other provider), or
              * You lack permissions.
          - Manually verify that a vulnerability scanning solution (MDC or third-party)
            is enabled for that registry.

        Note:
        - This script does NOT configure MDC or third-party scanning.
        - Use it regularly to identify registries and subscriptions that require
          manual review and potential configuration changes.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
