Pipeline Identities, Part 2: Docker Hub and a Stored Token
In this part you'll make the pipeline push a Docker image to Docker Hub. The call you'll cover:
- call 3, job → Docker Hub: the job pushes the image with an access token you stored in GitHub.
It needs a Docker Hub account. It is the one call in the lab with a credential stored in GitHub, so it is the one a thief could copy.
Add the image's files
The image is a web page served by nginx, stamped with the commit it was built from.
Create
app/Dockerfile:1FROM nginx:1.29-alpine 2ARG COMMIT=unknown 3COPY index.html /usr/share/nginx/html/index.html 4RUN sed -i "s/COMMIT/${COMMIT}/" /usr/share/nginx/html/index.htmlCreate
app/index.html:1<!doctype html> 2<html> 3<head><meta charset="utf-8"><title>pipeline-identities</title></head> 4<body> 5 <h1>Hello from the pipeline</h1> 6 <p>Built from commit COMMIT.</p> 7</body> 8</html>
Add the Docker Hub steps
In .github/workflows/pipeline.yml, add two steps after the checkout:
1 - name: Log in to Docker Hub with the stored token
2 uses: docker/login-action@v4
3 with:
4 username: ${{ vars.DOCKERHUB_USERNAME }}
5 password: ${{ secrets.DOCKERHUB_TOKEN }}
6
7 - name: Build and push the image
8 run: |
9 IMAGE="docker.io/${{ vars.DOCKERHUB_USERNAME }}/pipeline-identities:${GITHUB_SHA}"
10 docker build --build-arg COMMIT="$GITHUB_SHA" -t "$IMAGE" app
11 docker push "$IMAGE"
12 echo "IMAGE=$IMAGE" >> "$GITHUB_ENV"
docker/login-actionrunsdocker loginwith your Docker ID and the token, and logs out when the job ends.vars.reads a repository variable,secrets.a repository secret.
- The image tag is the commit's SHA, so every push makes a new image.
$GITHUB_ENVkeepsIMAGEfor the later steps; Part 5 deploys it.
Push, and read the refusal
Commit and push.
Open the run. Log in to Docker Hub fails:
1Error: Username and password required- The repository has no variable
DOCKERHUB_USERNAMEand no secretDOCKERHUB_TOKENyet, so both are empty. - The job has nothing to show Docker Hub, and the step stops before asking.
- The repository has no variable
Create the Docker Hub repository
On Docker Hub, open Repositories → Create a repository:
- Name:
pipeline-identities. - Visibility: Private.
- Anyone may pull a public image, with no credential, which would leave call 7 nothing to show.
Create the access token
- Open Account settings → Personal access tokens → Generate new token.
- Fill it in:
- Access token description:
pipeline-identities push; - Expiration date: 30 days;
- Access permissions: Repo Read & Write, enough to push.
- Access token description:
- Generate, then copy the token: Docker Hub shows it once.
A personal access token has
one permission level for every repository your account can access:
it cannot be limited to pipeline-identities.
Store the token in GitHub
In your repository, open Settings → Secrets and variables → Actions:
- Secrets → New repository secret: name
DOCKERHUB_TOKEN, value the token.- GitHub never shows a secret again, and masks it as
***in every log.
- GitHub never shows a secret again, and masks it as
- Variables → New repository variable: name
DOCKERHUB_USERNAME, value your Docker ID.- A user name is not a secret, so it is a variable, readable in the log.
Run the pipeline again
- Open the failed run, and Re-run all jobs: nothing in the repository changed, and a run reads the secrets and variables when it starts.
- Read the log:
- Log in to Docker Hub ends with
Login Succeeded!; - Build and push ends with the image's digest.
- Log in to Docker Hub ends with
- On Docker Hub, check the repository: it holds a tag named after the commit.
Use the token outside the pipeline
Nothing ties the token to GitHub: whoever holds it can use it, from anywhere. That is a bearer token.
On your own machine, log in with the token as the password, and pull the image:
1$ docker login -u <your-docker-id>
2Password:
3Login Succeeded
4$ docker pull docker.io/<your-docker-id>/pipeline-identities:<commit-sha>
5$ docker logout
Deactivate the token
Docker Hub refuses a deactivated token at once, wherever it is stored.
- On Docker Hub, open Personal access tokens, and deactivate
pipeline-identities push. - On GitHub, open the last run, and Re-run all jobs.
- Read the log: Log in to Docker Hub fails, with an
unauthorizederror. This time Docker Hub refuses. - Activate the token again, and re-run: it passes.