> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Minimize User Access To Amazon Ecr

### More Info:

Scan images being deployed to Amazon EKS for vulnerabilities.

### Risk Level

High

### 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

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Inventory who can access ECR (users, roles, groups, policies)**
           * On any machine with AWS CLI configured for the account:
           ```bash theme={null}
           # List all IAM users
           aws iam list-users

           # List all IAM roles
           aws iam list-roles

           # List all IAM groups
           aws iam list-groups

           # List all IAM policies (paginate or filter as needed)
           aws iam list-policies --scope Local
           ```
           * In the AWS Console, go to **IAM → Access analyzer → Policy analyzer** and search for policies containing `ecr:` actions.

        2. **Identify all IAM principals with ECR permissions and evaluate scope**
           * For each relevant IAM user, role, and group, on any machine with AWS CLI:
           ```bash theme={null}
           aws iam list-attached-user-policies   --user-name <USER_NAME>
           aws iam list-user-policies            --user-name <USER_NAME>

           aws iam list-attached-role-policies   --role-name <ROLE_NAME>
           aws iam list-role-policies            --role-name <ROLE_NAME>

           aws iam list-attached-group-policies  --group-name <GROUP_NAME>
           aws iam list-group-policies           --group-name <GROUP_NAME>
           ```
           * For each policy found, retrieve and inspect it for `ecr:*` or broad permissions:
           ```bash theme={null}
           aws iam get-policy --policy-arn <POLICY_ARN>
           aws iam get-policy-version \
             --policy-arn <POLICY_ARN> \
             --version-id <VERSION_ID_FROM_GET_POLICY>
           ```
           * Flag policies that:
             * Use `Action: "ecr:*"` instead of specific actions.
             * Use `Resource: "*"` instead of specific repositories.
             * Are attached directly to users instead of roles or groups.

        3. **Map ECR access to EKS usage and expected personas**
           * On any machine with kubectl access to the cluster, list namespaces and service accounts that pull images from ECR (assuming standard IAM roles for service accounts (IRSA) or node roles):
           ```bash theme={null}
           kubectl get serviceaccounts -A -o wide
           kubectl get nodes -o wide
           ```
           * In AWS Console, go to **EKS → Clusters → `<your-cluster>` → Configuration → Compute** and note:
             * Node instance profile IAM role(s).
             * IAM roles used via IRSA (under **Configuration → Access** and by inspecting service account annotations).
           * Verify that only:
             * Node IAM roles and IRSA roles used by workloads require `ecr:GetAuthorizationToken`, `ecr:BatchCheckLayerAvailability`, `ecr:GetDownloadUrlForLayer`, `ecr:BatchGetImage`.
             * Human users or CI roles with push rights are limited to specific repos and least-privilege actions.

        4. **Review ECR repository policies and public access**
           * On any machine with AWS CLI:
           ```bash theme={null}
           # List repositories
           aws ecr describe-repositories

           # For each repository
           aws ecr get-repository-policy --repository-name <REPO_NAME>
           ```
           * In AWS Console, go to **ECR → Repositories → `<REPO>` → Permissions** and:
             * Ensure no public access unless explicitly required.
             * Ensure repository policies do not grant wildcard principals (`"*"` or wide account ranges) or `ecr:*` on that repo.
             * Confirm that principals listed match the expected roles/users from step 3.

        5. **Tighten IAM and repository permissions (IaC/CLI/Console)**
           * For any over-privileged policies you identified:
             * Replace `ecr:*` with only the required actions.
             * Replace `Resource: "*"` with specific ECR repository ARNs (from `aws ecr describe-repositories`).
             * Prefer attaching policies to IAM roles used by EKS nodes/IRSA/CI, not directly to users.
           * Example of a read-only ECR policy document (adapt and apply via Console or IaC):
           ```json theme={null}
           {
             "Version": "2012-10-17",
             "Statement": [
               {
                 "Effect": "Allow",
                 "Action": [
                   "ecr:GetAuthorizationToken",
                   "ecr:BatchCheckLayerAvailability",
                   "ecr:GetDownloadUrlForLayer",
                   "ecr:BatchGetImage"
                 ],
                 "Resource": "*"
               }
             ]
           }
           ```
           * Ensure only CI/CD or designated operators have push (`ecr:PutImage`, `ecr:InitiateLayerUpload`, etc.) and that it is scoped to required repositories.

        6. **Verify minimized access and ongoing monitoring**
           * Re-run IAM and ECR policy inspection to confirm no broad `ecr:*` or `Resource: "*"` remain except where justified:
           ```bash theme={null}
           # Find customer-managed policies mentioning ecr
           aws iam list-policies --scope Local --query 'Policies[?contains(PolicyName, `ecr`) == `true`]'
           ```
           * Optionally, enable or review **AWS CloudTrail** and **Access Analyzer** to:
             * Confirm ECR is not accessed by unexpected principals.
             * Detect unintended public or cross-account access.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot be used to change Amazon ECR IAM permissions or access policies because this finding is entirely in the AWS cloud/provider configuration surface. Make the necessary changes using AWS IAM/ECR configuration via the AWS Console, CLI, or IaC, and refer to the Manual Steps section for detailed guidance.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Purpose: Report ECR image usage in an EKS cluster and highlight places where
        #          direct IAM user credentials are likely in use instead of roles.
        #
        # Run on: Any machine with kubectl and AWS CLI configured and access to the cluster.
        #
        # Requirements:
        #   - kubectl
        #   - aws CLI
        #   - jq
        #
        # Notes:
        #   - This does NOT change anything; it only reports for review.
        #   - Focus is on:
        #       * Which ECR registries are used
        #       * What Kubernetes identities pull those images
        #       * Where IAM users are referenced in ECR policies

        set -euo pipefail

        echo "=== 1. List all container images in the cluster and identify ECR usage ==="

        echo "[*] Gathering all images from pods in all namespaces..."
        IMAGES_JSON="$(kubectl get pods -A -o json)"
        ALL_IMAGES="$(echo "${IMAGES_JSON}" | jq -r '
          .items[]
          | .spec.containers[]?.image,
            .spec.initContainers[]?.image
        ' | sort -u)"

        echo
        echo "All unique images in cluster:"
        echo "-----------------------------"
        echo "${ALL_IMAGES}"

        echo
        echo "ECR images (aws_account_id.dkr.ecr.region.amazonaws.com/...):"
        echo "-------------------------------------------------------------"
        ECR_IMAGES="$(echo "${ALL_IMAGES}" | grep -E '^[0-9]{12}\.dkr\.ecr\.[a-z0-9-]+\.amazonaws\.com/' || true)"
        if [ -z "${ECR_IMAGES}" ]; then
          echo "No ECR images detected."
        else
          echo "${ECR_IMAGES}"
        fi

        echo
        echo "=== 2. Map ECR images to namespaces and service accounts ==="

        if [ -z "${ECR_IMAGES}" ]; then
          echo "Skipping mapping step because no ECR images were found."
        else
          echo "[*] Pods using ECR images and the identities they run as:"
          echo "---------------------------------------------------------"
          echo "${IMAGES_JSON}" | jq -r '
            .items[]
            | {
                ns: .metadata.namespace,
                pod: .metadata.name,
                sa: (.spec.serviceAccountName // "default"),
                node: (.spec.nodeName // "N/A"),
                containers: (
                  (.spec.containers // []) + (.spec.initContainers // [])
                )
              }
            | . as $pod
            | $pod.containers[]
            | select(.image
              | test("^[0-9]{12}\\.dkr\\.ecr\\.[a-z0-9-]+\\.amazonaws\\.com/"))
            | "\($pod.ns)\t\($pod.pod)\t\($pod.sa)\t\($pod.node)\t\(.image)"
          ' | sort -u \
            | awk 'BEGIN { print "NAMESPACE\tPOD\tSERVICEACCOUNT\tNODE\tIMAGE" }1'
        fi

        echo
        echo "=== 3. List imagePullSecrets used by pods (possible access path to ECR) ==="

        echo "[*] Pods with imagePullSecrets and the secrets they reference:"
        echo "-------------------------------------------------------------"
        kubectl get pods -A -o json \
          | jq -r '
              .items[]
              | select(.spec.imagePullSecrets != null)
              | . as $pod
              | .spec.imagePullSecrets[]
              | "\($pod.metadata.namespace)\t\($pod.metadata.name)\t\(.name)"
            ' \
          | awk 'BEGIN { print "NAMESPACE\tPOD\tIMAGEPULLSECRET" }1' \
          | sort -u || echo "No pods with imagePullSecrets found."

        echo
        echo "=== 4. Inspect Docker config secrets likely used for ECR ==="

        echo "[*] Checking all secrets for dockerconfigjson/dockerconfig ECR credentials..."
        echo "-------------------------------------------------------------------------------"
        for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
          for sec in $(kubectl -n "${ns}" get secrets -o jsonpath='{.items[?(@.type=="kubernetes.io/dockerconfigjson")].metadata.name}'); do
            echo
            echo "Namespace: ${ns}  Secret: ${sec}"
            echo "---------------------------------------"
            DOCKERCFG=$(kubectl -n "${ns}" get secret "${sec}" -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d 2>/dev/null || true)
            if [ -n "${DOCKERCFG}" ]; then
              echo "${DOCKERCFG}" | jq .
              echo
              echo "ECR servers referenced in this secret:"
              echo "${DOCKERCFG}" | jq -r '.auths | keys[]' | grep -E 'dkr\.ecr\.' || echo "  (none)"
            else
              echo "Unable to decode .dockerconfigjson"
            fi
          done

          for sec in $(kubectl -n "${ns}" get secrets -o jsonpath='{.items[?(@.type=="kubernetes.io/dockercfg")].metadata.name}'); do
            echo
            echo "Namespace: ${ns}  Secret: ${sec}"
            echo "---------------------------------------"
            DOCKERCFG=$(kubectl -n "${ns}" get secret "${sec}" -o jsonpath='{.data.\.dockercfg}' | base64 -d 2>/dev/null || true)
            if [ -n "${DOCKERCFG}" ]; then
              echo "${DOCKERCFG}" | jq .
              echo
              echo "ECR servers referenced in this secret:"
              echo "${DOCKERCFG}" | jq -r 'keys[]' | grep -E 'dkr\.ecr\.' || echo "  (none)"
            else
              echo "Unable to decode .dockercfg"
            fi
          done
        done

        echo
        echo "=== 5. (Optional) Review ECR repository policies for IAM users ==="
        echo
        echo "If you know which AWS accounts/regions host your ECR images, you can inspect"
        echo "their repository policies to find IAM users with access. This requires AWS CLI"
        echo "access to those accounts. Example commands you can run manually:"
        cat <<'EOF'

        # Example: list all repositories in a region
        aws ecr describe-repositories --region us-east-1 --query 'repositories[].repositoryName'

        # Example: show repository policy and highlight IAM users
        aws ecr get-repository-policy \
          --region us-east-1 \
          --repository-name <REPO_NAME> \
          --query 'policyText' \
          --output text | jq -r '
            .Statement[]
            | {
                Sid,
                Effect,
                Principal: .Principal,
                Action
              }
          '

        # Problem indicators in repository policies:
        #   - "AWS": "arn:aws:iam::<account-id>:user/<user-name>"
        #   - Wide principals like:
        #       "AWS": "*"
        #   - Use of IAM groups that include IAM users with broad permissions.

        EOF

        echo
        echo "=== INTERPRETING THE OUTPUT: WHAT INDICATES A PROBLEM? ==="
        cat <<'EOF'
        Look for the following patterns to flag for manual review:

        1) From sections 1–2:
           - Business‑critical workloads using ECR images where the associated
             serviceAccount is not mapped to an IRSA role (no AWS IAM role via
             eks.amazonaws.com/role-arn annotation on its ServiceAccount).
           - Shared or default service accounts pulling many different ECR images,
             which often implies broad, non‑minimal access.

           To check a specific ServiceAccount for IRSA:
             kubectl -n <namespace> get sa <serviceaccount> -o yaml | \
               yq '.metadata.annotations."eks.amazonaws.com/role-arn"'

           Absence of this annotation suggests the pod may rely on node‑level roles
           or legacy access patterns instead of fine‑grained roles.

        2) From sections 3–4:
           - imagePullSecrets that contain auth entries for ECR registries, especially
             if:
               * The username is 'AWS' with long‑lived password tokens created by
                 aws ecr get-login-password and baked into secrets.
               * The secret is used by many pods/namespaces (shared credentials).
           - Any credentials that are not clearly tied to a dedicated, scoped IAM role.

        3) From section 5 (AWS CLI, run separately):
           - ECR repository policies that reference:
               "arn:aws:iam::<account-id>:user/<user-name>"
               or other IAM users directly.
           - Very broad principals ("AWS": "*") or policies that allow access from
             shared roles/groups used by humans rather than workloads.

        These findings mean IAM access to ECR is not minimized and must be
        manually redesigned toward:
           - Role‑based access (IRSA) per workload.
           - Least‑privilege repository policies.
           - Elimination of direct IAM user access and long‑lived static credentials.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html](https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html)
