OpenShift Cluster-Wide Pull Secret with Robot Account
Replace admin credentials in the OpenShift cluster-wide pull secret with a Quay robot account for secure, auditable container image pulls across all namespaces.
π‘ Quick Answer: Extract the cluster-wide pull secret with
oc extract, merge your Quay robot credentials usingjq, then update withoc set data secret/pull-secretβ all nodes and namespaces inherit the new credentials immediately.
The Problem
You set up an OpenShift cluster using admin credentials for your Quay registry. Now you need to replace those with a robot account because:
- Admin credentials are overprivileged β they can push, delete, and manage repositories
- Shared passwords are a security risk β if leaked, the entire registry is compromised
- No audit trail β admin actions canβt be distinguished from cluster pulls
- Compliance requirements β production clusters should use service accounts, not personal credentials
The common mistake is trying to patch a ServiceAccount template directly:
# β This does NOT work on OpenShift 4.x
oc patch template serviceaccount/default \
--patch '{"objects":[{"kind":"ServiceAccount",...}]}'
# error: there is no need to specify a resource type as a separate argumentThe correct approach is to update the cluster-wide pull secret.
The Solution
Step 1: Create the Robot Account Secret
First, apply the robot account secret YAML from Quay:
# Apply the robot secret file from Quay
oc apply -f robot-pull-secret.yml -n openshift-configThe secret YAML looks like:
apiVersion: v1
kind: Secret
metadata:
name: quay-robot-pull-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <BASE64_ENCODED_DOCKER_CONFIG>Step 2: Extract the Current Cluster-Wide Pull Secret
# Extract to current directory
oc extract secret/pull-secret \
-n openshift-config \
--to=. --confirmThis creates .dockerconfigjson containing the current credentials:
{
"auths": {
"quay.internal.example.com": {
"auth": "YWRtaW46YWRtaW4tcGFzc3dvcmQ="
}
}
}Step 3: Decode and Verify Current Credentials
Always check whatβs currently configured before changing:
# Decode the auth field to see username:password
cat .dockerconfigjson | jq -r '.auths["quay.internal.example.com"].auth' | base64 -d
# Output: admin:admin-passwordStep 4: Extract Robot Account Credentials
# Decode the robot secret
oc get secret quay-robot-pull-secret \
-n openshift-config \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d > robot.json
# Verify the robot credentials
cat robot.json | jq -r '.auths["quay.internal.example.com"].auth' | base64 -d
# Output: myorg+k8s_prod_puller:ROBOT_TOKEN_HEREStep 5: Merge Robot Credentials into the Cluster Pull Secret
Replace admin credentials with the robot account:
# Merge: robot credentials replace admin for the same registry host
jq -s '.[0].auths + .[1].auths | {auths: .}' \
.dockerconfigjson robot.json > merged.json
# Verify the merge β admin credentials should be replaced
cat merged.json | jq .The merged result should show only the robot credentials:
{
"auths": {
"quay.internal.example.com": {
"auth": "bXlvcmcrazhzX3Byb2RfcHVsbGVyOlJPQk9UX1RPS0VOX0hFUkU=",
"email": ""
}
}
}Step 6: Update the Cluster-Wide Pull Secret
# Apply the merged credentials
oc set data secret/pull-secret \
-n openshift-config \
--from-file=.dockerconfigjson=merged.jsonStep 7: Verify the Update
# Confirm the cluster pull secret now uses robot credentials
oc get secret pull-secret -n openshift-config \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq .
# Decode the auth to confirm it's the robot account
oc get secret pull-secret -n openshift-config \
-o jsonpath='{.data.\.dockerconfigjson}' | base64 -d \
| jq -r '.auths["quay.internal.example.com"].auth' \
| base64 -d
# Expected: myorg+k8s_prod_puller:ROBOT_TOKEN_HEREStep 8: Test Image Pulls
# Create a test pod to verify pulls work
oc run test-pull --image=quay.internal.example.com/myorg/test-image:latest \
--restart=Never -n default
# Check events
oc describe pod test-pull -n default | grep -A5 "Events:"
# Clean up
oc delete pod test-pull -n defaultflowchart TD
A[Quay Robot Account] -->|Token| B[Robot Pull Secret]
B -->|oc set data| C[Cluster-Wide pull-secret<br/>openshift-config namespace]
C -->|Inherited by| D[All Nodes]
C -->|Inherited by| E[All Namespaces]
D -->|Authenticated Pull| F[Quay Registry]
E -->|Pods use| DCommon Issues
Nodes Donβt Pick Up New Credentials Immediately
After updating the cluster-wide pull secret, OpenShiftβs Machine Config Operator rolls out the change to nodes. This can take several minutes:
# Monitor the rollout
oc get machineconfigpool -wWait until all pools show UPDATED=True and DEGRADED=False.
Multiple Registries in One Pull Secret
If your cluster pulls from multiple registries, preserve all entries during the merge:
# Merge preserving all existing registries
jq -s '
{auths: (.[0].auths * .[1].auths)}
' .dockerconfigjson robot.json > merged.jsonThe * operator in jq merges objects, overwriting only matching keys.
Verifying the Base64 Auth Field
# Three ways to decode base64 on Linux
echo "YWRtaW46cGFzc3dvcmQ=" | base64 -d
# Or with Python
python3 -c "import base64; print(base64.b64decode('YWRtaW46cGFzc3dvcmQ=').decode())"
# Or decode the full chain from the secret
oc get secret pull-secret -n openshift-config -o json \
| jq -r '.data[".dockerconfigjson"]' | base64 -d | jqBest Practices
- Never use admin credentials in production clusters β always replace with robot accounts that have read-only access
- Back up before changing β save the original
.dockerconfigjsonbefore merging - Verify after updating β decode the secret to confirm the right credentials are active
- Clean up local files β delete
.dockerconfigjson,robot.json, andmerged.jsonafter updating - Monitor the MCO rollout β wait for all MachineConfigPools to finish updating
- Document the robot account β record which robot account is used in your cluster runbook
Key Takeaways
- The cluster-wide pull secret in
openshift-config/pull-secretis the correct place for registry credentials β not per-namespace ServiceAccount patches - Use
oc extractβjq -s mergeβoc set dataas the three-step workflow - Always decode and verify Base64 auth fields before and after changes
- Robot accounts provide scoped, auditable access compared to admin credentials

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
