Skip to content

Configure Image Registry on GCP

This guide explains how the OpenShift image registry works on GCP hosted clusters, how to verify it is functioning, and how to configure or disable it.

Overview

GCP hosted clusters use Workload Identity Federation (WIF) to grant the image registry operator access to a Google Cloud Storage (GCS) bucket for storing container images. No long-lived credentials are stored — the operator uses short-lived tokens issued by the hosted cluster's OIDC provider.

Component Name / Location Purpose
GCP Service Account <infra-id>-image-registry@<project-id>.iam.gserviceaccount.com Identity that GCS bucket operations run as
WIF credential secret installer-cloud-credentials in openshift-image-registry Federated credential JSON consumed by the registry operator
Kubernetes service account cluster-image-registry-operator in openshift-image-registry Issues OIDC tokens exchanged for GCP access tokens
GCS bucket Auto-created by the registry operator Stores container image layers and manifests

Prerequisites

  • A running GCP hosted cluster with oc access to the guest cluster
  • The image-registry GCP service account created during IAM setup (see Create GCP IAM Resources)
  • The --image-registry-service-account flag provided when the cluster was created (see Create a GCP Hosted Cluster)

Default Behavior

When a GCP hosted cluster starts up, the image registry is enabled automatically through a three-step flow:

  1. Credential propagation — The HyperShift control plane reads the image-registry GSA email from the HostedControlPlane spec and generates a WIF credential JSON. This credential is written to the installer-cloud-credentials secret in the openshift-image-registry namespace on the guest cluster.

  2. Bucket creation — The cluster image registry operator reads the WIF credentials and creates a GCS bucket. The bucket name is chosen automatically based on the cluster's infrastructure ID and region.

  3. Registry available — Once the bucket exists and the credentials are valid, the registry operator reports Available=True and the internal registry endpoint becomes active at image-registry.openshift-image-registry.svc:5000.

No manual configuration is required when the cluster is created with the --image-registry-service-account flag.

Verification

Check ClusterOperator Status

Verify the image registry operator is available:

KUBECONFIG=hosted-kubeconfig oc get clusteroperator image-registry

Expected output:

NAME             VERSION   AVAILABLE   PROGRESSING   DEGRADED   SINCE   MESSAGE
image-registry   4.18.0    True        False         False      5m

Check Registry Configuration

Inspect the registry operator configuration to see the GCS bucket that was created:

KUBECONFIG=hosted-kubeconfig oc get configs.imageregistry.operator.openshift.io cluster -o jsonpath='{.spec.storage}'

Expected output shows the GCS bucket:

{"gcs":{"bucket":"<auto-generated-bucket-name>","region":"<region>"}}

Check WIF Credentials

Verify the WIF credential secret was propagated to the guest cluster:

KUBECONFIG=hosted-kubeconfig oc get secret installer-cloud-credentials \
  -n openshift-image-registry -o jsonpath='{.data.service_account\.json}' | base64 -d | python3 -m json.tool

The decoded JSON should contain "type": "external_account" and reference your WIF pool and provider IDs, confirming that short-lived federated tokens are used rather than a service account key.

Advanced Configuration

Custom Bucket Name

To use a specific GCS bucket name instead of the auto-generated one, patch the registry operator configuration after cluster creation:

KUBECONFIG=hosted-kubeconfig oc patch configs.imageregistry.operator.openshift.io cluster \
  --type=merge \
  --patch='{"spec":{"storage":{"gcs":{"bucket":"<your-bucket-name>","region":"<region>"}}}}'

Bucket must exist

The bucket must already exist and the image-registry GSA must have Storage Admin permissions on it. The registry operator will not create a bucket when one is explicitly specified.

Using a Pre-Existing Bucket

If your organization requires using a pre-existing GCS bucket (for example, to apply custom lifecycle policies or retention rules):

  1. Create the bucket in the hosted cluster GCP project:

    gsutil mb -p <project-id> -l <region> gs://<your-bucket-name>
    
  2. Grant the image-registry GSA Storage Admin access:

    gsutil iam ch \
      serviceAccount:<infra-id>-image-registry@<project-id>.iam.gserviceaccount.com:roles/storage.admin \
      gs://<your-bucket-name>
    
  3. Configure the registry operator to use the bucket:

    KUBECONFIG=hosted-kubeconfig oc patch configs.imageregistry.operator.openshift.io cluster \
      --type=merge \
      --patch='{"spec":{"storage":{"gcs":{"bucket":"<your-bucket-name>","region":"<region>"}}}}'
    

