Skip to main content

AWS Elastic Container Registry (ECR) - Managing AWS ECR and IAM Access with the AWS CLI, Container Image Security Scan

997 words·
AWS AWS CLI Elastic Container Registry Container Registry Docker
Table of Contents

Prerequisites
#

Install AWS CLI
#

# Update packages
sudo apt update

# Unstall zip tool
sudo apt install unzip -y

# Download AWS CLI zip file
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

# Unzip
unzip awscliv2.zip

# Install
sudo ./aws/install
# Verify installation / check version
/usr/local/bin/aws --version

Configure AWS CLI
#

# Start AWS CLI configuration
aws configure



AWS Elastic Container Registry (ECR)
#

Create ECR Repository
#

# Create a repository
aws ecr create-repository --repository-name example-application --region eu-central-1

# Shell output:
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:eu-central-1:012345678912:repository/example-application",
        "registryId": "012345678912",
        "repositoryName": "example-application",
        "repositoryUri": "012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application",
        "createdAt": "2024-12-15T09:56:25.008000+00:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

Enable ScanOnPush
#

Enable the option to automatically scan the container images for security vulnerabilities, each time they are pushed to the repository:

# Enable ScanOnPush for the repository
aws ecr put-image-scanning-configuration \
 --repository-name example-application \
 --image-scanning-configuration scanOnPush=true \
 --region eu-central-1

# Shell output:
{
    "registryId": "012345678912",
    "repositoryName": "example-application",
    "imageScanningConfiguration": {
        "scanOnPush": true
    }
}

Docker Login
#

Login the new registry repository:

# Retrieve an authentication token and authenticate the Docker client
aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin 012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application

# Shell output:
WARNING! Your password will be stored unencrypted in /home/ubuntu/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores

Login Succeeded

Push Image to ECR
#

Example Application
#

  • Dockerfile
# Use the official Caddy image as the base
FROM caddy:alpine

# Create a non-root user "caddy"
RUN addgroup -S caddy && adduser -S -G caddy caddy

# Adjust permissions
RUN mkdir -p /usr/share/caddy && \
    chown -R caddy:caddy /usr/share/caddy /config /data

# Copy website files into the container
ADD index.html /usr/share/caddy/

# Switch to the non-root user
USER caddy

# Expose the default Caddy port
EXPOSE 80
  • index.html
<!DOCTYPE html>
<html>

<head>
    <title>jklug.work</title>
</head>

<body>
    <h1>Some HTML</h1>
    <p>Example Docker Container<br></p>

</body>

</html>

Build the Image
#

# Build the image for the application
docker build -t example-application .

Tag the Image
#

  • Docker images need a fully qualified name to push
# Tag the local Docker image to associate it with the ECR repository
docker tag example-application:latest 012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application:latest

Verify the image:

# List Docker images
docker images

# Shell output:
REPOSITORY                                                            TAG       IMAGE ID       CREATED         SIZE
012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application   latest    336a6a181143   3 minutes ago   49.3MB
example-application                                                   latest    336a6a181143   3 minutes ago   49.3MB

Push the Image to ECR
#

# Push the image to ECR
docker push 012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application:latest

# Shell output:
62b7f03085b1: Pushed
42d4c1ec2197: Pushed
23c36cdedae8: Pushed
5f70bf18a086: Pushed
355a1927f295: Pushed
625cb1c61fcf: Pushed
d7a20f4b69ff: Pushed
75654b8eeebd: Pushed
latest: digest: sha256:11b2bd79a548048c284a42801206efec00493656b6654ea956c32687e6901b92 size: 1986

Verify Security Scan
#

# List image security scan details
aws ecr describe-image-scan-findings \
 --repository-name example-application \
 --region eu-central-1 \
 --image-id imageTag=latest

# Shell output:
...
"imageScanStatus": {
    "status": "COMPLETE",
    "description": "The scan was completed successfully."
}

Verify / List Image in ECR
#

# List container images in the ECR repository
aws ecr list-images --repository-name example-application --region eu-central-1

# Shell output:
{
    "imageIds": [
        {
            "imageDigest": "sha256:11b2bd79a548048c284a42801206efec00493656b6654ea956c32687e6901b92",
            "imageTag": "latest"
        }
    ]
}



Access ECR from Another Host
#

