Skip to content

Own the CredentialsRequest the operator asks for - #2

Closed
frobware wants to merge 3 commits into
azure-e2efrom
credentialsrequest-ownership
Closed

frobware wants to merge 3 commits into
azure-e2efrom
credentialsrequest-ownership

Conversation

@frobware

Copy link
Copy Markdown
Owner

The CredentialsRequest this operator makes carries no owner, so it outlives the configuration that asked for it. Deleting the BGPCloudConfiguration leaves the request behind, and with it, on a cluster that mints, the cloud identity the cloud credential operator made to serve it. That is alebedev87's observation on openshift#122 (r4038418679), raised there as work for a dedicated PR.

This is stacked on azure-e2e rather than main so it can fix both platforms at once: internal/platform/azure/credentials.go does not exist on main yet.

Three commits:

  • Build the configuration's owner reference in one place. The FRR path already assembled one by hand; the credentials path needs the same one.
  • Own the CredentialsRequest the operator asks for. Both platforms name the configuration as the request's owner, and reconciling adopts a request that has no owner, so a cluster installed before this change is repaired rather than left as it was.
  • Assert in e2e that the CredentialsRequest goes with the config. E2E-AWS-05 and E2E-AZURE-05 already delete the configuration and check what went with it; the request now belongs on that list.

The configuration is cluster scoped, which is what lets it own an object in openshift-cloud-credential-operator: the ban on crossing namespaces applies to namespaced owners. blockOwnerDeletion is left unset deliberately -- OpenShift enforces ownerReferencesPermissionEnforcement, which would otherwise require this operator to hold delete on bgpcloudconfigurations/finalizers.

Worth stating plainly: an operator uninstall does not delete the BGPCloudConfiguration, so an uninstall on its own still leaves the request behind. What this buys is that deleting the configuration collects it.

The e2e assertion can only fire where the operator actually asked the cluster for credentials. A pod that already holds some -- the identity webhook's, or the profile on a desk running make run -- never asks, so there is no object to own or collect; the specs say so on the way past rather than asserting nothing quietly.

What it does on a cluster

Self-managed AWS, credentialsMode: Manual, driving aws.ResolveCredentials against the live API server. Before:

CredentialsRequest ownerReferences: []
deleted BGPCloudConfiguration
RESULT: CredentialsRequest still present after 90s, refs []

After, on the same cluster:

CredentialsRequest ownerReferences: [BGPCloudConfiguration cluster f37f6d0a-29e2-4f63-8c4c-91db09c73d0c controller=true]
deleted BGPCloudConfiguration
RESULT: CredentialsRequest garbage-collected      (1.35s)

A request seeded by hand with no owner -- what an earlier release leaves -- is adopted on the next resolve and then collected with the configuration. Azure gives the same before and after on a live Azure cluster: survives 90s unowned, collected in 1.58s once owned.

The whole chain, in-cluster, through Reconcile rather than a harness, running the packaged image:

$ oc get credentialsrequest -n openshift-cloud-credential-operator bgp-cloud-connector-azure \
    -o jsonpath='{.metadata.ownerReferences}'
[{"apiVersion":"networking.openshift.io/v1beta1","controller":true,"kind":"BGPCloudConfiguration",
  "name":"cluster","uid":"31624bcd-5e12-46b0-8656-762629fcfa66"}]

$ oc get secret -n openshift-bgp-cloud-connector bgp-cloud-connector-azure-credentials \
    -o go-template='{{range $k,$v := .data}}{{$k}} {{end}}'
azure_client_id azure_client_secret azure_region azure_resource_prefix azure_resourcegroup
azure_subscription_id azure_tenant_id

$ oc delete bgpcloudconfiguration cluster
bgpcloudconfiguration.networking.openshift.io "cluster" deleted

$ oc get credentialsrequest -n openshift-cloud-credential-operator bgp-cloud-connector-azure
Error from server (NotFound): credentialsrequests.cloudcredential.openshift.io "bgp-cloud-connector-azure" not found

$ oc get secret -n openshift-bgp-cloud-connector bgp-cloud-connector-azure-credentials
Error from server (NotFound): secrets "bgp-cloud-connector-azure-credentials" not found

CCO served the request and the operator authenticated with what it wrote -- discovery came back 404 ResourceNotFound for a deliberately fabricated route server name, which only a working token reaches. Deleting the configuration took the request, and CCO's finalizer took the secret with it. That cluster is passthrough, so there is no minted identity to reclaim; the credential material CCO placed on the cluster is the closest thing it has, and it went.

Test plan

  • make test and make lint green.
  • Four new unit tests: the request is owned on create, and an existing unowned request is adopted, for AWS and Azure.
  • Each commit builds, vets and passes its tests on its own.
  • Live AWS and live Azure clusters, before and after, as above.
  • The packaged image deployed with make deploy, driving the full reconcile, as above.

The FRR path assembles an owner reference naming the singleton by hand.
The credentials path is about to need the same one, so give it a name
rather than a second copy.
The request carries no owner, so it outlives the configuration that
asked for it: deleting the BGPCloudConfiguration leaves the request
behind, and with it, on a cluster that mints, the cloud identity the
cloud credential operator made to serve it.

Name the configuration as the request's owner. It is cluster scoped,
which is what lets it own an object in a namespace that is not its own
-- the ban on crossing namespaces applies to namespaced owners.
Reconciling also adopts a request that has no owner, so a cluster
installed before this change is repaired rather than left as it was.

blockOwnerDeletion stays unset. OpenShift enforces
ownerReferencesPermissionEnforcement, which would otherwise require
this operator to hold delete on bgpcloudconfigurations/finalizers.
The cleanup specs delete the configuration and check what should have
gone with it. The request this operator makes of the cloud credential
operator now belongs on that list: it is collected by the garbage
collector rather than by any code here, so nothing short of a cluster
can show that it works.

An operator whose pod already holds credentials asks the cluster for
none, and on such a run there is no object to own or collect. The specs
say so on the way past rather than asserting nothing quietly, because
an assertion that passes for want of an object reads exactly like one
that passed on its merits.
@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@frobware

Copy link
Copy Markdown
Owner Author

Reopened against the openshift repository as openshift#143.

@frobware frobware closed this Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant