Skip to main content

Minimize Container Registries To Only Those Approved

More Info:

Restrict container image pulls to an approved set of registries using firewall rules, admission controllers, or Azure Policy, and limit egress traffic to those registries.

Risk Level

Medium

Address

Security

Compliance Standards

  • CIS AKS

Triage and Remediation

Remediation

Manual Steps
  1. Inventory current image registries in use

    • Run on any machine with kubectl access:
      kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{" "}{end}{"\n"}{end}' | sort -u
    • Extract the registry hostnames (first path segment before /) and compile a list of all registries currently used by workloads (including system namespaces like kube-system and azure-*).
  2. Define and document the approved registry list

    • Using your organization’s security policy, decide which registries are approved (for example, specific Azure Container Registries and any required Microsoft/AKS system registries).
    • Document them as explicit FQDNs, e.g.:
      • mycorpprod.azurecr.io
      • mycorptest.azurecr.io
      • Required Microsoft endpoints as per AKS / egress docs.
  3. Restrict access at the registry and network level (Azure side)

  4. Enforce registry usage with Azure Policy / admission control

    • In Azure Portal: PolicyDefinitions and locate policies such as:
      • Kubernetes cluster containers should only use allowed images
    • Assign to the AKS cluster’s scope and configure the list of allowed registries (FQDNs from step 2).
    • If using Gatekeeper/another admission controller (via IaC), create/update a policy that rejects images whose registry host is not in the approved list. Example (conceptual) for Gatekeeper ConstraintTemplate/Constraint; apply via your existing GitOps/IaC pipeline.
  5. Verify enforcement and impact

    • Attempt to deploy a pod pulling from an unapproved registry, on any machine with kubectl access:
      cat <<'EOF' | kubectl apply -f -
      apiVersion: v1
      kind: Pod
      metadata:
      name: test-unapproved-registry
      spec:
      containers:
      - name: c
      image: unapproved.example.com/namespace/image:tag
      EOF
    • Confirm that:
      • The admission policy rejects the pod (check events):
        kubectl describe pod test-unapproved-registry
      • Or, if admitted, that image pull fails due to network/egress restrictions (image pull errors in events).
  6. Re-audit running workloads and system behavior

    • Re-run the inventory command (step 1) to confirm that all new pods only use approved registries.
    • Review AKS egress logs/firewall logs (Azure Firewall, NSG flow logs, etc.) to ensure no successful outbound connections from AKS subnets to non-approved registries.
Using kubectl

kubectl cannot be used to restrict container image pulls to approved registries because this control is enforced at the cloud/provider configuration level (Azure Container Registry firewall rules, Azure Policy, and egress controls), not via Kubernetes API objects. Apply the remediation in the cloud console or IaC as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
# Purpose: Report container registries in use across the cluster for review
# Requirements: kubectl configured with access to the target AKS cluster

set -euo pipefail

echo "==[ 1/4 ] Cluster-scoped image usage (Pods, Deployments, etc.)=="
# List all images referenced by core workload types in all namespaces
kubectl get pods,deployments,daemonsets,statefulsets,replicasets,cronjobs,jobs \
-A -o jsonpath='{range ..image}{.}{"\n"}{end}' 2>/dev/null \
| sort -u \
| awk 'NF' \
| tee /tmp/aks-images-all.txt

echo
echo "==[ 2/4 ] Unique image registries/domains in use (derived from above)=="
# Extract registry portion (text before first /); if no /, mark as "dockerhub_implicit"
awk '
{
img=$0
split(img,parts,"/")
if (NF==1 || img !~ /\./ && img !~ /:/) {
# Images like "nginx:1.21" => implicit Docker Hub
print "dockerhub_implicit"
} else {
print parts[1]
}
}' /tmp/aks-images-all.txt \
| sort -u \
| tee /tmp/aks-registries-all.txt

echo
echo "==[ 3/4 ] Report by namespace and workload=="
# Show each pod, its namespace, workload owner (if any), and images
kubectl get pods -A -o json \
| jq -r '
.items[]
| {
ns: .metadata.namespace,
pod: .metadata.name,
owner: ( .metadata.ownerReferences[0].kind + "/" + .metadata.ownerReferences[0].name ) // "POD/standalone",
images: ([.spec.containers[]?.image] + [.spec.initContainers[]?.image]) | unique
}
| .ns + "\t" + .owner + "\t" + .pod + "\t" + ( .images | join(",") )
' \
| column -t -s $'\t' \
| tee /tmp/aks-image-usage-by-pod.txt

echo
echo "==[ 4/4 ] OPTIONAL: Compare against an approved registry list (if provided)=="
APPROVED_FILE="./approved-registries.txt"
if [[ -f "${APPROVED_FILE}" ]]; then
echo "Using approved registry list from: ${APPROVED_FILE}"
echo "Approved registries:"
cat "${APPROVED_FILE}"
echo

echo "Non-approved registries in use:"
# Show any registry not present in approved-registries.txt
grep -Fvx -f "${APPROVED_FILE}" /tmp/aks-registries-all.txt || true
else
cat <<'EOF'
No ./approved-registries.txt found.
To enable automatic comparison, create a file named approved-registries.txt in the current directory
with one approved registry/hostname per line, for example:

myteam.azurecr.io
another-approved-registry.io
dockerhub_implicit

Then re-run this script to see which registries are outside the approved set.
EOF
fi

echo
echo "==[ SUMMARY ]=="
echo "All unique images: /tmp/aks-images-all.txt"
echo "All unique registries: /tmp/aks-registries-all.txt"
echo "Per-pod image usage: /tmp/aks-image-usage-by-pod.txt"
if [[ -f "${APPROVED_FILE}" ]]; then
echo "Compare non-approved registries above with your policies, ACR firewall rules,"
echo "Azure Policy / admission controller configurations, and egress controls."
fi

How to run (any machine with kubectl access)

chmod +x report-registries.sh
./report-registries.sh

Interpreting the output (what indicates a problem)

  • /tmp/aks-registries-all.txt lists every registry/domain in use.
    • Any entry that is not on your formally approved list (for example, your ACR FQDNs) is a potential problem.
    • dockerhub_implicit indicates images like nginx:latest with no explicit registry, typically Docker Hub. Treat this as unapproved unless your policy explicitly allows it.
  • The “Non-approved registries in use:” section (when approved-registries.txt is present) shows registries that:
    • Must be blocked via ACR firewall rules, Azure Policy/admission controls, or
    • Must be reviewed and either added to the approved list or removed/migrated.
  • /tmp/aks-image-usage-by-pod.txt lets you trace unapproved registries back to the exact namespaces/workloads to drive remediation decisions.