Create a new IAM user and attach the AmazonEC2ContainerRegistryReadOnly policy to access the ECR from another host:


Create IAM User
#

# Create a new IAM user named "example-user"
aws iam create-user --user-name example-user

Create Access Keys
#

# Create Access Keys for the user
aws iam create-access-key --user-name example-user

# Shell output:
{
    "AccessKey": {
        "UserName": "example-user",
        "AccessKeyId": "AKIARCHUALIN6QRH6WYK",
        "Status": "Active",
        "SecretAccessKey": "cKSprb4yeyL31mXDxs6qlcjNYoVazlY3eGFPWG7P",
        "CreateDate": "2024-12-11T21:49:17+00:00"
    }
}

Attach Policy
#

ECR Policies:

  • AmazonEC2ContainerRegistryReadOnly Pull permission

  • AmazonEC2ContainerRegistryFullAccess Push and Pull permission


# Attach the "AmazonEC2ContainerRegistryReadOnly" policy to the user:
aws iam attach-user-policy --user-name example-user --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly

Verify the Policy
#

# Confirm the policy is attached to the user
aws iam list-attached-user-policies --user-name example-user

# Shell output:
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonEC2ContainerRegistryReadOnly",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
        }
    ]
}

Configure AWS CLI
#

SSH into another Linux host and configure the AWS CLI with the previously created access keys:

# Configure AWS CLI with the new credentials
aws configure

# Shell output
AWS Access Key ID [None]: # Paste key: AKIARCHUALIN6QRH6WYK
AWS Secret Access Key [None]: # Paste key: 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
Default region name [None]:
Default output format [None]:

Docker Login
#

# Retrieve an authentication token and authenticate the Docker client
aws ecr get-login-password --region eu-central-1 | docker login --username AWS --password-stdin 012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application

# Shell output:
WARNING! Your password will be stored unencrypted in /home/ubuntu/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores

Login Succeeded

Pull the Image
#

# Pull the "example-application" image from the ECR repository
docker pull 012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application:latest

Verify the image:

# List Docker images
docker images

# Shell output
REPOSITORY                                                            TAG       IMAGE ID       CREATED          SIZE
012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application   latest    26cb4de176d7   37 minutes ago   11.8MB

Create a Container
#

# Create a Docker container of the image
docker run -d --name example-application -p 80:80 26cb4de176d7
# List containers
docker ps

# Shell output:
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS        PORTS                               NAMES
3b24f9428c86   26cb4de176d7   "/usr/sbin/httpd -D …"   2 seconds ago   Up 1 second   0.0.0.0:80->80/tcp, :::80->80/tcp   example-application
# Verify the example application
curl localhost

# Shell output:
<!DOCTYPE html>
<html>

<head>
    <title>jklug.work</title>
</head>

<body>
    <h1>Some HTML</h1>
    <p>Example Docker Container<br></p>

</body>

</html>



Cleanup
#

Delete IAM User
#

# Detach the policies attached to the user
aws iam detach-user-policy --user-name example-user --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
# List the access keys for the user
aws iam list-access-keys --user-name example-user

# Shell output:
{
    "AccessKeyMetadata": [
        {
            "UserName": "example-user",
            "AccessKeyId": "AKIARCHUALIN6QRH6WYK",
            "Status": "Active",
            "CreateDate": "2024-12-11T21:49:17+00:00"
        }
    ]
}

# Delete the access keys
aws iam delete-access-key --user-name example-user --access-key-id AKIARCHUALIN6QRH6WYK
# Delete the user
aws iam delete-user --user-name example-user

Delete ECR Repository
#

List Container Images
#

# List repository images
aws ecr list-images --repository-name example-application --region eu-central-1

# Shell output:
{
    "imageIds": [
        {
            "imageDigest": "sha256:787ab7c1433646d5a191dbedf787a9facfcb8e6fe8997bc638138379f983a16b",
            "imageTag": "latest"
        }
    ]
}

Delete Container Image
#

# Delete specific image:
aws ecr batch-delete-image --repository-name example-application --image-ids imageDigest=sha256:787ab7c1433646d5a191dbedf787a9facfcb8e6fe8997bc638138379f983a16b --region eu-central-1

Delete ECR Repository
#

# Delete the ECR repository
aws ecr delete-repository --repository-name example-application --region eu-central-1 --force