Skip to content

GCP-430: Wire GCP WIF credentials for CNCC in HyperShift HCP mode#2915

Open
apahim wants to merge 1 commit intoopenshift:masterfrom
apahim:cncc
Open

GCP-430: Wire GCP WIF credentials for CNCC in HyperShift HCP mode#2915
apahim wants to merge 1 commit intoopenshift:masterfrom
apahim:cncc

Conversation

@apahim
Copy link
Copy Markdown

@apahim apahim commented Feb 27, 2026

  • Read GCP_CNCC_CREDENTIALS_FILE env var (set by CPO) and set GOOGLE_APPLICATION_CREDENTIALS on the CNCC container so that CNCC's auto-detection (cloud-network-config-controller PR #206) picks up the WIF external_account credential.
  • Add --token-audience=openshift to the cloud-token minter so GCP STS can validate the projected service-account token against the OIDC provider's allowed audience.
  • Add unit tests for template rendering.

Summary by CodeRabbit

  • New Features

    • Added support for conditional Google Cloud Workload Identity credentials in cloud network configuration.
    • Enabled token-audience configuration for OpenShift token minter.
  • Tests

    • Added tests to verify GCP credential injection/omission and path handling.
    • Added tests to verify token-audience is present in the cloud token minter.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Feb 27, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Feb 27, 2026

@apahim: This pull request references GCP-430 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

  • Read GCP_CNCC_CREDENTIALS_FILE env var (set by CPO) and set GOOGLE_APPLICATION_CREDENTIALS on the CNCC container so that CNCC's auto-detection (cloud-network-config-controller PR remove all sriov bits from CNO #206) picks up the WIF external_account credential.
  • Add --token-audience=openshift to the cloud-token minter so GCP STS can validate the projected service-account token against the OIDC provider's allowed audience.
  • Add unit tests for template rendering.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e56981c2-b471-4718-b07a-9fe4a14747a0

📥 Commits

Reviewing files that changed from the base of the PR and between a430fb1 and 4cd79a7.

📒 Files selected for processing (3)
  • bindata/cloud-network-config-controller/managed/controller.yaml
  • pkg/network/cloud_network.go
  • pkg/network/cloud_network_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/network/cloud_network_test.go
  • pkg/network/cloud_network.go

Walkthrough

Adds conditional GCP credentials injection and sets the cloud-token minter's token audience to "openshift"; implements validation and rendering of a GCP credentials filename into HyperShift CNCC, and adds tests verifying these behaviors.

Changes

Cohort / File(s) Summary
Controller manifest
bindata/cloud-network-config-controller/managed/controller.yaml
Added --token-audience=openshift to the cloud-token container args and added a conditional block to set GOOGLE_APPLICATION_CREDENTIALS when GCPCredentialsPath is provided.
GCP credentials handling
pkg/network/cloud_network.go
Reads GCP_CNCC_CREDENTIALS_FILE, validates it is a simple filename, and sets GCPCredentialsPath to /etc/secret/cloudprovider/<filename> for HyperShift CNCC rendering; returns an error for invalid values.
Tests for rendering & token arg
pkg/network/cloud_network_test.go
New unit tests assert GOOGLE_APPLICATION_CREDENTIALS is rendered only when GCPCredentialsPath is set and verify the cloud-token minter container includes --token-audience=openshift.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: wiring GCP WIF credentials for CNCC in HyperShift HCP mode, which aligns with the core modifications across manifest and code files.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Stable And Deterministic Test Names ✅ Passed Test names use standard Go testing package with static, deterministic names containing no dynamic values, timestamps, or UUIDs.
Test Structure And Quality ✅ Passed Tests use standard Go testing with *testing.T, not Ginkgo framework, so Ginkgo-specific check does not apply.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

level=error msg="Running error: context loading failed: failed to load packages: failed to load packages: failed to load with go/packages: err: exit status 1: stderr: go: inconsistent vendoring in :\n\tgithub.com/Masterminds/semver@v1.5.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/Masterminds/sprig/v3@v3.2.3: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/containernetworking/cni@v0.8.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/ghodss/yaml@v1.0.1-0.20190212211648-25d852aebe32: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/go-bindata/go-bindata@v3.1.2+incompatible: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/onsi/gomega@v1.38.1: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tgithub.com/ope

... [truncated 17231 characters] ...

