Pipeline Identities, Part 6: The Cluster Pulling a Private Image

In this part you'll give the cluster a credential of its own, so its pods can pull the private image. The call you'll cover:

  • call 7, cluster → Docker Hub: the node starting a pod pulls the image Part 5 deployed.

The caller here is not the job.

  • Part 5's last run was this call's refusal: pull access denied, since the node had no credential.
  • The node gets a Docker Hub token of its own, read-only, stored in the cluster as an image pull secret.

Create a read-only token

A second token, so the cluster holds only what it needs.

  1. On Docker Hub, open Account settings → Personal access tokens → Generate new token.
  2. Fill it in:
    • Access token description: pipeline-identities pull;
    • Access permissions: Repo Read-only: pull, also from private repositories, and no push.
  3. Generate, and copy the token.

Store the token in the cluster

Create the secret from your own machine: the pipeline never sees this token.

1$ kubectl create secret docker-registry dockerhub-pull -n web \
2>   --docker-server=https://index.docker.io/v1/ \
3>   --docker-username=<your-docker-id> \
4>   --docker-password=<the-read-only-token>
5secret/dockerhub-pull created

Name the secret in the pod, and wait for the rollout

  1. In k8s/deployment.yaml, add imagePullSecrets to the pod template. A pod pulls with the secrets its spec names.

    1    spec:
    2      imagePullSecrets:
    3        - name: dockerhub-pull
    4      containers:
    5        - name: web
    
  2. In .github/workflows/pipeline.yml, change the deploy step to wait for the pods instead of listing them:

    1      - name: Deploy to the web namespace
    2        run: |
    3          sed "s|IMAGE_PLACEHOLDER|$IMAGE|" k8s/deployment.yaml | kubectl apply -n web -f -
    4          kubectl rollout status deployment/hello -n web --timeout=180s
    

Push, and open the site

  1. Commit and push both files. The deploy step ends with deployment "hello" successfully rolled out.

  2. Check the pods, and ask the site which commit it was built from:

    1$ kubectl get pods -n web
    2NAME                     READY   STATUS    RESTARTS   AGE
    3hello-7f9b6c5d4-9wz2m    1/1     Running   0          40s
    4hello-7f9b6c5d4-qk8rt    1/1     Running   0          40s
    5$ kubectl port-forward -n web svc/hello 8080:80 &
    6$ curl -s localhost:8080 | grep commit
    7  <p>Built from commit 3f1c…</p>
    

Read the pull token back

An image pull secret is a secret like any other: whoever may read secrets in web can read the token. Read it from your machine:

1$ kubectl get secret dockerhub-pull -n web -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
2{"auths":{"https://index.docker.io/v1/":{"username":"<your-docker-id>","password":"dckr_pat_…","auth":"…"}}}
  • Base64 is an encoding, not a protection.
  • AmazonEKSEditPolicy lets the pipeline's role read secrets in web, so the pipeline could read this token too.
  • The token reads every private repository of your Docker Hub account.