Disabling the Image Registry

The image registry can be disabled via the ImageRegistry capability on the HostedCluster. When disabled, the registry operator is not deployed and no GCS bucket is created.

To disable the image registry at cluster creation time, add --capabilities-disabled=ImageRegistry to the hypershift create cluster gcp command (refer to Create a GCP Hosted Cluster for the full command).

To disable the registry on a running cluster, patch the HostedCluster resource on the management cluster:

oc patch hostedcluster <cluster-name> -n <namespace> \
  --type=merge \
  --patch='{"spec":{"capabilities":{"disabled":["ImageRegistry"]}}}'

Note

This merge patch replaces the entire spec.capabilities.disabled list. If your cluster already has other capabilities disabled, include them in the patch to avoid re-enabling them.

Data loss

Disabling the image registry does not delete the GCS bucket or its contents. However, any images stored in the registry will become inaccessible to the cluster while the registry is disabled.

Troubleshooting

Registry Operator Not Available

If oc get clusteroperator image-registry shows Available=False:

  1. Check the registry operator logs:

    KUBECONFIG=hosted-kubeconfig oc logs -n openshift-image-registry \
      deployment/cluster-image-registry-operator
    
  2. Check the installer-cloud-credentials secret exists:

    KUBECONFIG=hosted-kubeconfig oc get secret installer-cloud-credentials \
      -n openshift-image-registry
    

    If the secret is missing, check the control plane namespace on the management cluster:

    oc get events -n <namespace>-<cluster-name> | grep image-registry
    

GCS Bucket Creation Fails (403 Forbidden)

A 403 error on bucket creation means the image-registry GSA does not have sufficient permissions.

Check that the GSA has the Storage Admin role:

gcloud projects get-iam-policy <project-id> \
  --flatten="bindings[].members" \
  --filter="bindings.members:<infra-id>-image-registry@<project-id>.iam.gserviceaccount.com" \
  --format="table(bindings.role)"

The output should include roles/storage.admin. If it does not, recreate the IAM resources using hypershift create iam gcp or grant the role manually:

gcloud projects add-iam-policy-binding <project-id> \
  --member="serviceAccount:<infra-id>-image-registry@<project-id>.iam.gserviceaccount.com" \
  --role="roles/storage.admin"

WIF Authentication Errors

If the registry operator logs show token exchange errors (e.g., invalid_grant or audience mismatch):

  1. Verify the WIF credential references the correct pool and provider:

    KUBECONFIG=hosted-kubeconfig oc get secret installer-cloud-credentials \
      -n openshift-image-registry -o jsonpath='{.data.service_account\.json}' | base64 -d
    

    Confirm the audience field matches the WIF provider URL: //iam.googleapis.com/projects/<project-number>/locations/global/workloadIdentityPools/<pool-id>/providers/<provider-id>

  2. Verify the WIF provider trust configuration allows the Kubernetes service account:

    gcloud iam workload-identity-pools providers describe <provider-id> \
      --workload-identity-pool=<pool-id> \
      --project=<project-id> \
      --location=global
    

Bucket Already Exists (409 Conflict)

GCS bucket names are globally unique. If the auto-generated name conflicts with an existing bucket, the registry operator will log a 409 error.

Configure the registry to use a different bucket name:

KUBECONFIG=hosted-kubeconfig oc patch configs.imageregistry.operator.openshift.io cluster \
  --type=merge \
  --patch='{"spec":{"storage":{"gcs":{"bucket":"<unique-bucket-name>","region":"<region>"}}}}'

Then create the bucket and grant permissions as described in Using a Pre-Existing Bucket.

Storage Quota Exceeded

If the GCP project has a storage quota that limits GCS bucket creation or capacity, check current quota usage in the GCP Console Cloud Storage quotas page and request an increase if needed, or contact your GCP administrator.