Skip to content

AWS ECR

ECR is the registry where IAM, regions, and cross-account access dominate the setup. The registry hostname encodes both the AWS account and the region — <account-id>.dkr.ecr.<region>.amazonaws.com — and a single connection scans one account in one region.

Auth options

MethodWhen to useRequired HarborGuard fields
IAM access key + secretCloud scan from outside AWS, or quick proof-of-conceptAccess Key ID + Secret Access Key
IAM role on the sensor hostSensor runs on EC2/ECS/EKS in the same account or one that can sts:AssumeRoleNone — the sensor uses the instance / pod IAM role
Cross-account assume-roleSensor runs in account A, scans ECR in account BThe sensor's role must be allowed by B's repository policy

ECR is the only provider whose wizard asks for Access Key ID / Secret Access Key rather than Username / Password. The provider is auto-detected when the URL matches *.dkr.ecr.*.amazonaws.com.

Add the registry

  1. Registries → Connect Registry.
  2. Registry URL123456789012.dkr.ecr.us-east-1.amazonaws.com. The wizard parses out account + region.
  3. The wizard shows AWS ECR Detected and the credential form switches to AWS fields.
  4. Cloud mode: paste the access key + secret of an IAM user with the policy below. Sensor mode: skip credentials; the sensor uses the host's role.
  5. Save. The first sync calls ecr:DescribeRepositories followed by ecr:DescribeImages per repo.

Required IAM permissions

Minimum policy for HarborGuard to enumerate and scan an ECR registry:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:DescribeRepositories",
        "ecr:ListImages",
        "ecr:DescribeImages",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchCheckLayerAvailability"
      ],
      "Resource": "arn:aws:ecr:<region>:<account-id>:repository/*"
    }
  ]
}

ecr:GetAuthorizationToken is special — it must be granted on *, not on a repository ARN. Forgetting this is the most common cause of a registry that lists its repos but cannot pull any layers.

Cross-account access

When the sensor's role lives in account A (111111111111) and the ECR registry is in account B (222222222222):

  1. In account A, the sensor's role gets the policy above (with <account-id> set to 222222222222).
  2. In account B, attach a repository policy to each scanned repository:
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowHarborGuardSensor",
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::111111111111:role/harborguard-sensor" },
    "Action": [
      "ecr:BatchGetImage",
      "ecr:GetDownloadUrlForLayer",
      "ecr:BatchCheckLayerAvailability",
      "ecr:DescribeImages",
      "ecr:ListImages"
    ]
  }]
}

Push-event sync

ECR emits PutImage events on the EventBridge default bus. To wire up on_push:

  1. Create an EventBridge rule matching aws.ecr / detail-type ECR Image Action / action-type = PUSH.
  2. Target an API Destination that POSTs to https://<your-harborguard-host>/api/webhooks/ecr.
  3. Set the registry's schedule to on_push.

A scan is queued within seconds of the push and a private-network sensor handles the actual pull, so the image never leaves your VPC.

Common pitfalls

  • Wrong region. ECR is regional. 123456789012.dkr.ecr.us-east-1.amazonaws.com and 123456789012.dkr.ecr.us-west-2.amazonaws.com are two separate registries. Add a connection per region.
  • ecr:GetAuthorizationToken resource scope. Granting it on a repository ARN silently fails token exchange. It must be Resource: "*".
  • Public ECR. public.ecr.aws is a different service with a different API. It is not yet supported as a typed provider — use Custom / OCI if you must.
  • Image immutability. If a tag has been pushed to an immutable repository, re-pushing the same tag fails — but HarborGuard still rescans on the new digest if you re-tag.
  • Lifecycle policies that race the scan. A lifecycle policy that prunes untagged images can delete an image between catalog sync and scan dispatch. The scan job will report "manifest not found"; reduce the policy's untagged window to ≥ scan interval.

Troubleshooting

SymptomLikely cause
Repos enumerate, but scans fail with deniedMissing ecr:BatchGetImage / ecr:GetDownloadUrlForLayer
Test connection succeeds, sync produces zero reposThe IAM principal has access in a different region than the URL
"InvalidSignatureException"Clock drift on the sensor host > 5 minutes
Cross-account: list works, pull failsRepository policy missing on the target account
Sensor mode authenticates but eventually 401sRole-chain credentials expired and the sensor isn't refreshing — confirm AWS_ROLE_ARN and IRSA / IMDSv2 access

On this page