ired in go.mod, but not marked as explicit in vendor/modules.txt\n\tk8s.io/gengo/v2@v2.0.0-20250922181213-ec3ebc5fd46b: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tk8s.io/kms@v0.34.1: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tk8s.io/kube-aggregator@v0.34.1: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tsigs.k8s.io/randfill@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\tsigs.k8s.io/structured-merge-diff/v6@v6.3.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor\n"


Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Feb 27, 2026

@apahim: This pull request references GCP-430 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

  • Read GCP_CNCC_CREDENTIALS_FILE env var (set by CPO) and set GOOGLE_APPLICATION_CREDENTIALS on the CNCC container so that CNCC's auto-detection (cloud-network-config-controller PR remove all sriov bits from CNO #206) picks up the WIF external_account credential.
  • Add --token-audience=openshift to the cloud-token minter so GCP STS can validate the projected service-account token against the OIDC provider's allowed audience.
  • Add unit tests for template rendering.

Summary by CodeRabbit

  • New Features

  • Added support for Google Cloud Platform Workload Identity Federation credentials in cloud network configuration

  • Implemented token audience configuration for OpenShift deployments

  • Tests

  • Added test coverage to verify GCP credentials are properly configured in the cloud network controller

  • Added test coverage to verify token audience is correctly set in the cloud token minter

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot requested review from danwinship and tssurya February 27, 2026 14:18
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Feb 27, 2026

@apahim: This pull request references GCP-430 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

  • Read GCP_CNCC_CREDENTIALS_FILE env var (set by CPO) and set GOOGLE_APPLICATION_CREDENTIALS on the CNCC container so that CNCC's auto-detection (cloud-network-config-controller PR #206) picks up the WIF external_account credential.
  • Add --token-audience=openshift to the cloud-token minter so GCP STS can validate the projected service-account token against the OIDC provider's allowed audience.
  • Add unit tests for template rendering.

Summary by CodeRabbit

  • New Features

  • Added support for Google Cloud Platform Workload Identity Federation credentials in cloud network configuration

  • Implemented token audience configuration for OpenShift deployments

  • Tests

  • Added test coverage to verify GCP credentials are properly configured in the cloud network controller

  • Added test coverage to verify token audience is correctly set in the cloud token minter

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Feb 27, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: apahim
Once this PR has been reviewed and has the lgtm label, please assign pliurh for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@apahim
Copy link
Copy Markdown
Author

apahim commented Feb 27, 2026

/hold

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 27, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/network/cloud_network_test.go (1)

34-66: Extract shared render-data fixture to reduce duplication.

Both tests build nearly identical render.MakeRenderData() payloads. A helper fixture will keep future template-key updates consistent.

Refactor sketch
+func makeManagedControllerRenderData() render.RenderData {
+	data := render.MakeRenderData()
+	data.Data["ReleaseVersion"] = "4.18.0"
+	data.Data["PlatformType"] = "GCP"
+	data.Data["PlatformRegion"] = "us-central1"
+	data.Data["PlatformTypeAWS"] = "AWS"
+	data.Data["PlatformTypeAzure"] = "Azure"
+	data.Data["PlatformTypeGCP"] = "GCP"
+	data.Data["CloudNetworkConfigControllerImage"] = "test-image"
+	data.Data["KubernetesServiceURL"] = "https://localhost:6443"
+	data.Data["ExternalControlPlane"] = true
+	data.Data["PlatformAzureEnvironment"] = ""
+	data.Data["PlatformAWSCAPath"] = ""
+	data.Data["PlatformAPIURL"] = ""
+	data.Data["CLIImage"] = "cli-image"
+	data.Data["TokenMinterImage"] = "token-minter-image"
+	data.Data["TokenAudience"] = "https://issuer.example.com"
+	data.Data["ManagementClusterName"] = "test-cluster"
+	data.Data["HostedClusterNamespace"] = "test-ns"
+	data.Data["ReleaseImage"] = "release-image"
+	data.Data["HCPNodeSelector"] = map[string]string{}
+	data.Data["HCPLabels"] = map[string]string{}
+	data.Data["HCPTolerations"] = []string{}
+	data.Data["RunAsUser"] = ""
+	data.Data["PriorityClass"] = ""
+	data.Data["HTTP_PROXY"] = ""
+	data.Data["HTTPS_PROXY"] = ""
+	data.Data["NO_PROXY"] = ""
+	data.Data["AzureManagedCertDirectory"] = ""
+	data.Data["AzureManagedCredsPath"] = ""
+	data.Data["AzureManagedSecretProviderClass"] = ""
+	return data
+}

