Image Vulnerability Scanning Using Amazon ECR Or Third
More Info:​
Enable image vulnerability scanning on Amazon ECR (scan-on-push) or a third-party provider so that container images are checked for known vulnerabilities before deployment.
Risk Level​
Medium
Address​
Security
Compliance Standards​
- CIS EKS
Triage and Remediation​
- Remediation
Remediation​
Manual Steps
-
Identify all image sources used by the cluster
- On any machine with
kubectlaccess, list all images currently referenced in workloads:kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{.spec.initContainers[*].image}{"\n"}{end}' \| tr ' ' '\n' | sort -u - From this list, determine which images are pulled from Amazon ECR (
*.dkr.ecr.*.amazonaws.com) and which come from other registries (for potential third‑party scanning).
- On any machine with
-
Check ECR repositories for scan-on-push configuration (AWS CLI)
- On any machine with AWS CLI access and appropriate IAM permissions, for each AWS account/region that hosts ECR images, run:
aws ecr describe-repositories --region us-east-1 --query 'repositories[].repositoryName' --output text
- For each repository listed, check its scanning configuration:
aws ecr describe-repositories \--repository-names REPLACE_WITH_REPOSITORY_NAME \--region us-east-1 \--query 'repositories[].imageScanningConfiguration'
- Record which repositories have
"scanOnPush": trueand which do not.
- On any machine with AWS CLI access and appropriate IAM permissions, for each AWS account/region that hosts ECR images, run:
-
Enable or correct ECR scan-on-push settings where missing
- For any ECR repository that does not have scan-on-push enabled, set it:
aws ecr put-image-scanning-configuration \--repository-name REPLACE_WITH_REPOSITORY_NAME \--image-scanning-configuration scanOnPush=true \--region us-east-1
- For new repositories you manage via IaC (CloudFormation/Terraform), ensure the repository definition includes the equivalent of
scanOnPush=trueso future repos are compliant by default.
- For any ECR repository that does not have scan-on-push enabled, set it:
-
Run ad‑hoc scans for existing images that may predate scan-on-push
- In the AWS console, go to
https://console.aws.amazon.com/ecr/repositories, select the correct Region, then open each repository that contains images used by your EKS cluster. - On the Images tab of a repository, select important/tagged images (e.g.,
latest, release tags) and choose Scan to perform manual scans, prioritizing images currently deployed in the cluster.
- In the AWS console, go to
-
Evaluate and document third‑party scanning (if using non‑ECR registries)
- For any non‑ECR registry discovered in step 1, confirm whether a vulnerability scanning solution is in place (e.g., native registry scanning, CI pipeline scanner, or external scanning service).
- Collect evidence such as:
- Registry or scanner configuration showing automatic scans on push or on schedule.
- Sample scan reports for images actually deployed in the cluster.
- If no scanning exists for a given registry, plan and implement a scanning solution comparable in coverage to ECR’s image scanning.
-
Verify effective coverage for all deployed images
- Cross‑check: every image from step 1 should either reside in an ECR repository with
scanOnPush=trueor in a non‑ECR registry with documented, active vulnerability scanning. - Optionally, spot‑check a few images by pulling their latest scan results in ECR (via console or CLI) or your third‑party tool, to confirm scans are actually running and producing findings.
- Cross‑check: every image from step 1 should either reside in an ECR repository with
Using kubectl
This control is configured in AWS ECR and/or your chosen image scanning provider, not in Kubernetes objects, so it cannot be fixed with kubectl. Make the changes in the AWS console, AWS CLI, or your IaC definitions for ECR repositories, and then follow the guidance in the Manual Steps section.
Automation
#!/usr/bin/env bash
# Purpose: Report which container images used in the cluster are stored in ECR
# and whether their repositories have scan-on-push enabled.
set -euo pipefail
# --------- CONFIGURATION ---------
# AWS CLI profile and region used to query ECR
AWS_PROFILE="default"
AWS_REGION="us-east-1"
# ---------------------------------
echo "Collecting unique container images from all namespaces..."
IMAGES=$(
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{range .spec.initContainers[*]}{.image}{"\n"}{end}{end}' \
| sort -u
)
if [ -z "$IMAGES" ]; then
echo "No images found in the cluster."
exit 0
fi
echo "Discovered images:"
printf ' %s\n' $IMAGES
echo
# Function: parse ECR registry, repository, and tag from an image string
parse_ecr_image() {
local image="$1"
# Match public or private ECR:
# private: 123456789012.dkr.ecr.us-east-1.amazonaws.com/repo[:tag]
# public: public.ecr.aws/alias/repo[:tag]
if [[ "$image" =~ ^([0-9]{12}\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com)/(.*)$ ]]; then
local registry="${BASH_REMATCH[1]}"
local remainder="${BASH_REMATCH[2]}"
elif [[ "$image" =~ ^(public\.ecr\.aws)/(.*)$ ]]; then
local registry="${BASH_REMATCH[1]}"
local remainder="${BASH_REMATCH[2]}"
else
# Not an ECR image
return 1
fi
# Split remainder into repo and tag/digest
# repo:tag or repo@sha256:...
local repo="${remainder%%[@:]*}"
local tag_or_digest="${remainder#"$repo"}"
local tag=""
if [[ "$tag_or_digest" == ":"* ]]; then
tag="${tag_or_digest#:}"
elif [[ "$tag_or_digest" == "@"* ]]; then
tag="${tag_or_digest#@}"
else
tag="latest"
fi
echo "$registry" "$repo" "$tag"
return 0
}
echo "Checking ECR scan-on-push configuration for all ECR-backed images..."
echo
# Collect unique ECR repositories referenced by the cluster
declare -A ECR_REPOS=()
while read -r img; do
parsed=$(parse_ecr_image "$img" || true)
if [ -n "$parsed" ]; then
registry=$(awk '{print $1}' <<< "$parsed")
repo=$(awk '{print $2}' <<< "$parsed")
key="$registry/$repo"
ECR_REPOS["$key"]=1
fi
done <<< "$IMAGES"
if [ "${#ECR_REPOS[@]}" -eq 0 ]; then
echo "No ECR images are currently used by this cluster."
echo "Potential issue: Images may be coming from registries where vulnerability scanning is not configured or not centrally visible."
exit 0
fi
echo "ECR repositories referenced by the cluster:"
for key in "${!ECR_REPOS[@]}"; do
echo " $key"
done
echo
# Query scan-on-push for each ECR repo
echo "Repository scan-on-push status (AWS_PROFILE=$AWS_PROFILE, AWS_REGION=$AWS_REGION):"
echo
for key in "${!ECR_REPOS[@]}"; do
registry="${key%%/*}"
repo="${key#"$registry/"}"
# Private ECR repositories live in specific regions and accounts.
# Skip public ECR (public.ecr.aws) here; scanning configuration is different.
if [[ "$registry" == "public.ecr.aws" ]]; then
echo "public.ecr.aws/$repo : SKIPPED (public ECR; verify scanning configuration manually)"
continue
fi
# Extract account ID and region from registry
# Example registry: 123456789012.dkr.ecr.us-east-1.amazonaws.com
account_id="${registry%%.*}"
reg_region="$(cut -d'.' -f4 <<< "$registry")"
# Only check in the configured AWS_REGION to avoid cross-region confusion
if [ "$reg_region" != "$AWS_REGION" ]; then
echo "$registry/$repo : SKIPPED (registry region $reg_region != configured AWS_REGION $AWS_REGION; run script per region)"
continue
fi
# Query ECR for scan-on-push
set +e
SCAN_OUTPUT=$(AWS_PROFILE="$AWS_PROFILE" AWS_REGION="$AWS_REGION" aws ecr describe-repositories \
--repository-names "$repo" \
--query "repositories[0].imageScanningConfiguration.scanOnPush" \
--output text 2>&1)
status=$?
set -e
if [ $status -ne 0 ]; then
echo "$registry/$repo : ERROR querying ECR: $SCAN_OUTPUT"
continue
fi
if [ "$SCAN_OUTPUT" = "True" ]; then
echo "$registry/$repo : scanOnPush=ENABLED"
elif [ "$SCAN_OUTPUT" = "False" ]; then
echo "$registry/$repo : scanOnPush=DISABLED <-- REVIEW: images from this repo are not auto-scanned on push"
else
echo "$registry/$repo : UNKNOWN response: $SCAN_OUTPUT"
fi
done
echo
echo "INTERPRETATION:"
echo "- Any line ending with 'scanOnPush=DISABLED' indicates a repository used by the cluster whose images are not automatically scanned on push; this is a gap against the control."
echo "- 'SKIPPED' lines require manual review to confirm that an equivalent vulnerability scanning mechanism is enabled for those registries."
Explanation of problematic output:
scanOnPush=DISABLEDfor anyregistry/repoused by running pods indicates that Amazon ECR image scanning on push is not enabled for that repository and should be reviewed and remediated.SKIPPEDentries (public ECR or different regions) mean the script could not automatically confirm scanning; you must verify that either ECR scanning or a third-party vulnerability scanner is in place for those images.