Skip to content

feat(providerconfig): add namespaced v1beta2 credentials surface - #408

Open
markussiebert wants to merge 1 commit into
masterfrom
feat/providerconfig-namespaced-secret-scope
Open

feat(providerconfig): add namespaced v1beta2 credentials surface#408
markussiebert wants to merge 1 commit into
masterfrom
feat/providerconfig-namespaced-secret-scope

Conversation

@markussiebert

Copy link
Copy Markdown
Collaborator

Summary

Adds gitlab.m.crossplane.io/v1beta2 ProviderConfig as the storage version of
the namespaced provider config, with a credentials surface that fits the
namespaced scope:

  • secretRef is a LocalSecretKeySelector, always resolved in the
    ProviderConfig's own namespace (no namespace field);
  • the filesystem and environment sources are not offered — they reference
    provider-global state (the provider pod's filesystem / process environment)
    and cannot be scoped to a single namespace without breaking isolation;
  • the credentials source enum is narrowed to None;Secret.

v1beta1 is retained (served, non-storage) and only gains a version-level
deprecation warning steering users to v1beta2. ClusterProviderConfig and
ProviderConfigUsage are unchanged (v1beta1 only) — they legitimately need a
namespaced secret selector / have no successor.

The provider resolves namespaced credentials via the v1beta2 ProviderConfig and
records the resolved namespace in Config.CredentialsSecretRef, so self-managed
token detection keeps comparing against the managed resource namespace.

Conversion

Strategy None (no webhook). The v1beta1 -> v1beta2 delta is only
dropped/optional fields and a narrowed enum, none of which needs data
transformation. Because v1beta2 is storage, fields it does not define
(secretRef.namespace, fs, env) are pruned when a v1beta1 object is written,
and the provider only ever reads v1beta2 — so namespaced credentials can no
longer be sourced across namespaces regardless of the version applied.

Backward compatibility

  • v1beta1 schema is unchanged except the deprecation marker; existing v1beta1
    manifests and stored objects keep working.
  • ClusterProviderConfig / ProviderConfigUsage CRDs are byte-identical to
    before.
  • No functional regression versus current master: secretRef.namespace was
    already ignored (own-namespace enforced) and fs/env were never
    implemented. The only visible change is that these already-ignored fields no
    longer persist on v1beta1 (pruned at v1beta2 storage), plus the deprecation
    warning.
  • Dropping v1beta1 in the future will require a storage-version migration; it is
    intentionally kept served here so nothing must migrate now.

Testing

  • go build ./..., go vet ./..., go test ./... pass; make generate
    produces no drift.
  • Live end-to-end against a real GitLab instance via a kwok cluster with the
    provider running out-of-cluster:
    • native v1beta2 owner-mode token create -> Ready;
    • v1beta2 self-managed detection (SelfManaged=True) and one forced
      self-rotation (token id changes, then settles, no rotation storm);
    • v1beta1 manifest -> None conversion -> Ready (deprecated namespace pruned
      at storage);
    • the v1beta1 deprecation warning is emitted on kubectl apply.

…credentials surface

Introduce gitlab.m.crossplane.io/v1beta2 ProviderConfig as the storage version
of the namespaced provider config, with a cleaned-up credentials surface:

  - secretRef is a LocalSecretKeySelector, always resolved in the
    ProviderConfig's own namespace (no namespace field);
  - the filesystem and environment sources, which reference provider-global
    state and cannot be scoped to a namespace, are not offered;
  - the credentials source enum is narrowed to None;Secret.

Conversion between v1beta1 and v1beta2 uses strategy None (no webhook): the
delta is only dropped/optional fields and a narrowed enum, none of which needs
data transformation. Because v1beta2 is the storage version, fields it does not
define (secretRef.namespace, fs, env) are pruned when a v1beta1 object is
written, and the provider only ever reads v1beta2 - so namespaced credentials
can no longer be sourced across namespaces regardless of the version applied.

v1beta1 is left unchanged except for a version-level deprecation warning
steering users to v1beta2; it stays served (non-storage). ClusterProviderConfig
and ProviderConfigUsage remain v1beta1 only.

The provider resolves namespaced credentials via the v1beta2 ProviderConfig
(GetTokenValueFromLocalSecret) and records the resolved namespace in
Config.CredentialsSecretRef so self-managed token detection keeps comparing
against the managed resource namespace.

Signed-off-by: Markus Siebert <markus.siebert@deutschebahn.com>
Assisted-by: Kiro:claude-opus-4.8
@markussiebert
markussiebert force-pushed the feat/providerconfig-namespaced-secret-scope branch from 0b2f359 to 1c03ab1 Compare September 4, 2026 14:37
@henrysachs

Copy link
Copy Markdown
Collaborator

Thanks @markussiebert — this addressed everything from the last pass, and in a couple of places more cleanly than I suggested.

LGTM

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.

3 participants