From 5ebd08b41f86c5040e5a0564622a92a07dd1b21f Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Mon, 29 Jun 2026 20:49:22 +0100 Subject: [PATCH 01/11] CORS-4508: Add e2e-gcd installer CI job for Google Cloud Dedicated Add step-registry components and CI job for testing OpenShift installations on Google Cloud Dedicated using Workload Identity Federation. New step-registry components: - ipi-conf-gcd-wif-auth ref: sets up WIF auth via AWS identity chain - ipi-conf-gcd chain: GCP config with WIF auth step - ipi-gcd-pre chain: full GCD pre-install chain - openshift-e2e-gcd workflow: end-to-end test workflow for GCD The auth flow uses AWS identity chaining: ci-ops injects an AWS config file, the step uses the hub profile (trusted by GCD WIF pool), and the WIF credential config stored as gce.json in the cluster profile secret enables the Google SDK to exchange AWS credentials for GCD tokens. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../installer/openshift-installer-main.yaml | 12 +++ .../openshift-installer-main-presubmits.yaml | 90 +++++++++++++++++++ ci-operator/step-registry/ipi/conf/gcd/OWNERS | 4 + .../conf/gcd/ipi-conf-gcd-chain.metadata.json | 10 +++ .../ipi/conf/gcd/ipi-conf-gcd-chain.yaml | 13 +++ .../ipi/conf/gcd/wif-auth/OWNERS | 4 + .../ipi-conf-gcd-wif-auth-commands.sh | 26 ++++++ .../ipi-conf-gcd-wif-auth-ref.metadata.json | 10 +++ .../wif-auth/ipi-conf-gcd-wif-auth-ref.yaml | 30 +++++++ ci-operator/step-registry/ipi/gcd/pre/OWNERS | 4 + .../gcd/pre/ipi-gcd-pre-chain.metadata.json | 10 +++ .../ipi/gcd/pre/ipi-gcd-pre-chain.yaml | 9 ++ .../step-registry/openshift/e2e/gcd/OWNERS | 4 + .../openshift-e2e-gcd-workflow.metadata.json | 10 +++ .../e2e/gcd/openshift-e2e-gcd-workflow.yaml | 14 +++ 15 files changed, 250 insertions(+) create mode 100644 ci-operator/step-registry/ipi/conf/gcd/OWNERS create mode 100644 ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json create mode 100644 ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml create mode 100644 ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS create mode 100755 ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh create mode 100644 ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json create mode 100644 ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml create mode 100644 ci-operator/step-registry/ipi/gcd/pre/OWNERS create mode 100644 ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json create mode 100644 ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml create mode 100644 ci-operator/step-registry/openshift/e2e/gcd/OWNERS create mode 100644 ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json create mode 100644 ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml diff --git a/ci-operator/config/openshift/installer/openshift-installer-main.yaml b/ci-operator/config/openshift/installer/openshift-installer-main.yaml index b65d8d54ec200..99db4a546c6c9 100644 --- a/ci-operator/config/openshift/installer/openshift-installer-main.yaml +++ b/ci-operator/config/openshift/installer/openshift-installer-main.yaml @@ -530,6 +530,18 @@ tests: FEATURE_SET: TechPreviewNoUpgrade OS_IMAGE_STREAM: rhel-10 workflow: openshift-e2e-aws +- always_run: false + as: e2e-gcd + cluster: build13 + optional: true + steps: + cluster_profile: gcd + env: + AWS_CONFIG_FILE: /var/run/secrets/aws/config/config + AWS_PROFILE: hub + COMPUTE_NODE_REPLICAS: "2" + GOOGLE_CLOUD_UNIVERSE_DOMAIN: apis-berlin-build0.goog + workflow: openshift-e2e-gcd - as: e2e-gcp-ovn run_if_changed: (gcp|google) steps: diff --git a/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml b/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml index 6d356881046d9..ab087803d1485 100644 --- a/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml +++ b/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml @@ -5803,6 +5803,96 @@ presubmits: secret: secretName: result-aggregator trigger: (?m)^/test( | .* )e2e-external-aws-ccm,?($|\s.*) + - agent: kubernetes + always_run: false + branches: + - ^main$ + - ^main- + cluster: build13 + context: ci/prow/e2e-gcd + decorate: true + decoration_config: + sparse_checkout_files: + - .ci-operator.yaml + - images/baremetal/Dockerfile.ci + - images/installer/Dockerfile.ci + - images/installer/Dockerfile.upi.ci + - images/libvirt/Dockerfile.ci + - images/openstack/Dockerfile.ci + labels: + ci-operator.openshift.io/cloud: gcp + ci-operator.openshift.io/cloud-cluster-profile: gcd + ci-operator.openshift.io/cluster: build13 + ci.openshift.io/generator: prowgen + pj-rehearse.openshift.io/can-be-rehearsed: "true" + name: pull-ci-openshift-installer-main-e2e-gcd + optional: true + rerun_command: /test e2e-gcd + spec: + containers: + - args: + - --gcs-upload-secret=/secrets/gcs/service-account.json + - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --lease-server-credentials-file=/etc/boskos/credentials + - --report-credentials-file=/etc/report/credentials + - --secret-dir=/secrets/ci-pull-credentials + - --target=e2e-gcd + command: + - ci-operator + env: + - name: HTTP_SERVER_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest + imagePullPolicy: Always + name: "" + ports: + - containerPort: 8080 + name: http + resources: + requests: + cpu: 10m + volumeMounts: + - mountPath: /etc/boskos + name: boskos + readOnly: true + - mountPath: /secrets/ci-pull-credentials + name: ci-pull-credentials + readOnly: true + - mountPath: /secrets/gcs + name: gcs-credentials + readOnly: true + - mountPath: /secrets/manifest-tool + name: manifest-tool-local-pusher + readOnly: true + - mountPath: /etc/pull-secret + name: pull-secret + readOnly: true + - mountPath: /etc/report + name: result-aggregator + readOnly: true + serviceAccountName: ci-operator + volumes: + - name: boskos + secret: + items: + - key: credentials + path: credentials + secretName: boskos-credentials + - name: ci-pull-credentials + secret: + secretName: ci-pull-credentials + - name: manifest-tool-local-pusher + secret: + secretName: manifest-tool-local-pusher + - name: pull-secret + secret: + secretName: registry-pull-credentials + - name: result-aggregator + secret: + secretName: result-aggregator + trigger: (?m)^/test( | .* )e2e-gcd,?($|\s.*) - agent: kubernetes always_run: false branches: diff --git a/ci-operator/step-registry/ipi/conf/gcd/OWNERS b/ci-operator/step-registry/ipi/conf/gcd/OWNERS new file mode 100644 index 0000000000000..720f096f6c037 --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/OWNERS @@ -0,0 +1,4 @@ +approvers: +- patrickdillon +- rochacbruno +- tthvo diff --git a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json new file mode 100644 index 0000000000000..ceab6c8856948 --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json @@ -0,0 +1,10 @@ +{ + "path": "ipi/conf/gcd/ipi-conf-gcd-chain.yaml", + "owners": { + "approvers": [ + "patrickdillon", + "rochacbruno", + "tthvo" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml new file mode 100644 index 0000000000000..d184cdc57b50a --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml @@ -0,0 +1,13 @@ +chain: + as: ipi-conf-gcd + steps: + - ref: ipi-conf + - ref: ipi-conf-telemetry + - ref: ipi-conf-gcd-wif-auth + - ref: ipi-conf-gcp + - ref: ipi-conf-gcp-zones + - ref: ipi-install-monitoringpvc + documentation: >- + This chain generates an install-config.yaml configured to run clusters + on Google Cloud Dedicated (GCD). Sets up WIF authentication before + configuring GCP-specific install-config fields. diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS new file mode 100644 index 0000000000000..720f096f6c037 --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS @@ -0,0 +1,4 @@ +approvers: +- patrickdillon +- rochacbruno +- tthvo diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh new file mode 100755 index 0000000000000..ee5cdca7ad2cc --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -euo pipefail + +export AWS_CONFIG_FILE=/var/run/secrets/aws/config/config +export AWS_PROFILE=hub + +export GOOGLE_CLOUD_UNIVERSE_DOMAIN="${GOOGLE_CLOUD_UNIVERSE_DOMAIN:-apis-berlin-build0.goog}" + +CRED_FILE="${CLUSTER_PROFILE_DIR}/gce.json" +if [[ ! -f "${CRED_FILE}" ]]; then + echo "ERROR: WIF credential config not found at ${CRED_FILE}" + exit 1 +fi + +echo "Authenticating to GCD via Workload Identity Federation..." + +[[ $- == *x* ]] && WAS_TRACING=true || WAS_TRACING=false +set +x + +gcloud auth login --cred-file "${CRED_FILE}" --quiet + +$WAS_TRACING && set -x + +echo "GCD WIF authentication configured" +gcloud auth list diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json new file mode 100644 index 0000000000000..c48b533abcef5 --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json @@ -0,0 +1,10 @@ +{ + "path": "ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml", + "owners": { + "approvers": [ + "patrickdillon", + "rochacbruno", + "tthvo" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml new file mode 100644 index 0000000000000..13bd16e7000a2 --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml @@ -0,0 +1,30 @@ +ref: + as: ipi-conf-gcd-wif-auth + from_image: + namespace: ocp + name: "4.18" + tag: upi-installer + commands: ipi-conf-gcd-wif-auth-commands.sh + resources: + requests: + cpu: 10m + memory: 100Mi + env: + - name: AWS_CONFIG_FILE + default: "/var/run/secrets/aws/config/config" + documentation: |- + Path to the AWS config file injected by ci-ops. Contains the + identity chain profiles used by GCD WIF for authentication. + - name: AWS_PROFILE + default: "hub" + documentation: |- + The AWS profile to use for GCD WIF authentication. Must be "hub" + because GCD WIF trusts only the hub account (320297955214). + - name: GOOGLE_CLOUD_UNIVERSE_DOMAIN + default: "apis-berlin-build0.goog" + documentation: |- + The universe domain for Google Cloud Dedicated. + documentation: |- + Sets up Workload Identity Federation authentication for Google Cloud + Dedicated (GCD). Configures the AWS identity chain that GCD's WIF pool + trusts, and authenticates gcloud with the WIF credential config. diff --git a/ci-operator/step-registry/ipi/gcd/pre/OWNERS b/ci-operator/step-registry/ipi/gcd/pre/OWNERS new file mode 100644 index 0000000000000..720f096f6c037 --- /dev/null +++ b/ci-operator/step-registry/ipi/gcd/pre/OWNERS @@ -0,0 +1,4 @@ +approvers: +- patrickdillon +- rochacbruno +- tthvo diff --git a/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json new file mode 100644 index 0000000000000..0ab9b7c86121d --- /dev/null +++ b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json @@ -0,0 +1,10 @@ +{ + "path": "ipi/gcd/pre/ipi-gcd-pre-chain.yaml", + "owners": { + "approvers": [ + "patrickdillon", + "rochacbruno", + "tthvo" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml new file mode 100644 index 0000000000000..56ee158107d3d --- /dev/null +++ b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml @@ -0,0 +1,9 @@ +chain: + as: ipi-gcd-pre + steps: + - chain: ipi-conf-gcd + - ref: rhcos-conf-osstream + - chain: ipi-install + documentation: |- + The IPI GCD setup chain provisions an OpenShift cluster with a default + configuration on Google Cloud Dedicated using WIF authentication. diff --git a/ci-operator/step-registry/openshift/e2e/gcd/OWNERS b/ci-operator/step-registry/openshift/e2e/gcd/OWNERS new file mode 100644 index 0000000000000..720f096f6c037 --- /dev/null +++ b/ci-operator/step-registry/openshift/e2e/gcd/OWNERS @@ -0,0 +1,4 @@ +approvers: +- patrickdillon +- rochacbruno +- tthvo diff --git a/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json new file mode 100644 index 0000000000000..c07540edf3658 --- /dev/null +++ b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json @@ -0,0 +1,10 @@ +{ + "path": "openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml", + "owners": { + "approvers": [ + "patrickdillon", + "rochacbruno", + "tthvo" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml new file mode 100644 index 0000000000000..d93739c82345a --- /dev/null +++ b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml @@ -0,0 +1,14 @@ +workflow: + as: openshift-e2e-gcd + steps: + allow_best_effort_post_steps: true + pre: + - chain: ipi-gcd-pre + test: + - ref: openshift-e2e-test + post: + - chain: gather-core-dump + - chain: ipi-gcp-post + documentation: |- + The OpenShift E2E GCD workflow executes the common end-to-end test + suite on Google Cloud Dedicated with WIF authentication. From 502a13ef149d6df9a9d8b0ae781b07aea026203d Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Mon, 29 Jun 2026 21:16:03 +0100 Subject: [PATCH 02/11] Add missing OWNERS file for ipi/gcd directory Co-Authored-By: Claude Opus 4.6 (1M context) --- ci-operator/step-registry/ipi/gcd/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ci-operator/step-registry/ipi/gcd/OWNERS diff --git a/ci-operator/step-registry/ipi/gcd/OWNERS b/ci-operator/step-registry/ipi/gcd/OWNERS new file mode 100644 index 0000000000000..720f096f6c037 --- /dev/null +++ b/ci-operator/step-registry/ipi/gcd/OWNERS @@ -0,0 +1,4 @@ +approvers: +- patrickdillon +- rochacbruno +- tthvo From f55dbe93972135d2897a7b6a726b56ccbd5222da Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Mon, 29 Jun 2026 21:26:04 +0100 Subject: [PATCH 03/11] Address review feedback on WIF auth step - Use ${VAR:-default} pattern so env vars from ref/config are honored - Remove gcloud auth login since it doesn't persist across steps; each step authenticates independently via GOOGLE_CLOUD_KEYFILE_JSON pointing to gce.json from the cluster profile mount Co-Authored-By: Claude Opus 4.6 (1M context) --- .../wif-auth/ipi-conf-gcd-wif-auth-commands.sh | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh index ee5cdca7ad2cc..453ef94baca77 100755 --- a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh @@ -2,8 +2,8 @@ set -euo pipefail -export AWS_CONFIG_FILE=/var/run/secrets/aws/config/config -export AWS_PROFILE=hub +export AWS_CONFIG_FILE="${AWS_CONFIG_FILE:-/var/run/secrets/aws/config/config}" +export AWS_PROFILE="${AWS_PROFILE:-hub}" export GOOGLE_CLOUD_UNIVERSE_DOMAIN="${GOOGLE_CLOUD_UNIVERSE_DOMAIN:-apis-berlin-build0.goog}" @@ -13,14 +13,8 @@ if [[ ! -f "${CRED_FILE}" ]]; then exit 1 fi -echo "Authenticating to GCD via Workload Identity Federation..." - -[[ $- == *x* ]] && WAS_TRACING=true || WAS_TRACING=false -set +x - -gcloud auth login --cred-file "${CRED_FILE}" --quiet - -$WAS_TRACING && set -x - echo "GCD WIF authentication configured" -gcloud auth list +echo " AWS_CONFIG_FILE=${AWS_CONFIG_FILE}" +echo " AWS_PROFILE=${AWS_PROFILE}" +echo " GOOGLE_CLOUD_UNIVERSE_DOMAIN=${GOOGLE_CLOUD_UNIVERSE_DOMAIN}" +echo " Credential config: ${CRED_FILE}" From 484d34060410f3d29bb1dc03bd61a7c2958fcf0d Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Tue, 30 Jun 2026 10:36:56 +0100 Subject: [PATCH 04/11] Add PUBLISH: Internal for GCD private cluster GCD only supports private DNS zones, so the cluster must be published internally. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../config/openshift/installer/openshift-installer-main.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-operator/config/openshift/installer/openshift-installer-main.yaml b/ci-operator/config/openshift/installer/openshift-installer-main.yaml index 99db4a546c6c9..ed1eae517a6df 100644 --- a/ci-operator/config/openshift/installer/openshift-installer-main.yaml +++ b/ci-operator/config/openshift/installer/openshift-installer-main.yaml @@ -541,6 +541,7 @@ tests: AWS_PROFILE: hub COMPUTE_NODE_REPLICAS: "2" GOOGLE_CLOUD_UNIVERSE_DOMAIN: apis-berlin-build0.goog + PUBLISH: Internal workflow: openshift-e2e-gcd - as: e2e-gcp-ovn run_if_changed: (gcp|google) From f5b5480f8bd499237b775f4f8f34615e5cd05f75 Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Tue, 30 Jun 2026 10:58:04 +0100 Subject: [PATCH 05/11] Address review feedback - Rename e2e-gcd to e2e-gcd-techpreview, add FEATURE_SET: TechPreviewNoUpgrade - Switch from build13 (GCP) to build07 (AWS) for STS role assumption - Add PUBLISH: Internal (GCD only supports private DNS zones) - Remove AWS_CONFIG_FILE/AWS_PROFILE env overrides (injected by ci-operator) - Simplify WIF auth step to validate credential config and declare GOOGLE_CLOUD_UNIVERSE_DOMAIN env var - Add barbacbd to OWNERS files Co-Authored-By: Claude Opus 4.6 (1M context) --- .../installer/openshift-installer-main.yaml | 7 +++---- .../openshift-installer-main-presubmits.yaml | 14 +++++++------- ci-operator/step-registry/ipi/conf/gcd/OWNERS | 1 + .../ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json | 1 + .../ipi/conf/gcd/ipi-conf-gcd-chain.yaml | 4 ++-- .../step-registry/ipi/conf/gcd/wif-auth/OWNERS | 1 + .../wif-auth/ipi-conf-gcd-wif-auth-commands.sh | 15 ++++++++------- .../ipi-conf-gcd-wif-auth-ref.metadata.json | 1 + .../gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml | 15 ++------------- ci-operator/step-registry/ipi/gcd/OWNERS | 1 + ci-operator/step-registry/ipi/gcd/pre/OWNERS | 1 + .../ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json | 1 + .../step-registry/openshift/e2e/gcd/OWNERS | 1 + .../gcd/openshift-e2e-gcd-workflow.metadata.json | 1 + 14 files changed, 31 insertions(+), 33 deletions(-) diff --git a/ci-operator/config/openshift/installer/openshift-installer-main.yaml b/ci-operator/config/openshift/installer/openshift-installer-main.yaml index ed1eae517a6df..60dedeb290d29 100644 --- a/ci-operator/config/openshift/installer/openshift-installer-main.yaml +++ b/ci-operator/config/openshift/installer/openshift-installer-main.yaml @@ -531,15 +531,14 @@ tests: OS_IMAGE_STREAM: rhel-10 workflow: openshift-e2e-aws - always_run: false - as: e2e-gcd - cluster: build13 + as: e2e-gcd-techpreview + cluster: build07 optional: true steps: cluster_profile: gcd env: - AWS_CONFIG_FILE: /var/run/secrets/aws/config/config - AWS_PROFILE: hub COMPUTE_NODE_REPLICAS: "2" + FEATURE_SET: TechPreviewNoUpgrade GOOGLE_CLOUD_UNIVERSE_DOMAIN: apis-berlin-build0.goog PUBLISH: Internal workflow: openshift-e2e-gcd diff --git a/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml b/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml index ab087803d1485..68d15d27f84df 100644 --- a/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml +++ b/ci-operator/jobs/openshift/installer/openshift-installer-main-presubmits.yaml @@ -5808,8 +5808,8 @@ presubmits: branches: - ^main$ - ^main- - cluster: build13 - context: ci/prow/e2e-gcd + cluster: build07 + context: ci/prow/e2e-gcd-techpreview decorate: true decoration_config: sparse_checkout_files: @@ -5822,12 +5822,12 @@ presubmits: labels: ci-operator.openshift.io/cloud: gcp ci-operator.openshift.io/cloud-cluster-profile: gcd - ci-operator.openshift.io/cluster: build13 + ci-operator.openshift.io/cluster: build07 ci.openshift.io/generator: prowgen pj-rehearse.openshift.io/can-be-rehearsed: "true" - name: pull-ci-openshift-installer-main-e2e-gcd + name: pull-ci-openshift-installer-main-e2e-gcd-techpreview optional: true - rerun_command: /test e2e-gcd + rerun_command: /test e2e-gcd-techpreview spec: containers: - args: @@ -5836,7 +5836,7 @@ presubmits: - --lease-server-credentials-file=/etc/boskos/credentials - --report-credentials-file=/etc/report/credentials - --secret-dir=/secrets/ci-pull-credentials - - --target=e2e-gcd + - --target=e2e-gcd-techpreview command: - ci-operator env: @@ -5892,7 +5892,7 @@ presubmits: - name: result-aggregator secret: secretName: result-aggregator - trigger: (?m)^/test( | .* )e2e-gcd,?($|\s.*) + trigger: (?m)^/test( | .* )e2e-gcd-techpreview,?($|\s.*) - agent: kubernetes always_run: false branches: diff --git a/ci-operator/step-registry/ipi/conf/gcd/OWNERS b/ci-operator/step-registry/ipi/conf/gcd/OWNERS index 720f096f6c037..d93971ab2936d 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/OWNERS +++ b/ci-operator/step-registry/ipi/conf/gcd/OWNERS @@ -1,4 +1,5 @@ approvers: +- barbacbd - patrickdillon - rochacbruno - tthvo diff --git a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json index ceab6c8856948..acc7086049d1e 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json +++ b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.metadata.json @@ -2,6 +2,7 @@ "path": "ipi/conf/gcd/ipi-conf-gcd-chain.yaml", "owners": { "approvers": [ + "barbacbd", "patrickdillon", "rochacbruno", "tthvo" diff --git a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml index d184cdc57b50a..acfc88127dda7 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml +++ b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml @@ -9,5 +9,5 @@ chain: - ref: ipi-install-monitoringpvc documentation: >- This chain generates an install-config.yaml configured to run clusters - on Google Cloud Dedicated (GCD). Sets up WIF authentication before - configuring GCP-specific install-config fields. + on Google Cloud Dedicated (GCD). Validates the WIF credential config + before configuring GCP-specific install-config fields. diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS index 720f096f6c037..d93971ab2936d 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/OWNERS @@ -1,4 +1,5 @@ approvers: +- barbacbd - patrickdillon - rochacbruno - tthvo diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh index 453ef94baca77..968faec5498a8 100755 --- a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh @@ -2,9 +2,6 @@ set -euo pipefail -export AWS_CONFIG_FILE="${AWS_CONFIG_FILE:-/var/run/secrets/aws/config/config}" -export AWS_PROFILE="${AWS_PROFILE:-hub}" - export GOOGLE_CLOUD_UNIVERSE_DOMAIN="${GOOGLE_CLOUD_UNIVERSE_DOMAIN:-apis-berlin-build0.goog}" CRED_FILE="${CLUSTER_PROFILE_DIR}/gce.json" @@ -13,8 +10,12 @@ if [[ ! -f "${CRED_FILE}" ]]; then exit 1 fi -echo "GCD WIF authentication configured" -echo " AWS_CONFIG_FILE=${AWS_CONFIG_FILE}" -echo " AWS_PROFILE=${AWS_PROFILE}" +CRED_TYPE=$(jq -r .type "${CRED_FILE}") +if [[ "${CRED_TYPE}" != "external_account" ]]; then + echo "ERROR: Expected external_account credential type, got ${CRED_TYPE}" + exit 1 +fi + +echo "GCD WIF configuration validated" echo " GOOGLE_CLOUD_UNIVERSE_DOMAIN=${GOOGLE_CLOUD_UNIVERSE_DOMAIN}" -echo " Credential config: ${CRED_FILE}" +echo " Credential type: ${CRED_TYPE}" diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json index c48b533abcef5..8164c0db98284 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.metadata.json @@ -2,6 +2,7 @@ "path": "ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml", "owners": { "approvers": [ + "barbacbd", "patrickdillon", "rochacbruno", "tthvo" diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml index 13bd16e7000a2..fda8fa335eae5 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml @@ -10,21 +10,10 @@ ref: cpu: 10m memory: 100Mi env: - - name: AWS_CONFIG_FILE - default: "/var/run/secrets/aws/config/config" - documentation: |- - Path to the AWS config file injected by ci-ops. Contains the - identity chain profiles used by GCD WIF for authentication. - - name: AWS_PROFILE - default: "hub" - documentation: |- - The AWS profile to use for GCD WIF authentication. Must be "hub" - because GCD WIF trusts only the hub account (320297955214). - name: GOOGLE_CLOUD_UNIVERSE_DOMAIN default: "apis-berlin-build0.goog" documentation: |- The universe domain for Google Cloud Dedicated. documentation: |- - Sets up Workload Identity Federation authentication for Google Cloud - Dedicated (GCD). Configures the AWS identity chain that GCD's WIF pool - trusts, and authenticates gcloud with the WIF credential config. + Validates the GCD WIF credential configuration and sets environment + variables required for Google Cloud Dedicated authentication. diff --git a/ci-operator/step-registry/ipi/gcd/OWNERS b/ci-operator/step-registry/ipi/gcd/OWNERS index 720f096f6c037..d93971ab2936d 100644 --- a/ci-operator/step-registry/ipi/gcd/OWNERS +++ b/ci-operator/step-registry/ipi/gcd/OWNERS @@ -1,4 +1,5 @@ approvers: +- barbacbd - patrickdillon - rochacbruno - tthvo diff --git a/ci-operator/step-registry/ipi/gcd/pre/OWNERS b/ci-operator/step-registry/ipi/gcd/pre/OWNERS index 720f096f6c037..d93971ab2936d 100644 --- a/ci-operator/step-registry/ipi/gcd/pre/OWNERS +++ b/ci-operator/step-registry/ipi/gcd/pre/OWNERS @@ -1,4 +1,5 @@ approvers: +- barbacbd - patrickdillon - rochacbruno - tthvo diff --git a/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json index 0ab9b7c86121d..ed396ccfe791e 100644 --- a/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json +++ b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.metadata.json @@ -2,6 +2,7 @@ "path": "ipi/gcd/pre/ipi-gcd-pre-chain.yaml", "owners": { "approvers": [ + "barbacbd", "patrickdillon", "rochacbruno", "tthvo" diff --git a/ci-operator/step-registry/openshift/e2e/gcd/OWNERS b/ci-operator/step-registry/openshift/e2e/gcd/OWNERS index 720f096f6c037..d93971ab2936d 100644 --- a/ci-operator/step-registry/openshift/e2e/gcd/OWNERS +++ b/ci-operator/step-registry/openshift/e2e/gcd/OWNERS @@ -1,4 +1,5 @@ approvers: +- barbacbd - patrickdillon - rochacbruno - tthvo diff --git a/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json index c07540edf3658..093a7d2826c14 100644 --- a/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json +++ b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.metadata.json @@ -2,6 +2,7 @@ "path": "openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml", "owners": { "approvers": [ + "barbacbd", "patrickdillon", "rochacbruno", "tthvo" From 1aa9968d8cb0a28d7b789ec93fdfd70d3b45d16e Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Tue, 30 Jun 2026 11:05:53 +0100 Subject: [PATCH 06/11] Add WIF external_account support to GCP install/deprovision/gather steps The GCD cluster profile uses a WIF credential config (type external_account) instead of a service account key. Update shared GCP scripts to detect the credential type and handle both: - ipi-conf-gcp-zones: use gcloud auth login --cred-file for WIF, read project ID from cluster profile instead of gce.json - ipi-install-install: set GOOGLE_APPLICATION_CREDENTIALS for WIF - ipi-deprovision-deprovision: same as install - gather-gcp-console: use gcloud auth login --cred-file for WIF Also restore AWS_PROFILE=hub in the CI config - GCD WIF trusts only the hub account, not the default target account. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../installer/openshift-installer-main.yaml | 1 + .../gcp-console/gather-gcp-console-commands.sh | 6 +++++- .../gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml | 6 ++++++ .../gcp/zones/ipi-conf-gcp-zones-commands.sh | 17 ++++++++++++----- .../ipi-deprovision-deprovision-commands.sh | 5 ++++- .../install/ipi-install-install-commands.sh | 5 ++++- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/ci-operator/config/openshift/installer/openshift-installer-main.yaml b/ci-operator/config/openshift/installer/openshift-installer-main.yaml index 60dedeb290d29..586e9679a5fc6 100644 --- a/ci-operator/config/openshift/installer/openshift-installer-main.yaml +++ b/ci-operator/config/openshift/installer/openshift-installer-main.yaml @@ -537,6 +537,7 @@ tests: steps: cluster_profile: gcd env: + AWS_PROFILE: hub COMPUTE_NODE_REPLICAS: "2" FEATURE_SET: TechPreviewNoUpgrade GOOGLE_CLOUD_UNIVERSE_DOMAIN: apis-berlin-build0.goog diff --git a/ci-operator/step-registry/gather/gcp-console/gather-gcp-console-commands.sh b/ci-operator/step-registry/gather/gcp-console/gather-gcp-console-commands.sh index b2b0166415d23..037185db2c0cb 100755 --- a/ci-operator/step-registry/gather/gcp-console/gather-gcp-console-commands.sh +++ b/ci-operator/step-registry/gather/gcp-console/gather-gcp-console-commands.sh @@ -7,7 +7,11 @@ set -o pipefail trap 'CHILDREN=$(jobs -p); if test -n "${CHILDREN}"; then kill ${CHILDREN} && wait; fi' TERM export GOOGLE_CLOUD_KEYFILE_JSON="${CLUSTER_PROFILE_DIR}/gce.json" -gcloud auth activate-service-account --key-file="${GOOGLE_CLOUD_KEYFILE_JSON}" +if [[ "$(jq -r .type ${GOOGLE_CLOUD_KEYFILE_JSON} 2>/dev/null)" == "external_account" ]]; then + gcloud auth login --cred-file="${GOOGLE_CLOUD_KEYFILE_JSON}" --quiet +else + gcloud auth activate-service-account --key-file="${GOOGLE_CLOUD_KEYFILE_JSON}" +fi if test ! -f "${SHARED_DIR}/metadata.json" then diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml index fda8fa335eae5..a0c5b05e6f72c 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-ref.yaml @@ -10,6 +10,12 @@ ref: cpu: 10m memory: 100Mi env: + - name: AWS_PROFILE + default: "hub" + documentation: |- + The AWS profile to use for GCD WIF authentication. Must be "hub" + because GCD WIF trusts only the hub account. The default profile + points to a different target account and will fail the STS exchange. - name: GOOGLE_CLOUD_UNIVERSE_DOMAIN default: "apis-berlin-build0.goog" documentation: |- diff --git a/ci-operator/step-registry/ipi/conf/gcp/zones/ipi-conf-gcp-zones-commands.sh b/ci-operator/step-registry/ipi/conf/gcp/zones/ipi-conf-gcp-zones-commands.sh index be4b9490ea5b0..8ff5b80587970 100755 --- a/ci-operator/step-registry/ipi/conf/gcp/zones/ipi-conf-gcp-zones-commands.sh +++ b/ci-operator/step-registry/ipi/conf/gcp/zones/ipi-conf-gcp-zones-commands.sh @@ -107,12 +107,19 @@ function array_intersection_or_fallback() { } export GCP_SHARED_CREDENTIALS_FILE="${CLUSTER_PROFILE_DIR}/gce.json" -GOOGLE_PROJECT_ID=$(jq -r .project_id ${GCP_SHARED_CREDENTIALS_FILE}) -sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) -if ! gcloud auth list | grep -E "\*\s+${sa_email}" -then - gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" +CRED_TYPE=$(jq -r .type "${GCP_SHARED_CREDENTIALS_FILE}") +if [[ "${CRED_TYPE}" == "external_account" ]]; then + GOOGLE_PROJECT_ID="$(< ${CLUSTER_PROFILE_DIR}/openshift_gcp_project)" + gcloud auth login --cred-file="${GCP_SHARED_CREDENTIALS_FILE}" --quiet gcloud config set project "${GOOGLE_PROJECT_ID}" +else + GOOGLE_PROJECT_ID=$(jq -r .project_id ${GCP_SHARED_CREDENTIALS_FILE}) + sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) + if ! gcloud auth list | grep -E "\*\s+${sa_email}" + then + gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" + gcloud config set project "${GOOGLE_PROJECT_ID}" + fi fi # As a temporary workaround of https://redhat.atlassian.net/browse/OCPBUGS-78431, diff --git a/ci-operator/step-registry/ipi/deprovision/deprovision/ipi-deprovision-deprovision-commands.sh b/ci-operator/step-registry/ipi/deprovision/deprovision/ipi-deprovision-deprovision-commands.sh index 805e30ed19ccd..1ded09cc215a1 100755 --- a/ci-operator/step-registry/ipi/deprovision/deprovision/ipi-deprovision-deprovision-commands.sh +++ b/ci-operator/step-registry/ipi/deprovision/deprovision/ipi-deprovision-deprovision-commands.sh @@ -48,7 +48,10 @@ fi export AZURE_AUTH_LOCATION=$CLUSTER_PROFILE_DIR/osServicePrincipal.json export GOOGLE_CLOUD_KEYFILE_JSON=$CLUSTER_PROFILE_DIR/gce.json -if [ -f "${SHARED_DIR}/gcp_min_permissions.json" ]; then +if [[ "$(jq -r .type ${GOOGLE_CLOUD_KEYFILE_JSON} 2>/dev/null)" == "external_account" ]]; then + echo "$(date -u --rfc-3339=seconds) - Using WIF external_account credentials for GCD..." + export GOOGLE_APPLICATION_CREDENTIALS="${GOOGLE_CLOUD_KEYFILE_JSON}" +elif [ -f "${SHARED_DIR}/gcp_min_permissions.json" ]; then echo "$(date -u --rfc-3339=seconds) - Using the IAM service account for the minimum permissions testing on GCP..." export GOOGLE_CLOUD_KEYFILE_JSON="${SHARED_DIR}/gcp_min_permissions.json" elif [ -f "${SHARED_DIR}/user_tags_sa.json" ]; then diff --git a/ci-operator/step-registry/ipi/install/install/ipi-install-install-commands.sh b/ci-operator/step-registry/ipi/install/install/ipi-install-install-commands.sh index 59efc308a6983..646525ad2283b 100755 --- a/ci-operator/step-registry/ipi/install/install/ipi-install-install-commands.sh +++ b/ci-operator/step-registry/ipi/install/install/ipi-install-install-commands.sh @@ -681,7 +681,10 @@ azurestack) ;; gcp) export GOOGLE_CLOUD_KEYFILE_JSON=${CLUSTER_PROFILE_DIR}/gce.json - if [ -f "${SHARED_DIR}/gcp_min_permissions.json" ]; then + if [[ "$(jq -r .type ${GOOGLE_CLOUD_KEYFILE_JSON} 2>/dev/null)" == "external_account" ]]; then + echo "$(date -u --rfc-3339=seconds) - Using WIF external_account credentials for GCD..." + export GOOGLE_APPLICATION_CREDENTIALS="${GOOGLE_CLOUD_KEYFILE_JSON}" + elif [ -f "${SHARED_DIR}/gcp_min_permissions.json" ]; then echo "$(date -u --rfc-3339=seconds) - Using the IAM service account for the minimum permissions testing on GCP..." export GOOGLE_CLOUD_KEYFILE_JSON="${SHARED_DIR}/gcp_min_permissions.json" elif [ -f "${SHARED_DIR}/user_tags_sa.json" ]; then From 03d65cd9f009b7a72f52313d4287baba1363b2e7 Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Tue, 30 Jun 2026 11:10:33 +0100 Subject: [PATCH 07/11] Handle malformed gce.json in WIF auth validation Wrap jq parsing in an explicit check so invalid JSON produces a clear error message instead of a raw parser failure. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh index 968faec5498a8..ebb71ca549063 100755 --- a/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh +++ b/ci-operator/step-registry/ipi/conf/gcd/wif-auth/ipi-conf-gcd-wif-auth-commands.sh @@ -10,7 +10,10 @@ if [[ ! -f "${CRED_FILE}" ]]; then exit 1 fi -CRED_TYPE=$(jq -r .type "${CRED_FILE}") +if ! CRED_TYPE=$(jq -er '.type' "${CRED_FILE}" 2>/dev/null); then + echo "ERROR: Invalid WIF credential config at ${CRED_FILE}" + exit 1 +fi if [[ "${CRED_TYPE}" != "external_account" ]]; then echo "ERROR: Expected external_account credential type, got ${CRED_TYPE}" exit 1 From 85548ddf9b33b319ffc95911a37cbfba0a7a40c6 Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Tue, 30 Jun 2026 11:55:41 +0100 Subject: [PATCH 08/11] Add BASE_DOMAIN for GCD installs Set BASE_DOMAIN to ci.gcd.devcluster.openshift.com for internal DNS records. The public_hosted_zone file must also be added to the vault secret with the same value. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../config/openshift/installer/openshift-installer-main.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-operator/config/openshift/installer/openshift-installer-main.yaml b/ci-operator/config/openshift/installer/openshift-installer-main.yaml index 586e9679a5fc6..cf9076b2abf87 100644 --- a/ci-operator/config/openshift/installer/openshift-installer-main.yaml +++ b/ci-operator/config/openshift/installer/openshift-installer-main.yaml @@ -538,6 +538,7 @@ tests: cluster_profile: gcd env: AWS_PROFILE: hub + BASE_DOMAIN: ci.gcd.devcluster.openshift.com COMPUTE_NODE_REPLICAS: "2" FEATURE_SET: TechPreviewNoUpgrade GOOGLE_CLOUD_UNIVERSE_DOMAIN: apis-berlin-build0.goog From 3cf97be98bf11cc2a8aebddde3d69149efdd1f11 Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Wed, 1 Jul 2026 20:46:28 +0100 Subject: [PATCH 09/11] Add private cluster infra and WIF support to VPC/bastion steps For private GCD clusters, add VPC provisioning, bastion host, and proxy to the pre-install chain, with teardown in post steps. Based on tthvo's reference commit. - Add WIF external_account auth to gcp-provision-vpc, gcp-deprovision-vpc, gcp-provision-bastionhost, gcp-deprovision-bastionhost scripts - Make bastion machine type and image configurable via env vars (BASTION_MACHINE_TYPE, BASTION_IMAGE_NAME, BASTION_IMAGE_PROJECT) - Update ipi-gcd-pre chain with VPC, bastion, and proxy steps - Update openshift-e2e-gcd workflow with bastion and VPC teardown - Restore AWS_PROFILE: hub in CI config (required for GCD WIF) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../gcp-deprovision-bastionhost-commands.sh | 14 +++++++++---- .../vpc/gcp-deprovision-vpc-commands.sh | 14 +++++++++---- .../gcp-provision-bastionhost-commands.sh | 20 ++++++++++++------- .../gcp-provision-bastionhost-ref.yaml | 15 ++++++++++++++ .../vpc/gcp-provision-vpc-commands.sh | 14 +++++++++---- .../ipi/gcd/pre/ipi-gcd-pre-chain.yaml | 9 +++++++-- .../e2e/gcd/openshift-e2e-gcd-workflow.yaml | 5 ++++- 7 files changed, 69 insertions(+), 22 deletions(-) diff --git a/ci-operator/step-registry/gcp/deprovision/bastionhost/gcp-deprovision-bastionhost-commands.sh b/ci-operator/step-registry/gcp/deprovision/bastionhost/gcp-deprovision-bastionhost-commands.sh index 5fb75dab2f4a8..cc4e33a3dbffd 100755 --- a/ci-operator/step-registry/gcp/deprovision/bastionhost/gcp-deprovision-bastionhost-commands.sh +++ b/ci-operator/step-registry/gcp/deprovision/bastionhost/gcp-deprovision-bastionhost-commands.sh @@ -25,11 +25,17 @@ if [[ "${OSD_QE_PROJECT_AS_SERVICE_PROJECT}" == "yes" ]]; then else GOOGLE_PROJECT_ID="$(< ${CLUSTER_PROFILE_DIR}/openshift_gcp_project)" export GCP_SHARED_CREDENTIALS_FILE="${CLUSTER_PROFILE_DIR}/gce.json" - sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) - if ! gcloud auth list | grep -E "\*\s+${sa_email}" - then - gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" + CRED_TYPE=$(jq -r .type "${GCP_SHARED_CREDENTIALS_FILE}" 2>/dev/null) + if [[ "${CRED_TYPE}" == "external_account" ]]; then + gcloud auth login --cred-file="${GCP_SHARED_CREDENTIALS_FILE}" --quiet gcloud config set project "${GOOGLE_PROJECT_ID}" + else + sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) + if ! gcloud auth list | grep -E "\*\s+${sa_email}" + then + gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" + gcloud config set project "${GOOGLE_PROJECT_ID}" + fi fi fi diff --git a/ci-operator/step-registry/gcp/deprovision/vpc/gcp-deprovision-vpc-commands.sh b/ci-operator/step-registry/gcp/deprovision/vpc/gcp-deprovision-vpc-commands.sh index c35724101d4f3..c36252bb15f19 100755 --- a/ci-operator/step-registry/gcp/deprovision/vpc/gcp-deprovision-vpc-commands.sh +++ b/ci-operator/step-registry/gcp/deprovision/vpc/gcp-deprovision-vpc-commands.sh @@ -14,11 +14,17 @@ fi GOOGLE_PROJECT_ID="$(< ${CLUSTER_PROFILE_DIR}/openshift_gcp_project)" export GCP_SHARED_CREDENTIALS_FILE="${CLUSTER_PROFILE_DIR}/gce.json" -sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) -if ! gcloud auth list | grep -E "\*\s+${sa_email}" -then - gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" +CRED_TYPE=$(jq -r .type "${GCP_SHARED_CREDENTIALS_FILE}" 2>/dev/null) +if [[ "${CRED_TYPE}" == "external_account" ]]; then + gcloud auth login --cred-file="${GCP_SHARED_CREDENTIALS_FILE}" --quiet gcloud config set project "${GOOGLE_PROJECT_ID}" +else + sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) + if ! gcloud auth list | grep -E "\*\s+${sa_email}" + then + gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" + gcloud config set project "${GOOGLE_PROJECT_ID}" + fi fi ## Destroy the VPC diff --git a/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-commands.sh b/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-commands.sh index 6ca6d724d3cf9..653fbed5006d4 100755 --- a/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-commands.sh +++ b/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-commands.sh @@ -65,8 +65,8 @@ workdir=`mktemp -d` # Generally we do not update boot image for bastion host very often, we just use it as a jump # host, mirror registry, and proxy server, these services do not have frequent update. # So hard-code them here. -IMAGE_NAME="fedora-coreos-41-20241122-3-0-gcp-x86-64" -IMAGE_PROJECT="fedora-coreos-cloud" +IMAGE_NAME="${BASTION_IMAGE_NAME:-fedora-coreos-41-20241122-3-0-gcp-x86-64}" +IMAGE_PROJECT="${BASTION_IMAGE_PROJECT:-fedora-coreos-cloud}" echo "Using ${IMAGE_NAME} image from ${IMAGE_PROJECT} project" ##################################### @@ -88,11 +88,17 @@ if [[ "${OSD_QE_PROJECT_AS_SERVICE_PROJECT}" == "yes" ]]; then else GOOGLE_PROJECT_ID="$(< ${CLUSTER_PROFILE_DIR}/openshift_gcp_project)" export GCP_SHARED_CREDENTIALS_FILE="${CLUSTER_PROFILE_DIR}/gce.json" - sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) - if ! gcloud auth list | grep -E "\*\s+${sa_email}" - then - gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" + CRED_TYPE=$(jq -r .type "${GCP_SHARED_CREDENTIALS_FILE}" 2>/dev/null) + if [[ "${CRED_TYPE}" == "external_account" ]]; then + gcloud auth login --cred-file="${GCP_SHARED_CREDENTIALS_FILE}" --quiet gcloud config set project "${GOOGLE_PROJECT_ID}" + else + sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) + if ! gcloud auth list | grep -E "\*\s+${sa_email}" + then + gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" + gcloud config set project "${GOOGLE_PROJECT_ID}" + fi fi fi @@ -100,7 +106,7 @@ REGION="${LEASED_RESOURCE}" echo "Using region: ${REGION}" ZONE_0=$(gcloud compute regions describe ${REGION} --format=json | jq -r .zones[0] | cut -d "/" -f9) -MACHINE_TYPE="n2-standard-2" +MACHINE_TYPE="${BASTION_MACHINE_TYPE:-n2-standard-2}" ##################################### ##########Create Bastion############# diff --git a/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-ref.yaml b/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-ref.yaml index adb96b6673aba..3c8d03fe35624 100644 --- a/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-ref.yaml +++ b/ci-operator/step-registry/gcp/provision/bastionhost/gcp-provision-bastionhost-ref.yaml @@ -29,5 +29,20 @@ ref: - name: OSD_QE_PROJECT_AS_SERVICE_PROJECT default: "no" documentation: Whether to use OSD QE's project as the service project. The supported values are [no, yes]. + - name: BASTION_MACHINE_TYPE + default: "" + documentation: |- + The GCP machine type for the bastion host. If empty, defaults to + n2-standard-2. + - name: BASTION_IMAGE_NAME + default: "" + documentation: |- + The GCP image name for the bastion host. If empty, defaults to a + Fedora CoreOS image. + - name: BASTION_IMAGE_PROJECT + default: "" + documentation: |- + The GCP project hosting the bastion image. If empty, defaults to + fedora-coreos-cloud. documentation: |- The step launches Linux bastion host within the CONTROL_PLANE_SUBNET. diff --git a/ci-operator/step-registry/gcp/provision/vpc/gcp-provision-vpc-commands.sh b/ci-operator/step-registry/gcp/provision/vpc/gcp-provision-vpc-commands.sh index fdbee1363f70d..4ee38c4155ea0 100755 --- a/ci-operator/step-registry/gcp/provision/vpc/gcp-provision-vpc-commands.sh +++ b/ci-operator/step-registry/gcp/provision/vpc/gcp-provision-vpc-commands.sh @@ -73,11 +73,17 @@ EOF GOOGLE_PROJECT_ID="$(< ${CLUSTER_PROFILE_DIR}/openshift_gcp_project)" export GCP_SHARED_CREDENTIALS_FILE="${CLUSTER_PROFILE_DIR}/gce.json" -sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) -if ! gcloud auth list | grep -E "\*\s+${sa_email}" -then - gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" +CRED_TYPE=$(jq -r .type "${GCP_SHARED_CREDENTIALS_FILE}" 2>/dev/null) +if [[ "${CRED_TYPE}" == "external_account" ]]; then + gcloud auth login --cred-file="${GCP_SHARED_CREDENTIALS_FILE}" --quiet gcloud config set project "${GOOGLE_PROJECT_ID}" +else + sa_email=$(jq -r .client_email ${GCP_SHARED_CREDENTIALS_FILE}) + if ! gcloud auth list | grep -E "\*\s+${sa_email}" + then + gcloud auth activate-service-account --key-file="${GCP_SHARED_CREDENTIALS_FILE}" + gcloud config set project "${GOOGLE_PROJECT_ID}" + fi fi echo "$(date -u --rfc-3339=seconds) - Copying resource files from lib dir..." diff --git a/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml index 56ee158107d3d..b863316f3d2f1 100644 --- a/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml +++ b/ci-operator/step-registry/ipi/gcd/pre/ipi-gcd-pre-chain.yaml @@ -1,9 +1,14 @@ chain: as: ipi-gcd-pre steps: + - ref: gcp-provision-vpc + - ref: ignition-bastionhost + - ref: gcp-provision-bastionhost + - ref: proxy-config-generate - chain: ipi-conf-gcd - ref: rhcos-conf-osstream - chain: ipi-install documentation: |- - The IPI GCD setup chain provisions an OpenShift cluster with a default - configuration on Google Cloud Dedicated using WIF authentication. + The IPI GCD setup chain provisions a VPC, bastion host, and proxy, + then installs a private OpenShift cluster on Google Cloud Dedicated + using WIF authentication. diff --git a/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml index d93739c82345a..d1d96048921bc 100644 --- a/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml +++ b/ci-operator/step-registry/openshift/e2e/gcd/openshift-e2e-gcd-workflow.yaml @@ -9,6 +9,9 @@ workflow: post: - chain: gather-core-dump - chain: ipi-gcp-post + - ref: gcp-deprovision-bastionhost + - ref: gcp-deprovision-vpc documentation: |- The OpenShift E2E GCD workflow executes the common end-to-end test - suite on Google Cloud Dedicated with WIF authentication. + suite on a private cluster on Google Cloud Dedicated with WIF + authentication. From cb78111fe28d9f90b7cf7fde90df71f3512e1be8 Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Wed, 1 Jul 2026 20:49:13 +0100 Subject: [PATCH 10/11] Add rhcos10 OS image for GCD installs Add ipi-conf-gcp-osimage step to the GCD chain and set DEFAULT_MACHINE_OSIMAGE to rhcos10, which is the RHCOS image published to GCD. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../config/openshift/installer/openshift-installer-main.yaml | 1 + ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/ci-operator/config/openshift/installer/openshift-installer-main.yaml b/ci-operator/config/openshift/installer/openshift-installer-main.yaml index cf9076b2abf87..578965d7eada1 100644 --- a/ci-operator/config/openshift/installer/openshift-installer-main.yaml +++ b/ci-operator/config/openshift/installer/openshift-installer-main.yaml @@ -540,6 +540,7 @@ tests: AWS_PROFILE: hub BASE_DOMAIN: ci.gcd.devcluster.openshift.com COMPUTE_NODE_REPLICAS: "2" + DEFAULT_MACHINE_OSIMAGE: rhcos10 FEATURE_SET: TechPreviewNoUpgrade GOOGLE_CLOUD_UNIVERSE_DOMAIN: apis-berlin-build0.goog PUBLISH: Internal diff --git a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml index acfc88127dda7..7cec3138e6d7f 100644 --- a/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml +++ b/ci-operator/step-registry/ipi/conf/gcd/ipi-conf-gcd-chain.yaml @@ -5,6 +5,7 @@ chain: - ref: ipi-conf-telemetry - ref: ipi-conf-gcd-wif-auth - ref: ipi-conf-gcp + - ref: ipi-conf-gcp-osimage - ref: ipi-conf-gcp-zones - ref: ipi-install-monitoringpvc documentation: >- From ab921e61499d936236b2bf5e156db1f69f28b7df Mon Sep 17 00:00:00 2001 From: Bruno Cesar Rocha Date: Thu, 2 Jul 2026 20:37:07 +0100 Subject: [PATCH 11/11] Add README for GCD CI configuration Document the WIF authentication flow, cluster profile secret format, credential config generation, environment variables, and troubleshooting guide. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../step-registry/ipi/conf/gcd/README.md | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 ci-operator/step-registry/ipi/conf/gcd/README.md diff --git a/ci-operator/step-registry/ipi/conf/gcd/README.md b/ci-operator/step-registry/ipi/conf/gcd/README.md new file mode 100644 index 0000000000000..12f6e72509e36 --- /dev/null +++ b/ci-operator/step-registry/ipi/conf/gcd/README.md @@ -0,0 +1,150 @@ +# Google Cloud Dedicated (GCD) CI Configuration + +This directory contains step-registry components for running OpenShift +installer e2e tests on Google Cloud Dedicated. + +## Prerequisites + +1. A GCD project with a Workload Identity Federation (WIF) pool configured + to trust the CI build cluster's AWS account via STS role chaining. +2. A GCD service account with installer-required IAM roles (compute, DNS, + storage, IAM, etc.). +3. The WIF pool must have a provider with an attribute condition that + matches the CI pod's AWS identity. +4. The DPTP team must add the `home_role_arn` to the build cluster's + `aws-sts-cluster-config` secret so that STS is activated for the + `gcd` cluster profile. + +## Authentication Flow + +GCD CI jobs use AWS STS role chaining to authenticate: + +``` +CI pod (build cluster) + -> AWS STS token (projected SA token) + -> home role (build cluster AWS account) + -> hub role (shared hub AWS account, trusted by GCD WIF) + -> GCD STS exchanges AWS credentials for GCD access token + -> impersonates GCD service account +``` + +ci-operator automatically injects the AWS config file and STS token when +the cluster profile secret contains `home_role_arn`, `hub_role_arn`, and +`target_role_arn`. + +The job must set `AWS_PROFILE=hub` because GCD WIF trusts only the hub +account. The `default` profile points to a different target account. + +## Cluster Profile Secret (`cluster-secrets-gcd`) + +The secret is stored in the CI vault at +`selfservice.vault.ci.openshift.org` and must contain: + +| Key | Description | +|-----|-------------| +| `gce.json` | WIF credential config (see format below) | +| `openshift_gcp_project` | GCD project ID with prefix, e.g. `eu0:openshift` | +| `public_hosted_zone` | Base domain for DNS records | +| `ssh-publickey` | SSH public key for node access | +| `ssh-privatekey` | SSH private key for node access | +| `home_role_arn` | ARN of the home IAM role on the build cluster account | +| `hub_role_arn` | ARN of the hub IAM role (trusted by GCD WIF) | +| `target_role_arn` | ARN of the target IAM role | + +The vault secret must also have these metadata keys for sync: +``` +secretsync/target-namespace: ci +secretsync/target-name: cluster-secrets-gcd +``` + +## WIF Credential Config Format (`gce.json`) + +The credential config is an `external_account` type JSON that tells the +Google SDK how to exchange AWS credentials for GCD tokens: + +```json +{ + "universe_domain": "apis-berlin-build0.goog", + "type": "external_account", + "audience": "//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID", + "subject_token_type": "urn:ietf:params:aws:token-type:aws4_request", + "token_url": "https://sts.apis-berlin-build0.goog/v1/token", + "credential_source": { + "environment_id": "aws1", + "region_url": "http://169.254.169.254/latest/meta-data/placement/availability-zone", + "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials", + "regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15" + }, + "service_account_impersonation_url": "https://iamcredentials.apis-berlin-build0.goog/v1/projects/-/serviceAccounts/SA_EMAIL:generateAccessToken" +} +``` + +Replace `PROJECT_NUMBER`, `POOL_ID`, `PROVIDER_ID`, and `SA_EMAIL` with +actual values from your GCD WIF setup. + +### Generating the credential config + +```bash +export GOOGLE_CLOUD_UNIVERSE_DOMAIN=apis-berlin-build0.goog + +gcloud iam workload-identity-pools create-cred-config \ + "projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID" \ + --service-account=SA_EMAIL \ + --aws \ + --output-file=gce.json +``` + +After generating, verify that the `token_url` and +`service_account_impersonation_url` use `apis-berlin-build0.goog` +endpoints (not `googleapis.com`). The `gcloud` command may default to +public GCP endpoints, and the GCD endpoints must be set manually if so. + +## Environment Variables + +| Variable | Value | Purpose | +|----------|-------|---------| +| `AWS_PROFILE` | `hub` | Select the hub AWS profile trusted by GCD WIF | +| `GOOGLE_CLOUD_UNIVERSE_DOMAIN` | `apis-berlin-build0.goog` | Route API calls to GCD endpoints | +| `FEATURE_SET` | `TechPreviewNoUpgrade` | GCD support is currently TechPreview | +| `PUBLISH` | `Internal` | GCD only supports private DNS zones | +| `DEFAULT_MACHINE_OSIMAGE` | `rhcos10` | RHCOS image published to GCD | + +## Troubleshooting + +### "STS will not be activated" + +``` +STS hub and target role ARNs are set for profile gcd but home_role_arn +was not found in Secret aws-sts-cluster-config +``` + +The DPTP team needs to add the GCD profile's home role ARN to the build +cluster's `aws-sts-cluster-config` secret. Contact them with the ARN +values from the cluster profile secret. + +### "Connection refused" to 169.254.169.254 + +``` +HTTPConnectionPool(host='169.254.169.254', port=80): Max retries exceeded +``` + +The Google SDK is trying to get AWS credentials from the EC2 metadata +service, which means STS was not activated (see above). Once STS is +active, ci-operator injects AWS credentials as environment variables and +the SDK uses those instead of IMDS. + +### "external_account" type validation failure + +The `ipi-conf-gcd-wif-auth` step validates that `gce.json` contains a +valid `external_account` credential config. If this fails, check: +- The file was uploaded to vault correctly (valid JSON) +- The `type` field is `external_account` +- The vault secret has synced (can take up to 30 minutes) + +### gcloud auth succeeds but API calls fail + +If `gcloud auth login --cred-file` reports success but subsequent commands +fail, check: +- `GOOGLE_CLOUD_UNIVERSE_DOMAIN` is set to `apis-berlin-build0.goog` +- The `token_url` in `gce.json` uses `sts.apis-berlin-build0.goog` +- The GCD service account has the required IAM roles