Skip to content

feat(token): opt-in recreation of a token whose connection secret is missing - #44

Open
kaessert wants to merge 3 commits into
mainfrom
feat/token-connection-secret-recovery
Open

kaessert wants to merge 3 commits into
mainfrom
feat/token-connection-secret-recovery

Conversation

@kaessert

Copy link
Copy Markdown
Contributor

Description of your changes

Follow-up to #37. The Upbound API only returns a token's JWT at creation, so when a Token MR is restored without its connection secret (for example after a control plane export/import, which typically drops Secrets), #37 surfaces an error and leaves recovery to the user: delete the upstream token by hand so it gets recreated.

This adds an opt-in way to do that automatically, keeping the current behaviour as the default:

  • New optional spec.connectionSecretRecovery on the cluster and namespaced Token: None (default) or Recreate. It isn't an upstream parameter, so it sits next to forProvider.
  • Recreate: once an uncached read confirms the connection secret is missing or has no token, Observe deletes the upstream token (404 counts as gone), emits a RecreatingToken warning naming the old token ID, and reports the token as gone. The managed reconciler then creates a new token and publishes its connection secret, so the old token isn't left orphaned.
  • Guards: recovery is refused when the deletion policy is Orphan (cluster scope) or the management policies don't allow Create and Delete, and within 10 minutes of the last successful creation, so a token whose secret can't be published isn't recreated on every reconcile.
  • None: the behaviour from Fix token connection secret handling and auth session caching #37 is unchanged. Only the error message now names the option.
  • Docs: a short "Token Connection Secrets" section in the quickstart, and the field is set in both Token examples.

Consumers that still hold the old token need to pick up the new secret (for example a restart), the same as with a manual rotation.

I have:

  • Read and followed Crossplane's contribution process.
  • Run make reviewable to ensure this PR is ready for review. (Ran go build ./..., go test ./..., golangci-lint run ./... and go generate ./apis/... with a clean tree.)
  • Added backport release-x.y labels to auto-backport this PR if necessary.

How has this code been tested

  • Unit tests for the cluster and namespaced Token controllers: None vs Recreate, confirmed miss, upstream delete (incl. 404), guards (Orphan, management policies, cooldown), and error paths.
  • Against the real api.upbound.io on kind, with the package built from this branch:
    • Crossplane 1.20.13, None: after deleting the connection secret, the Token reports the error naming the option and the upstream token list is unchanged.
    • Crossplane 1.20.13, Recreate: the old token is deleted upstream, a new one is created, the secret is republished with token and id, only the new token remains, and one warning names the old ID. Recovery took 26–36 s (next poll).
    • Restore: after an export without Secrets and import into a fresh cluster, a Token with Recreate healed within seconds and a downstream consumer picked up the new token. The same setup with None stayed broken.
    • Crossplane 2.4.2: a namespaced Token with Recreate recovers after the cooldown. Orphan and management policies without Delete block recovery with an error that says why.
    • No loops: each recovery was watched for 8–17 minutes with exactly one recreate, also across a provider restart.

Add an optional spec.connectionSecretRecovery field to the cluster and
namespaced Token (enum None or Recreate, default None) and regenerate the
CRDs. The field is not an upstream parameter, so it sits next to
forProvider rather than inside it.

Signed-off-by: Tobias Kässer <tobias.kasser@upbound.io>
With spec.connectionSecretRecovery: Recreate, Observe no longer stops at
the missing-secret error added in #37. Once an uncached read confirms the
secret is missing or has no token, it deletes the upstream token (404
counts as gone), emits a RecreatingToken warning naming the old token ID
and reports the token as gone, so the managed reconciler creates a new
token and publishes its connection secret.

Recovery is refused when the deletion policy is Orphan (cluster scope) or
the effective management policies don't allow Create and Delete, and
within 10 minutes of the last successful creation, so that a new token
whose secret can't be published isn't recreated on every reconcile.

With None, the default, only the error message changes: it names the
option.

Signed-off-by: Tobias Kässer <tobias.kasser@upbound.io>
Add a short Token Connection Secrets section to the quickstart and set the
field in both Token examples.

Signed-off-by: Tobias Kässer <tobias.kasser@upbound.io>
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