Skip to main content

Minimize Container Registries To Only Those Approved

More Info:

Use approved container registries. If using OCI Container Registry, utilize OCI IAM policies to control access to the container registry.

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 OKE
  • 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. Identify all registries currently used by cluster workloads

    • On any machine with kubectl access, list all images used in the cluster and extract their registries:
      kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{.spec.initContainers[*].image}{"\n"}{end}' \
      | tr ' ' '\n' | sed '/^$/d' | sort -u
    • From this list, note the distinct registry domains (e.g. iad.ocir.io, docker.io, gcr.io, quay.io, internal registries).
  2. Define and document the approved registries list

    • Out-of-band (documentation / policy), compile a list of registries that are explicitly approved for use (e.g. specific OCIR regions and repositories, specific third‑party registries).
    • Compare the discovered registry list from step 1 against this approved list and flag any non‑approved registries for follow‑up.
  3. Review OCI Container Registry (OCIR) usage and IAM controls

    • In the OCI Console, navigate to Developer Services → Container Registry and list all repositories being used by the cluster (match against images from step 1).
    • For each relevant compartment, review IAM policies via OCI CLI (run from any machine with OCI CLI configured):
      oci iam policy list --compartment-id <COMPARTMENT_OCID> --all
    • Verify that only intended groups/principals have read/pull permissions on the OCIR repositories used by the cluster, and that broader policies (e.g. inspect repos in tenancy) are justified and documented.
  4. Tighten or create OCI IAM policies for OCIR as needed

    • For flagged overly-broad access, update or create policies in the OCI Console or via IaC to:
      • Restrict OCIR access to specific groups (e.g. cluster nodes, CI/CD service accounts).
      • Limit scope to specific compartments and, where applicable, to specific repos.
    • Example (conceptual) policy snippet to allow only a build group to push and cluster nodes to pull, scoped to a compartment:
      • “Allow group <build-group> to manage repos in compartment <compartment-name>
      • “Allow group <cluster-nodes-group> to read repos in compartment <compartment-name>
    • Apply equivalent constraints in your Terraform/other IaC if used.
  5. Assess and harden third‑party registries (if any)

    • For each non‑OCIR registry discovered in step 1, consult that vendor’s access control and security best practices (e.g. repository‑scoped credentials, read‑only tokens, IP allowlists, enforced TLS, signed images).
    • In the vendor console/CLI/IaC, ensure:
      • Only required identities (CI/CD, node pools) can pull images.
      • Multi‑factor auth / strong credentials are enforced for human access.
      • Public repositories are used only where explicitly intended.
  6. Verify only approved registries are in current and new workloads

    • Re-run the image discovery and validation from step 1 and confirm all registries now appear in the approved list.
    • Optionally, implement admission controls (OPA/Gatekeeper, Kyverno, or managed policy features) out-of-band to prevent future use of unapproved registries, and then validate by attempting (and seeing rejection of) a deployment using an unapproved registry.
Using kubectl

kubectl cannot be used to restrict which container registries are allowed or to configure OCI IAM/third‑party registry access; this is controlled at the cloud/provider and registry/IAM configuration layer. Apply the changes using your cloud console, CLI, or IaC as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Report all container image registries in the cluster for review
# Run on: any machine with kubectl access and correct KUBECONFIG
#
# Usage:
# ./report-image-registries.sh > image-registries-report.txt

set -euo pipefail

# Optional: define your approved registries here (space-separated substrings or FQDNs)
# Examples for OCI:
# iad.ocir.io mytenancy/ myregion.ocir.io
APPROVED_REGISTRIES=(
"iad.ocir.io"
"phx.ocir.io"
# add more approved registry hostnames or patterns here
)

# Helper: print header to stderr so stdout stays machine-friendly if needed
echo "Collecting image registry usage from all namespaces..." >&2

# Get all images from all pods, including initContainers, across all namespaces
# Output format: NAMESPACE POD CONTAINER_TYPE CONTAINER_NAME IMAGE
kubectl get pods --all-namespaces -o json \
| jq -r '
.items[]
| . as $pod
| [
$pod.metadata.namespace,
$pod.metadata.name,
"container",
( .spec.containers[]? | .name, .image )
],
[
$pod.metadata.namespace,
$pod.metadata.name,
"initContainer",
( .spec.initContainers[]? | .name, .image )
]
| select(length>0)
' 2>/dev/null \
| paste - - - - - \
| sed 's/\t/ /g' \
| sort -u \
> /tmp/_all_pod_images.txt

