Accessing private image repositories
When the image repository visibility is set to private (the default), you need to authenticate before you can pull images. Konflux provides an RBAC image proxy that controls access based on your permissions.
Who can pull images and access scope
Access to pull images is controlled at the tenant level through Kubernetes RBAC:
-
Users or service accounts who have permission to
get,list, orwatchImageRepositoryresources in a tenant can pull images from all components in that tenant -
Image path format:
proxy_host/redhat-user-workloads(-stage)/tenant/component:tag -
Without the required RBAC permissions, image pulls will fail
To grant this access, a tenant maintainer creates a Role that permits reading ImageRepository resources, then binds that role to a subject with a RoleBinding:
-
Service account (recommended for automation): bind the role to a
ServiceAccountfor CI/CD pipelines and other external systems. See Granting pull access with a service account. -
User (for local development): bind the role to an individual
Userso a person can pull images with their own token. See Getting registry login credentials via the UI.
|
Tenant administrators cannot create new custom |
Token types and scope
-
User tokens:
-
Any Konflux user can obtain a user token through the proxy authentication flow
-
Issued by the proxy’s Dex (not SSO), so they can ONLY be used for pulling images through the proxy
-
Cannot be used for OpenShift API authentication
-
Expire after 24 hours
-
Best for local development and manual testing
-
-
Service account tokens:
-
Any Konflux user who has permission to create secrets in a namespace can create a service account token in that namespace
-
Can authenticate against both the proxy AND the OpenShift API (works like a regular OpenShift service account)
-
Do not expire (valid until the secret is deleted)
-
Best for automated systems and CI/CD pipelines
-
Finding your proxy URL
The examples on this page use image-rbac-proxy.apps.example.com as a placeholder. Replace it with the RBAC image proxy hostname for the cluster that hosts your tenant. The hostname follows this pattern:
image-rbac-proxy.apps.<cluster-domain>
For example, on the stone-prod-p02 cluster the proxy hostname is:
image-rbac-proxy.apps.stone-prod-p02.hjvn.p1.openshiftapps.com
The proxy hostname matches the domain of the Konflux instance you use, so the login command shown in the UI is always the authoritative source for your cluster. To find the exact hostname:
-
Open the Component details page for any of your components in the Konflux UI.
-
In the Registry login information section, read the
podman logincommand. The host in that command is the proxy hostname for your cluster. -
Copy the private image path shown for the component. It begins with the same proxy hostname.
Granting pull access with a service account
For automated access from external systems such as Testing Farm or CI/CD pipelines, grant a service account permission to pull images. Create the following objects in this order, because each object depends on the ones before it: the Secret and the RoleBinding both reference the ServiceAccount, so the service account must exist first.
-
Create a
Rolethat permits readingImageRepositoryresources:apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: repo-viewer namespace: <your-namespace> rules: - apiGroups: - appstudio.redhat.com resources: - imagerepositories verbs: - get - watch - list -
Create a
ServiceAccount:apiVersion: v1 kind: ServiceAccount metadata: name: external-puller namespace: <your-namespace> -
Create a
Secretthat holds a non-expiring token for the service account. Thekubernetes.io/service-account.nameannotation must reference the service account created in the previous step:apiVersion: v1 kind: Secret metadata: name: external-puller-token namespace: <your-namespace> annotations: kubernetes.io/service-account.name: external-puller type: kubernetes.io/service-account-token -
Create a
RoleBindingthat binds theRoleto theServiceAccount:apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: repo-viewer namespace: <your-namespace> roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: repo-viewer subjects: - kind: ServiceAccount name: external-puller namespace: <your-namespace> -
Get the service account token from the secret:
kubectl get secret external-puller-token -n <your-namespace> -o jsonpath='{.data.token}' | base64 -d -
Use the token to authenticate to the registry in your external system:
podman login -u external-puller image-rbac-proxy.apps.example.com # When prompted for password, paste the service account tokenThen pull images:
podman pull image-rbac-proxy.apps.example.com/redhat-user-workloads/my-tenant/my-app:b153d64
Replace image-rbac-proxy.apps.example.com with your cluster’s proxy hostname. See Finding your proxy URL.
|
| If a token is compromised, delete the secret to revoke the token, then create a new one. The username must match the service account name. |
Getting registry login credentials via the UI
To access private images locally with your own user token:
-
Ask a tenant maintainer to bind the pull
Roleto your user. This uses the sameRoleshown in Granting pull access with a service account, with aUsersubject instead of aServiceAccount:apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: repo-viewer-user namespace: <your-namespace> roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: repo-viewer subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: <your-username> -
Navigate to the Component details page for your component
-
In the Registry login information section, copy and run the
podman logincommand in your terminal:podman login -u unused image-rbac-proxy.apps.example.com -
Click the OAuth URL link to get your authentication token
-
Paste the token when prompted for password
-
Copy the private image path from the UI and pull the image:
podman pull image-rbac-proxy.apps.example.com/redhat-user-workloads/my-tenant/my-app:b153d64The image path includes the proxy host (e.g., image-rbac-proxy.apps.example.com) which enforces access control. You must use this proxy URL, not a direct registry URL. Replace it with your cluster’s proxy hostname; see Finding your proxy URL.
Using Quay image references for local development
For local development, you can configure Podman to route pulls for quay.io/redhat-user-workloads and quay.io/redhat-user-workloads-stage through the RBAC image proxy. This configuration lets you continue to use existing Quay image references in Podman commands, Containerfiles, and Dockerfiles without changing them.
Before you begin, ensure that a tenant maintainer has granted your user permission to pull images, as described in Getting registry login credentials via the UI. You also need podman, xdg-open, and keyctl installed on your Linux system.
-
Add the following configuration to
~/.config/containers/registries.conf:[[registry]] prefix = "quay.io/redhat-user-workloads" location = "quay.io/redhat-user-workloads" [[registry.mirror]] location = "image-rbac-proxy.apps.example.com/redhat-user-workloads" [[registry]] prefix = "quay.io/redhat-user-workloads-stage" location = "quay.io/redhat-user-workloads-stage" [[registry.mirror]] location = "image-rbac-proxy.apps.example.com/redhat-user-workloads-stage"Replace
image-rbac-proxy.apps.example.comwith your cluster’s proxy hostname. See Finding your proxy URL. Podman now tries the proxy mirror first whenever you pull an image from either Quay organization. If the proxy mirror cannot provide the image, Podman falls back to Quay. For a private image, this fallback succeeds only if you are also authenticated and authorized directly by Quay. -
Add the following function to your Bash configuration, such as
~/.bashrc:function image_proxy_login { local _proxy="image-rbac-proxy.apps.example.com" local _key_name="image_proxy_token:${_proxy}" local _key_id local _token _key_id=$(keyctl search @s user "${_key_name}" 2>/dev/null) if [ -n "${_key_id}" ]; then echo "Already logged into ${_proxy}" return fi echo "Logging into ${_proxy}..." xdg-open "https://${_proxy}/oauth" 2>/dev/null echo -n "Paste token from browser: " read -rs _token echo if ! echo -n "${_token}" | podman login "${_proxy}" -u unused --password-stdin; then echo "Login failed" >&2 return 1 fi _key_id=$(echo -n "${_token}" | keyctl padd user "${_key_name}" @s) keyctl timeout "${_key_id}" $((8 * 3600)) }Replace
image-rbac-proxy.apps.example.comwith the same proxy hostname that you used inregistries.conf. -
Reload your Bash configuration and run the helper:
source ~/.bashrc image_proxy_loginThe helper opens the proxy’s OAuth page, prompts you for the displayed token, and logs Podman into the proxy. After a successful login, it stores the token in your session keyring for eight hours so that repeated calls do not prompt you to authenticate again. The key name includes the proxy hostname so that changing clusters triggers a new login.
-
Pull the image by using its original Quay reference:
podman pull quay.io/redhat-user-workloads/my-tenant/my-app:b153d64When the proxy mirror provides the image, it verifies your tenant-level RBAC permissions.