Pulling Images from a Private Container Registry
This guide shows how to configure your P6M cluster to pull container images from a private container registry. This is useful when your organization builds containers using CI/CD pipelines and pushes them to your own registry.
Overview
The setup involves:
- Creating a registry access token with pull permissions
- Storing the credentials in a secret store
- Granting your cluster's External Secrets identity access to the secrets
- Deploying a ClusterExternalSecret that generates
imagePullSecretsfor your namespaces
Prerequisites
kubectlaccess to your P6M cluster
Step 1: Create Registry Credentials
- Azure Container Registry
- GitHub Container Registry
Prerequisites
- Azure CLI installed and logged in
- Access to your Azure Container Registry
Throughout this guide, we use acr-p6m-shared as the name for the scope map, token, Key Vault, and Kubernetes resources. This creates a consistent, identifiable set of resources for your P6M cluster's registry access. You can customize this name to match your organization's naming conventions.
Set Defaults
Look up your ACR's resource group and location:
az acr show --name <your-acr-name> --query "{ResourceGroup:resourceGroup, Location:location}" -o table
Set them as defaults for subsequent commands:
az configure --defaults group=<ResourceGroup> location=<Location>
Create a scope map
This defines pull access to all repositories in your ACR:
az acr scope-map create \
--name acr-p6m-shared \
--registry <your-acr-name> \
--repository '*' content/read \
--description "Pull access to all repositories for P6M Clusters"
Create the token
az acr token create \
--name acr-p6m-shared \
--registry <your-acr-name> \
--scope-map acr-p6m-shared
Save the username and password from the output. You'll need these in Step 2.
Coming soon
Step 2: Store Credentials in Secret Store
- Azure Container Registry
- GitHub Container Registry
Create the Key Vault
az keyvault create --name acr-p6m-shared --enable-rbac-authorization false
Store the credentials
Store each credential as a separate secret:
az keyvault secret set --vault-name acr-p6m-shared --name acr-username --value "<username>"
az keyvault secret set --vault-name acr-p6m-shared --name acr-password --value "<password>"
az keyvault secret set --vault-name acr-p6m-shared --name acr-host --value "<your-acr-name>.azurecr.io"
Coming soon
Step 3: Grant External Secrets Access
- Azure Container Registry
- GitHub Container Registry
Find your External Secrets service principal
Each P6M cluster has a service principal for External Secrets. Find yours:
az ad sp list --all --query "[?ends_with(displayName, 'externalsecrets')].{Name:displayName, AppId:appId}" -o table
Look for {cluster-name}-externalsecrets (e.g., a1p-apps-dev-eastus-externalsecrets).
Grant secret read access
az keyvault set-policy \
--name acr-p6m-shared \
--spn <AppId-from-above> \
--secret-permissions get
Coming soon
Step 4: Deploy Kubernetes Resources
Apply the following resources to your cluster.
- Azure Container Registry
- GitHub Container Registry
ClusterSecretStore
This connects External Secrets to your Key Vault:
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: acr-p6m-shared
spec:
provider:
azurekv:
authType: WorkloadIdentity
vaultUrl: https://acr-p6m-shared.vault.azure.net/
serviceAccountRef:
name: external-secrets-platform
namespace: external-secrets
ClusterExternalSecret
This generates the dockerconfigjson secret in any namespace with the label acr-pull-secret: enabled:
apiVersion: external-secrets.io/v1beta1
kind: ClusterExternalSecret
metadata:
name: acr-dockerconfig
spec:
namespaceSelector:
matchLabels:
acr-pull-secret: enabled
externalSecretSpec:
refreshInterval: 5m
secretStoreRef:
name: acr-p6m-shared
kind: ClusterSecretStore
target:
name: acr-dockerconfig
template:
type: kubernetes.io/dockerconfigjson
engineVersion: v2
data:
.dockerconfigjson: |
{"auths":{"{{ .host }}":{"username":"{{ .username }}","password":"{{ .password }}","auth":"{{ printf "%s:%s" .username .password | b64enc }}"}}}
data:
- secretKey: username
remoteRef:
key: acr-username
- secretKey: password
remoteRef:
key: acr-password
- secretKey: host
remoteRef:
key: acr-host
Coming soon
Step 5: Enable for Your Namespace
Label any namespace that needs to pull images from your registry:
kubectl label namespace <your-namespace> acr-pull-secret=enabled
The acr-dockerconfig secret will be automatically created in that namespace.
Step 6: Use the Image Pull Secret
Reference the secret in your pod or deployment:
spec:
containers:
- name: my-app
image: <your-registry>/my-image:tag
imagePullSecrets:
- name: acr-dockerconfig
Or configure the default service account to use it automatically:
kubectl patch serviceaccount default -n <your-namespace> \
-p '{"imagePullSecrets": [{"name": "acr-dockerconfig"}]}'
Testing the Setup
To verify everything is working, push a test image and run it.
- Azure Container Registry
- GitHub Container Registry
Push a test image to your ACR
az acr import --name <your-acr-name> --source docker.io/library/hello-world:latest --image test/hello-world:latest
Run a one-off test pod
kubectl run hello-world-test --rm -it --restart=Never \
-n <your-namespace> \
--image=<your-acr-name>.azurecr.io/test/hello-world:latest \
--overrides='{"spec":{"imagePullSecrets":[{"name":"acr-dockerconfig"}]}}'
If successful, you'll see the "Hello from Docker!" message and the pod will be automatically removed.
Coming soon
Troubleshooting
Check ClusterSecretStore status
kubectl get clustersecretstore acr-p6m-shared -o yaml
Look for status.conditions - it should show Ready: True.
Check ExternalSecret status
kubectl get externalsecret acr-dockerconfig -n <namespace> -o yaml
Verify the secret was created
kubectl get secret acr-dockerconfig -n <namespace>
Test the credentials
kubectl get secret acr-dockerconfig -n <namespace> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq .
Common issues
| Issue | Cause | Solution |
|---|---|---|
| ClusterSecretStore not ready | Service principal doesn't have Key Vault access | Re-run Step 3 |
| Secret not created in namespace | Namespace missing label | Run kubectl label namespace <ns> acr-pull-secret=enabled |
| Image pull fails with "unauthorized" | Incorrect credentials in Key Vault | Verify secrets in Step 2 match the token from Step 1 |