Image Vulnerability Scanning Using Amazon Ecr 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 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
Remediation
Manual Steps
-
Inventory images used in the cluster (any machine with
kubectlaccess)kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' \| tr ' ' '\n' | sort -uSave the list and identify which images are stored in Amazon ECR (
*.dkr.ecr.*.amazonaws.com/*) vs. other registries. -
Verify ECR repositories have scan-on-push enabled (AWS CLI, any machine with AWS CLI and permissions)
For each ECR imageACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/REPO_NAME:TAG, run:aws ecr describe-repositories --repository-names REPO_NAME --region REGION \--query 'repositories[0].imageScanningConfiguration'If
scanOnPushisfalseor missing, enable it:aws ecr put-image-scanning-configuration \--repository-name REPO_NAME \--image-scanning-configuration scanOnPush=true \--region REGION -
Ensure new repositories are created with scan-on-push (AWS CLI / IaC policy, any machine)
For any new ECR repository you plan to use with EKS, create it with scanning enabled:aws ecr create-repository \--repository-name REPO_NAME \--image-scanning-configuration scanOnPush=true \--region REGIONUpdate Terraform/CloudFormation/CD pipelines so repository creation always sets
scanOnPush=true. -
Manually scan existing images lacking a recent scan (AWS Console or CLI)
Console (per remediation): navigate to the repository → select the image → Scan.
CLI alternative (per image digest):aws ecr start-image-scan \--repository-name REPO_NAME \--image-id imageTag=TAG \--region REGIONThen retrieve findings:
aws ecr describe-image-scan-findings \--repository-name REPO_NAME \--image-id imageTag=TAG \--region REGION -
Decide on policy for non‑ECR images (manual review)
- Identify images from Docker Hub, other vendors, or private registries from step 1.
- Choose and configure a third‑party scanner (e.g., integrated into your CI/CD) to scan those registries before push or deploy.
- Ensure your deployment process rejects images with unscanned or high‑severity vulnerabilities according to your risk tolerance.
-
Verify compliance for all in‑use images
- For every ECR‑hosted image currently used in the cluster, confirm
scanOnPush=trueon its repository and that a scan has run (viadescribe-image-scan-findings). - For every non‑ECR image, document which scanner and pipeline stage covers it and ensure a current report exists.
- For every ECR‑hosted image currently used in the cluster, confirm
Using kubectl
kubectl cannot configure image vulnerability scanning for Amazon ECR repositories or third‑party scanners; this must be set in the AWS account via the AWS console, CLI, or your IaC. Refer to the Manual Steps section for how to enable ECR scan-on-push and/or integrate a third-party image scanning solution.
Automation
#!/usr/bin/env bash
# Purpose: Report which container images used in the cluster are NOT stored in
# ECR repositories that have scanOnPush enabled.
# Runs on: Any machine with kubectl, aws CLI, and creds for the target cluster/account.
set -euo pipefail
# ---------- CONFIGURATION ----------
AWS_REGION="us-east-1" # set to the primary region where your ECR repos live
# ----------------------------------
echo "Discovering all images running in the cluster..."
ALL_IMAGES_RAW=$(
kubectl get pods --all-namespaces -o json |
jq -r '.items[]
| .spec.containers[]?.image,
.spec.initContainers[]?.image' |
sort -u
)
if [[ -z "${ALL_IMAGES_RAW}" ]]; then
echo "No images found in the cluster."
exit 0
fi
echo
echo "Unique images in cluster:"
printf '%s\n' "${ALL_IMAGES_RAW}"
echo
echo "Filtering for AWS ECR images..."
ECR_IMAGES=$(printf '%s\n' "${ALL_IMAGES_RAW}" | grep -E '\.ecr\.[^.]+\.amazonaws\.com/' || true)
NON_ECR_IMAGES=$(comm -23 <(printf '%s\n' "${ALL_IMAGES_RAW}" | sort) <(printf '%s\n' "${ECR_IMAGES}" | sort || true))
echo
echo "Non‑ECR images (require separate vulnerability‑scanning solution):"
if [[ -n "${NON_ECR_IMAGES}" ]]; then
printf '%s\n' "${NON_ECR_IMAGES}"
else
echo "None detected."
fi
if [[ -z "${ECR_IMAGES}" ]]; then
echo
echo "No ECR images detected. Ensure your non‑ECR registries have image vulnerability scanning enabled."
exit 0
fi
echo
echo "Checking scanOnPush setting for ECR repositories referenced by the cluster..."
# Normalize image names to extract registry, repository, and then repo-name for ECR
# ECR image formats (examples):
# 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-repo:tag
# 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-namespace/my-repo@sha256:...
#
# We only care about the repository path relative to the ECR registry endpoint.
ECR_REPOS=$(
printf '%s\n' "${ECR_IMAGES}" |
sed -E 's|@sha256:.*$||' |
sed -E 's|:([^/:]+)$||' | \
awk -F'/' '
{
# drop the first field (the registry host)
$1=""; sub(/^ /, "", $0);
print $0
}' |
sort -u
)
if [[ -z "${ECR_REPOS}" ]]; then
echo "No ECR repositories could be parsed from image names."
exit 1
fi
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
if [[ -z "${ACCOUNT_ID}" ]]; then
echo "Unable to determine AWS account ID from current credentials."
exit 1
fi
echo
echo "AWS Account: ${ACCOUNT_ID}"
echo "AWS Region : ${AWS_REGION}"
echo
echo "ECR repositories referenced by cluster images:"
printf '%s\n' "${ECR_REPOS}"
echo
echo "Querying scanOnPush configuration for each referenced ECR repository..."
echo
# Header
printf "%-50s %-8s %-s\n" "ECR_REPOSITORY" "SCAN_ON_PUSH" "NOTES"
while IFS= read -r repo; do
# Some images may reference repos that don't exist in this account/region (e.g. cross-account)
if ! OUT=$(aws ecr describe-repositories \
--region "${AWS_REGION}" \
--repository-names "${repo}" 2>/dev/null); then
printf "%-50s %-8s %-s\n" "${repo}" "UNKNOWN" "Repository not found in ${ACCOUNT_ID}/${AWS_REGION} (cross-account? different region?)"
continue
fi
SCAN_ON_PUSH=$(echo "${OUT}" | jq -r '.repositories[0].imageScanningConfiguration.scanOnPush // "false"')
if [[ "${SCAN_ON_PUSH}" == "true" ]]; then
printf "%-50s %-8s %-s\n" "${repo}" "true" ""
else
printf "%-50s %-8s %-s\n" "${repo}" "false" "IMAGE SCANNING NOT ENABLED (scanOnPush=false)"
fi
done <<< "${ECR_REPOS}"
echo
echo "INTERPRETATION:"
echo " - Any row with SCAN_ON_PUSH = false indicates an ECR repository that does NOT automatically"
echo " scan images on push. This is a potential finding for CIS EKS 5.1.1."
echo " - Rows with SCAN_ON_PUSH = UNKNOWN mean the repository is not found in the current account/region."
echo " Review whether those images are:"
echo " * hosted in another AWS account or region, and"
echo " * covered by an alternate vulnerability-scanning solution."
echo " - Non‑ECR images listed earlier must be independently verified to be scanned by a third‑party provider."
What output indicates a problem
- Under “Non‑ECR images”, any listed image requires confirmation that a third‑party vulnerability scanner is in place.
- In the final table:
SCAN_ON_PUSH = false→ ECR repo is not configured for automatic image scanning (non‑compliant unless compensated by another approved scanner).SCAN_ON_PUSH = UNKNOWN→ the script couldn’t find that repo in the current account/region; you must manually verify where it lives and whether scanning is enabled there.