Also applies to: 106-137

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/network/cloud_network_test.go` around lines 34 - 66, The test duplicated
a large render.MakeRenderData() payload in cloud_network_test.go (the blocks
starting at the shown diff and again at lines ~106-137); refactor by extracting
a shared helper (e.g., newTestRenderData or makeRenderDataFixture) that returns
render.MakeRenderData() with all required keys set (ReleaseVersion,
PlatformType, PlatformRegion, PlatformTypeAWS/Azure/GCP,
CloudNetworkConfigControllerImage, KubernetesServiceURL, ExternalControlPlane,
PlatformAzureEnvironment, PlatformAWSCAPath, PlatformAPIURL, CLIImage,
TokenMinterImage, TokenAudience, ManagementClusterName, HostedClusterNamespace,
ReleaseImage, HCPNodeSelector, HCPLabels, HCPTolerations, RunAsUser,
PriorityClass, HTTP_PROXY, HTTPS_PROXY, NO_PROXY, AzureManagedCertDirectory,
AzureManagedCredsPath, AzureManagedSecretProviderClass, GCPCredentialsPath) and
have both tests call that helper (passing tc.gcpCredentialsPath when needed) to
remove duplication and keep future template-key updates in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/network/cloud_network.go`:
- Around line 113-117: Validate and constrain the GCP_CNCC_CREDENTIALS_FILE
value to a filename before joining: read it via os.Getenv into gcpCredsFile,
compute base := filepath.Base(gcpCredsFile) and only use
filepath.Join("/etc/secret/cloudprovider", base) when base equals the original
gcpCredsFile and base is non-empty (otherwise treat it as invalid and set
data.Data["GCPCredentialsPath"] = "" or handle error); update the assignment to
data.Data["GCPCredentialsPath"] accordingly so absolute paths or values with
directories cannot escape the intended directory.

---

Nitpick comments:
In `@pkg/network/cloud_network_test.go`:
- Around line 34-66: The test duplicated a large render.MakeRenderData() payload
in cloud_network_test.go (the blocks starting at the shown diff and again at
lines ~106-137); refactor by extracting a shared helper (e.g., newTestRenderData
or makeRenderDataFixture) that returns render.MakeRenderData() with all required
keys set (ReleaseVersion, PlatformType, PlatformRegion,
PlatformTypeAWS/Azure/GCP, CloudNetworkConfigControllerImage,
KubernetesServiceURL, ExternalControlPlane, PlatformAzureEnvironment,
PlatformAWSCAPath, PlatformAPIURL, CLIImage, TokenMinterImage, TokenAudience,
ManagementClusterName, HostedClusterNamespace, ReleaseImage, HCPNodeSelector,
HCPLabels, HCPTolerations, RunAsUser, PriorityClass, HTTP_PROXY, HTTPS_PROXY,
NO_PROXY, AzureManagedCertDirectory, AzureManagedCredsPath,
AzureManagedSecretProviderClass, GCPCredentialsPath) and have both tests call
that helper (passing tc.gcpCredentialsPath when needed) to remove duplication
and keep future template-key updates in one place.

ℹ️ Review info

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1c1a097 and a430fb1.

📒 Files selected for processing (3)
  • bindata/cloud-network-config-controller/managed/controller.yaml
  • pkg/network/cloud_network.go
  • pkg/network/cloud_network_test.go

