CircleCI Dockerhub Authentication
This runbook shows how to setup and use “service” DockerIDs to service CircleCI builds.
Please use Github Actions instead of CircleCI
Context
as of 1st november 2020, anonymous pulls for docker images will be rate limited to 100 per 6 hours. There are higher rates for personal accounts and unlimited pulls for organisational accounts. See:
- Scaling Docker to Serve Millions More Developers: Network Egress
- Authenticate with Docker to avoid impact of Nov. 1st rate limits
This will significantly hamper our ability to run builds in CircleCI without action. in order to resolve this, CircleCI recommends adding docker hub authentication.
Fortunately, we have access to a DockerHub organisation in the Ministry of Justice, which has free unlimited pulls of images.
Security
We are not using CircleCI contexts as this is a shared organisational level construct, that any pipeline could use. We’re not set up with context restrictions or groups in CircleCI at time of writing.
We need to ensure that each of the circleci projects has an individual DockerID and token added in project level environment variables, reducing blast radius should it become compromised.
Prerequisites
You will need:
- Your own Docker ID, which has been:
- Added to the
ministryofjustice
dockerhub organisation as an owner. - added to the
opgdockerhubusers
team.
- Added to the
- Access to the OPG webops team google group email.
- Access to the project settings on the CircleCI project you are working on.
Ask one of your webops colleagues to help if you don’t have details of these.
Steps
there are 3 main steps:
- Create a service Docker ID
- Add service user to docker organisation and team
- Add docker hub credentials to CircleCI
1. Create a service Docker ID
- On hub.docker.com create a Docker ID, using:
- A strong randomised password
- A name that makes sense for the pipeline.
- The email associated with OPG Webops Google Group, using a
+
email alias to associate with the new Docker ID.
- Take note of the above credentials and store in the webops secure vault for safekeeping.
- Log out of hub.docker.com.
- This will send a validation email to the opg team google group, but look out for one with the correct alias.
- Validate the email.
- Once validated successfully, log back in with the new credentials
- Go to the profile name, drop down to
Account Settings
and selectSecurity
on the screen. - In the Access Tokens click
New Access Token
. - Give the token a useful name e.g.
CircleCI access token
and clickCreate
- On the next dialog, copy the access token provided.
- Paste into the relevant secure vault entry for safekeeping.
- Click
Copy and Close
.
2. Add the service account to organisation and team
- Log in to your own DockerID on hub.docker.com.
- under Organisations click
ministryofjustice
and then clickAdd Member
- Enter the DockerID of the new service user and select
opgdockerhubusers
from the dropdown - Click
Add
.
This user will have Member permissions, which will be enough to pull images. No higher permission level should be set.
3. Add dockerhub credentials to a CircleCI Project
Create AWS Secrets Manager secrets for the DockerID and access token in your product’s module in opg-org-infra. Our intention is to create these secrets in the opg-management AWS account.
module "ci_dockerhub_secrets" { source = "../modules/ci_dockerhub_secrets" product_prefix = "the_name_of_the_product_to_namespace_secrets" providers = { aws = aws.management } } output "aws_secretsmanager_secret_dockerhub_id" { value = module.ci_dockerhub_secrets.aws_secretsmanager_secret_dockerhub_id } output "aws_secretsmanager_secret_dockerhub_token" { value = module.ci_dockerhub_secrets.aws_secretsmanager_secret_dockerhub_token }
Use the aws_secretsmanager_secret_version data source to provide the secret string as an environment variable to CircleCI. You can use the opg-org-infra repository module to create environment variables for CircleCI. Applying this module will set a value of
default
for each secret, to be replaced later.data "aws_secretsmanager_secret_version" "product_dockerhub_id" { secret_id = module.product.aws_secretsmanager_secret_dockerhub_id.id provider = aws.management } data "aws_secretsmanager_secret_version" "product_dockerhub_token" { secret_id = module.product.aws_secretsmanager_secret_dockerhub_token.id provider = aws.management } module "product" { source = "./modules/repository" name = "product" ... circleci_env_vars = { DOCKER_USER = data.aws_secretsmanager_secret_version.product_dockerhub_id.secret_string DOCKER_ACCESS_TOKEN = data.aws_secretsmanager_secret_version.product_dockerhub_token.secret_string
When the secrets have been created, the value of each can be set from the command line with
aws-cli
aws-vault exec management -- aws secretsmanager put-secret-value --secret-id product_prefix-dockerhub_id --secret-string 'somesecretstringvalue' aws-vault exec management -- aws secretsmanager put-secret-value --secret-id product_prefix-dockerhub_token --secret-string 'somesecretstringvalue'
Alternatively, these values can be set in Secrets Manager in the AWS console.
Once these are set, rerun the build workflow on opg-org-infra’s master branch in CircleCI to update your project settings.
4. Adding Docker Authenticated Pulls to CircleCI jobs
CircleCI pulls for executors should be updated to include auth details.
executors: puppeteer: docker: - image: buildkite/puppeteer auth: username: $DOCKER_USER password: $DOCKER_ACCESS_TOKEN resource_class: small
Use the docker orb to create a command that installs the credential helper and completes a docker login.
orbs: path-to-live: orbs: docker: circleci/docker@1.4.0 commands: dockerhub_login: steps: - docker/install-docker-credential-helper - docker/check: docker-password: DOCKER_ACCESS_TOKEN docker-username: DOCKER_USER
Docker pulls inside your jobs can then be authorised just prior to any step that will attempt a docker pull. For example,
docker_build_front_app: executor: python steps: - checkout - setup_remote_docker: version: 19.03.12 docker_layer_caching: false - dockerhub_login - run: name: Build command: docker build --file ./docker/app/Dockerfile --tag front-app:latest .
More information available at using Docker Authenticated Pulls and circleci/docker orb