echo "Discovered the following unique container images (namespace pod type name image):" >&2
cat /tmp/_all_pod_images.txt >&2

# Extract registry host (or 'docker.io' for implicit Docker Hub) from image reference
# E.g.:
# iad.ocir.io/tenant/repo/image:tag -> iad.ocir.io
# nginx:latest -> docker.io
# library/nginx:1.21 -> docker.io
# registry.k8s.io/pause:3.9 -> registry.k8s.io
awk '
{
ns=$1; pod=$2; ctype=$3; cname=$4; image=$5;
registry=image;

# Split image by /
n=split(image, parts, "/");

if (n == 1) {
# No slash -> implicit Docker Hub
registry="docker.io";
} else if (n == 2 && index(parts[1], ".") == 0 && index(parts[1], ":") == 0) {
# Form: namespace/repo (no dots or port) -> Docker Hub
registry="docker.io";
} else {
# First element is registry host
registry=parts[1];
}

print ns, pod, ctype, cname, image, registry;
}
' /tmp/_all_pod_images.txt > /tmp/_all_pod_images_with_registry.txt

echo "" >&2
echo "Unique registries in use:" >&2
cut -d" " -f6 /tmp/_all_pod_images_with_registry.txt | sort -u >&2

# Check against APPROVED_REGISTRIES list
echo "" >&2
echo "Checking for images that do NOT match approved registry patterns..." >&2

# Build a simple grep pattern from APPROVED_REGISTRIES
APPROVED_PATTERN=""
if [ "${#APPROVED_REGISTRIES[@]}" -gt 0 ]; then
for r in "${APPROVED_REGISTRIES[@]}"; do
# Escape dots for grep
esc=$(printf '%s\n' "$r" | sed 's/\./\\./g')
if [ -z "$APPROVED_PATTERN" ]; then
APPROVED_PATTERN="$esc"
else
APPROVED_PATTERN="$APPROVED_PATTERN|$esc"
fi
done
fi

if [ -z "$APPROVED_PATTERN" ]; then
echo "No APPROVED_REGISTRIES configured in script; listing all images grouped by registry." >&2
echo "" >&2
echo "=== ALL IMAGES GROUPED BY REGISTRY (for manual review) ===" >&2
sort -k6,6 /tmp/_all_pod_images_with_registry.txt \
| column -t \
| sed 's/^/ /' >&2

echo "" >&2
echo "NOTE: Manually determine which registries are approved (e.g., your OCI Container Registry endpoints)" >&2
echo " and ensure that only images from those registries are in use." >&2
else
# Print non-approved images to stdout (machine-readable)
# Format: NAMESPACE POD CONTAINER_TYPE CONTAINER_NAME IMAGE REGISTRY
grep -Ev " (${APPROVED_PATTERN})$" /tmp/_all_pod_images_with_registry.txt || true

echo "" >&2
echo "=== NON-APPROVED REGISTRY USE (if any) ===" >&2
if grep -Ev " (${APPROVED_PATTERN})$" /tmp/_all_pod_images_with_registry.txt >/tmp/_non_approved.txt; then
cat /tmp/_non_approved.txt \
| sort -k6,6 \
| column -t \
| sed 's/^/ /' >&2

echo "" >&2
echo "INTERPRETATION:" >&2
echo " Lines above show pods using images whose registry hostname does NOT match any approved pattern:" >&2
printf ' - Approved patterns: %s\n' "${APPROVED_REGISTRIES[@]}" >&2
echo " For each entry, review whether this registry should be approved or the workload should be updated" >&2
echo " to use an image from your approved registries (e.g., OCI Container Registry with proper IAM policies)." >&2
else
echo "No images from non-approved registries detected based on current APPROVED_REGISTRIES list." >&2
fi
fi

echo "" >&2
echo "DONE. For OCI Container Registry, ensure OCI IAM policies restrict who can push/pull images." >&2

What output indicates a problem

  • Any lines printed under === NON-APPROVED REGISTRY USE (if any) === show pods using images from registries that are not in your APPROVED_REGISTRIES list.
  • If you did not configure APPROVED_REGISTRIES, manually review the “ALL IMAGES GROUPED BY REGISTRY” section and treat any registry that is not an explicitly approved OCI Container Registry endpoint (or other vetted third‑party registry) as a potential issue.

Additional Reading: