Skip to main content

Minimize Container Registries Only Those Approved

More Info:

Scan images being deployed to Amazon EKS for vulnerabilities.

Risk Level

Low

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CIS EKS
  • 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

Manual Steps
  1. Inventory all registries your EKS workloads pull from

    • 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 host for each image (text after // and before the first /, or before / if no //), e.g. 123456789012.dkr.ecr.us-east-1.amazonaws.com, docker.io, gcr.io.
  2. List all AWS ECR registries and repositories in your accounts

    • On any machine with AWS CLI configured:
      aws ecr describe-registry
      aws ecr describe-repositories --region us-east-1
      aws ecr describe-repositories --region us-west-2
      # repeat for each region you operate in
    • Compare these to the registries found in step 1 to distinguish ECR vs non‑ECR sources.
  3. Define and document “approved registry” criteria and the allowed list

    • With your security/compliance team, decide: which AWS accounts/regions’ ECRs are allowed, and which third‑party registries (if any) are permitted and under what conditions (scanning enabled, private, signed images, etc.).
    • Write a short policy stating: “Only the following registries may be used for EKS workloads: …”.
  4. Evaluate current registry usage against the approved list

    • From the image list in step 1, mark each registry as: approved, candidate (needs review), or disallowed.
    • For AWS ECR registries:
      aws ecr describe-image-scan-findings \
      --repository-name <repo-name> \
      --image-id imageTag=<tag> \
      --region <region>
    • Use this to check whether images from candidate/disallowed registries meet your security criteria (scanning, severity levels, etc.).
  5. Implement or tighten controls to enforce only approved registries

    • Using AWS IAM / Organizations (console, CLI, or IaC), adjust policies so that:
      • Only specific AWS accounts/roles can pull from approved ECR registries.
      • Pull/push actions to any non‑approved registries (e.g., internet egress) are restricted via IAM, VPC egress controls, or organizational SCPs.
    • Optionally, add admission controls (e.g., OPA/Gatekeeper, Kyverno) that deny Pods whose image registry is not in your approved list (implemented via your chosen IaC/tooling, not kubectl directly for the control plane).
  6. Verify and periodically review

    • Re-run the workload image inventory:
      kubectl get pods -A -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | sort -u
    • Confirm that all registries now appear on your approved list and that IAM/egress controls prevent use of unapproved registries. Repeat this review on a defined schedule (e.g., quarterly) or when adding new registries.
Using kubectl

kubectl cannot be used to restrict or approve container registries for Amazon EKS, because this control is enforced at the cloud provider / managed control plane and IAM/ECR policy layer. Make the required changes in AWS (ECR, IAM, organization policies, and any admission controls configured via cloud tooling) as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
# Purpose: Report all container image registries used in an EKS cluster so they
# can be reviewed against your approved ECR registry list.
# Run on: any machine with kubectl access and the correct kubeconfig for the EKS cluster.

set -o errexit
set -o nounset
set -o pipefail

# ---------- CONFIGURATION ----------
# Comma-separated list of approved registry prefixes (edit for your org).
# Examples:
# 123456789012.dkr.ecr.us-east-1.amazonaws.com
# public.ecr.aws
# 602401143452.dkr.ecr.${AWS_REGION}.amazonaws.com
APPROVED_REGISTRIES_CSV="123456789012.dkr.ecr.us-east-1.amazonaws.com,public.ecr.aws"

# -----------------------------------

IFS=',' read -r -a APPROVED_REGISTRIES <<< "$APPROVED_REGISTRIES_CSV"

timestamp() {
date -u +"%Y-%m-%dT%H:%M:%SZ"
}

echo "[$(timestamp)] Collecting images from all namespaces..."

# Collect all unique images (includes pods, daemonsets, statefulsets, jobs, cronjobs, replicasets, deployments, replicas, replicationcontrollers)
ALL_IMAGES_JSON=$(kubectl get pods,daemonsets,statefulsets,jobs,cronjobs,replicasets,deployments,replicationcontrollers --all-namespaces -o json 2>/dev/null || echo '{"items":[]}')

# Extract all container images (containers + initContainers) with owner references and namespace.
# This produces lines: "<namespace> <workloadKind>/<workloadName> <podName> <containerType> <containerName> <image>"
IMAGES_REPORT=$(
echo "$ALL_IMAGES_JSON" \
| jq -r '
.items[]
| . as $pod
| ($pod.metadata.ownerReferences[0].kind // "Pod") as $ownerKind
| ($pod.metadata.ownerReferences[0].name // $pod.metadata.name) as $ownerName
| ($pod.metadata.namespace // "default") as $ns
| [ "containers", "initContainers" ][]
| . as $ctype
| ($pod.spec[$ctype] // [])[]
| [$ns,
($ownerKind + "/" + $ownerName),
$pod.metadata.name,
$ctype,
.name,
.image]
| @tsv
' 2>/dev/null || true
)

if [[ -z "$IMAGES_REPORT" ]]; then
echo "[$(timestamp)] No images found (cluster may be empty)."
exit 0
fi

echo "[$(timestamp)] Unique registry usage:"
# Extract registry (first path component before first '/') and count
echo "$IMAGES_REPORT" \
| awk '{print $6}' \
| sed 's#^#//##' \
| awk -F/ '{print $2}' \
| sort -u \
| while read -r registry; do
[[ -z "$registry" ]] && continue
echo " - $registry"
done

echo
echo "[$(timestamp)] Checking images against approved registries:"
echo "Approved registry prefixes:"
for r in "${APPROVED_REGISTRIES[@]}"; do
echo " - $r"
done
echo

# Function: return 0 if image is from an approved registry, 1 otherwise
is_approved_image() {
local image="$1"
local registry

# Extract registry: if image has '/', take first part; otherwise treat as "docker.io" style (no explicit registry)
if [[ "$image" == *"/"* ]]; then
registry="${image%%/*}"
else
registry="docker.io"
fi

# Check against approved registry prefixes (simple prefix match)
for approved in "${APPROVED_REGISTRIES[@]}"; do
if [[ "$registry" == "$approved"* ]]; then
return 0
fi
done
return 1
}

# Build a report of non-approved images
NON_APPROVED_FILE="$(mktemp)"
APPROVED_FILE="$(mktemp)"

while IFS=$'\t' read -r ns owner pod ctype cname image; do
if is_approved_image "$image"; then
printf "%s\t%s\t%s\t%s\t%s\t%s\n" "$ns" "$owner" "$pod" "$ctype" "$cname" "$image" >> "$APPROVED_FILE"
else
printf "%s\t%s\t%s\t%s\t%s\t%s\n" "$ns" "$owner" "$pod" "$ctype" "$cname" "$image" >> "$NON_APPROVED_FILE"
fi
done <<< "$IMAGES_REPORT"

echo "[$(timestamp)] Summary:"
echo " Total image references: $(echo "$IMAGES_REPORT" | wc -l | xargs)"
echo " Approved image references: $(wc -l < "$APPROVED_FILE" | xargs)"
echo " Non-approved image references: $(wc -l < "$NON_APPROVED_FILE" | xargs)"
echo

echo "[$(timestamp)] Detailed non-approved image usage:"
if [[ -s "$NON_APPROVED_FILE" ]]; then
printf "namespace\tworkload\tpod\tcontainerType\tcontainerName\timage\n"
sort -u "$NON_APPROVED_FILE"
else
echo " None detected (all images are from approved registries as per current list)."
fi

echo
echo "[$(timestamp)] NOTE:"
echo " - Lines listed under 'Detailed non-approved image usage' indicate potential policy violations."
echo " - For each such line, review whether the registry is intentionally allowed."
echo " - Update APPPROVED_REGISTRIES_CSV in this script as your approved ECR/public registries evolve."

What output indicates a problem:

  • Any non-zero value for Non-approved image references in the “Summary” section.
  • Any rows printed under “Detailed non-approved image usage” (each row shows a namespace, workload, pod, container type, container name, and image whose registry does not match your approved registry prefixes).

Additional Reading: