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
ministryofjusticedockerhub organisation as an owner. - added to the
opgdockerhubusersteam.
- 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 Settingsand selectSecurityon the screen. - In the Access Tokens click
New Access Token. - Give the token a useful name e.g.
CircleCI access tokenand 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
ministryofjusticeand then clickAdd Member - Enter the DockerID of the new service user and select
opgdockerhubusersfrom 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
defaultfor 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_stringWhen the secrets have been created, the value of each can be set from the command line with
aws-cliaws-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: smallUse 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_USERDocker 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