Pushing Docker images to AWS Elastic Container Registry (ECR) from Drone CI is a common task, but it often trips people up due to the intricacies of authentication and repository creation.
Let’s see it in action. Imagine you have a simple Drone CI pipeline defined in your .drone.yml:
kind: pipeline
type: docker
name: default
steps:
- name: build_and_push
image: plugins/docker
settings:
repo: 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app
tags:
- latest
- ${DRONE_COMMIT_SHA}
username:
from_secret: aws_access_key_id
password:
from_secret: aws_secret_access_key
registry: 123456789012.dkr.ecr.us-east-1.amazonaws.com
This pipeline uses the official plugins/docker image, which is designed to handle pushing to various registries, including ECR. The settings block is where the magic (and potential pitfalls) lie.
The core problem this solves is getting your application’s Docker image from your CI environment into a secure, managed registry within AWS, ready for deployment to services like ECS or EKS. Drone CI, by default, doesn’t know how to authenticate with AWS ECR. You need to provide it with credentials and tell it where to push.
Here’s how it works under the hood for ECR:
- Authentication: The
plugins/dockerimage, when configured for ECR, doesn’t just blindly use the providedusernameandpassword. It actually uses these credentials to call the AWS ECRGetAuthorizationTokenAPI. This API returns a temporary, base64-encoded token. The plugin then decodes this token and uses it as the password for a standard Docker login against the ECR endpoint. The username is typicallyAWS. - Repository Existence: The plugin will attempt to push to the specified
repo. If the repository doesn’t exist in ECR, the push will fail. Theplugins/dockerdoes not automatically create ECR repositories. You must create them beforehand in AWS. - Tagging: The
tagssetting allows you to specify multiple tags for your image. This is crucial for versioning and deployment strategies. You can use environment variables like${DRONE_COMMIT_SHA}to tag with the commit hash, ensuring traceability.
The most surprising true thing about this process is that the username and password you provide to the plugins/docker are not directly used for a static Docker login. Instead, they are used to obtain a temporary, dynamic authentication token from AWS. This is a security measure to prevent long-lived credentials from being embedded directly in Docker login commands.
Let’s break down the essential components you need to control:
repo: This is your full ECR repository URI. It follows the pattern:<aws_account_id>.dkr.ecr.<region>.amazonaws.com/<repository_name>. For example,123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app.tags: A list of tags to apply to the image. Common choices includelatestand the commit SHA.username: This should be an IAM user’s Access Key ID. It’s best practice to create a dedicated IAM user with only the necessary permissions for ECR.password: This should be the IAM user’s Secret Access Key.registry: This is the ECR endpoint URL. It’s the same as the base of yourrepoURI, without the repository name.
You’ll need to create these secrets in your Drone CI project. Navigate to your project’s settings in Drone, then to the "Secrets" tab. Add aws_access_key_id and aws_secret_access_key with the corresponding values from your IAM user.
Crucially, before Drone can push, you must create the ECR repository in your AWS account. You can do this via the AWS Management Console or the AWS CLI:
aws ecr create-repository --repository-name my-app --region us-east-1
Replace my-app and us-east-1 with your desired repository name and AWS region. The IAM user whose credentials you’re using in Drone must have permissions to create and push images to this repository. A policy like this is a good starting point:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECRRepoPolicy",
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:DescribeImages",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage"
],
"Resource": "*"
}
]
}
The plugins/docker image also has a repo_exists setting (defaults to true). If you set it to false, the plugin will attempt to create the repository if it doesn’t exist. However, this requires broader IAM permissions (like ecr:CreateRepository) for the user, which is often less desirable from a security perspective. It’s generally recommended to create the repository manually or via infrastructure-as-code.
The next hurdle you’ll likely encounter is understanding how to manage image lifecycles within ECR, such as setting up lifecycle policies to automatically delete old images.