Comment thread pkg/network/cloud_network.go
@apahim apahim marked this pull request as draft February 27, 2026 14:44
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Feb 27, 2026
Comment thread pkg/network/cloud_network.go
Comment thread pkg/network/cloud_network_test.go Outdated
Comment thread pkg/network/cloud_network_test.go Outdated
- Read GCP_CNCC_CREDENTIALS_FILE env var (set by the Control Plane
  Operator via the HyperShift PR #7824) and set
  GOOGLE_APPLICATION_CREDENTIALS on the CNCC container so that
  CNCC's auto-detection (cloud-network-config-controller PR openshift#206)
  picks up the WIF external_account credential.
- Validate GCP_CNCC_CREDENTIALS_FILE is a plain filename to prevent
  path traversal.
- Add --token-audience=openshift to the cloud-token minter so GCP
  STS can validate the projected service-account token against the
  OIDC provider's allowed audience.
- Add unit tests for template rendering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Mar 11, 2026

@apahim: This pull request references GCP-430 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

  • Read GCP_CNCC_CREDENTIALS_FILE env var (set by CPO) and set GOOGLE_APPLICATION_CREDENTIALS on the CNCC container so that CNCC's auto-detection (cloud-network-config-controller PR #206) picks up the WIF external_account credential.
  • Add --token-audience=openshift to the cloud-token minter so GCP STS can validate the projected service-account token against the OIDC provider's allowed audience.
  • Add unit tests for template rendering.

Summary by CodeRabbit

  • New Features

  • Added support for conditional Google Cloud Workload Identity credentials in cloud network configuration.

  • Enabled token-audience configuration for OpenShift token minter.

  • Tests

  • Added tests to verify GCP credential injection/omission and path handling.

  • Added tests to verify token-audience is present in the cloud token minter.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@apahim apahim marked this pull request as ready for review March 12, 2026 14:38
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 12, 2026
@openshift-ci openshift-ci bot requested a review from bpickard22 March 12, 2026 14:47
@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 12, 2026

/retest-required

1 similar comment
@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 12, 2026

/retest-required

@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 12, 2026

/retest ci/prow/hypershift-e2e-aks

@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 12, 2026

/retest-required

3 similar comments
@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 16, 2026

/retest-required

@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 18, 2026

/retest-required

@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 31, 2026

/retest-required

@apahim
Copy link
Copy Markdown
Author

apahim commented Mar 31, 2026

/unhold

@openshift-ci openshift-ci bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Mar 31, 2026
@apahim
Copy link
Copy Markdown
Author

apahim commented Apr 1, 2026

/retest-required

@apahim
Copy link
Copy Markdown
Author

apahim commented Apr 1, 2026

/retest-required

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 1, 2026

@apahim: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security 4cd79a7 link false /test security
ci/prow/e2e-metal-ipi-ovn-dualstack-bgp 4cd79a7 link true /test e2e-metal-ipi-ovn-dualstack-bgp
ci/prow/e2e-metal-ipi-ovn-dualstack-bgp-local-gw 4cd79a7 link true /test e2e-metal-ipi-ovn-dualstack-bgp-local-gw

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

return nil, errors.Errorf("invalid GCP_CNCC_CREDENTIALS_FILE %q: must be a filename", gcpCredsFile)
} else {
data.Data["GCPCredentialsPath"] = filepath.Join("/etc/secret/cloudprovider", gcpCredsFile)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... if the feature is configured, hypershift passes the literal string "application_default_credentials.json" to CNO, which then prepends the literal string "/etc/secret/cloudprovider/" and passes it to CNCC, which uses it as a filename.

This would make sense if hypershift knew the credentials filename but not the directory it was in, and CNO knew the directory but not the filename. But I'm guessing that's not the case.

Where do the creds come from? Who writes them there?

If HyperShift actually knows for sure what the credentials filename is (and nobody else does know for sure) then it should pass the whole path to CNO, which should pass it to CNCC.

If HyperShift doesn't know where the creds are, but only knows whether or not it wants CNCC to use them, then it should just pass a true/false value to CNO, and then likewise, CNO can either pass the full pathname or a true/false value to CNCC.

Also, it seems like it would be better to configure CNCC via a command-line argument...

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hypershift creates the secret cloud-network-config-controller-creds containing the WIF credential JSON under the key application_default_credentials.json

Here specifically:

But that's becuase the secret name is hardcoded in CNO:

Then CNO mounts it in /etc/secret/cloudprovider:

Then we have to create the env var for CNO with the filename:

The filename-only approach follows the existing Azure pattern at line 110, where MANAGED_AZURE_HCP_CREDENTIALS_FILE_PATH similarly passes a filename that CNO combines with a mount path (/var/run/secrets/azure).

Each component owns its part of the path: HyperShift controls the secret key name, CNO controls the mount point.

The env var also doubles as a feature flag - empty means GCP WIF is not configured.

Passing the full path would couple HyperShift to CNO's mount point; passing a boolean would require hardcoding the filename in CNO, coupling it to HyperShift's secret key choice. The current split keeps both sides independent.

Regarding configuring CNCC: the env var set on the CNCC container is GOOGLE_APPLICATION_CREDENTIALS, which is a standard GCP SDK convention. The client libraries read it automatically to locate credentials... It's not an arbitrary env var, so a CLI argument would add an extra layer that just sets this env var anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants