OIDC groupsClaims and requiredClaims are silently corrupted by the v1alpha2 conversion
/kind bug
1. What kops version are you running? The command kops version, will display
this information.
Present on master (1.37 development). The conversion has had this shape since v1alpha3 was introduced.
2. What Kubernetes version are you running? kubectl version will print the
version if a cluster is running or provide the Kubernetes version specified as
a kops flag.
Not version specific — the corruption happens in the kOps API conversion layer, before anything reaches the cluster.
3. What cloud provider are you using?
All providers.
4. What commands did you run? What is the simplest way to reproduce this issue?
Configure an OIDC group claim containing a comma, or a required claim whose key
contains an equals sign, then run any command that writes the cluster back to the
state store (kops edit cluster, kops replace -f, kops update cluster).
spec:
authentication:
oidc:
clientID: kubernetes
issuerURL: https://example.com
groupsClaims:
- "a,b"
requiredClaims:
"a=b": "c"5. What happened after the commands executed?
Both values are silently rewritten:
| field | stored | read back |
|---|---|---|
groupsClaims |
["a,b"] |
["a", "b"] |
requiredClaims |
{"a=b": "c"} |
{"a": "b=c"} |
No warning and no error — the cluster is reconciled against the corrupted values.
6. What did you expect to happen?
Either the claims round trip unchanged, or kOps rejects the configuration with a clear validation error instead of silently rewriting it.
7. Please provide your cluster manifest.
See the snippet in (4); nothing else is required to reproduce.
8. Please run the commands with most verbose logging by adding the -v 10 flag.
Not applicable — there is no log output, which is the point of the report.
9. Anything else do we need to know?
Cause. spec.authentication.oidc has no representation in v1alpha2. The hand
written conversion flattens it into the legacy kube-apiserver OIDC flags, which are
string encoded:
pkg/apis/kops/v1alpha2/conversion.go:402joinsGroupsClaimswith,into the singleoidcGroupsClaimflag;conversion.go:122splits it back on,.pkg/apis/kops/v1alpha2/conversion.go:407encodes eachRequiredClaimsentry askey=valueintooidcRequiredClaim;conversion.go:129splits each entry on the first=.
A separator inside a claim name is therefore indistinguishable from the separator itself. Comma and equals sign are unusual in JWT claim names but are perfectly legal, so this is silent data corruption rather than a rejected input.
This is live rather than theoretical, because the state store is still written as
v1alpha2 (pkg/client/simple/vfsclientset/commonvfs.go:
var StoreVersion = v1alpha2.SchemeGroupVersion). Every write/read cycle re-applies
the corruption. v1alpha3 is unaffected — it carries authentication.oidc structurally.
Possible fixes.
- Validate and reject. Add validation that a
groupsClaimsentry contains no,and arequiredClaimskey contains no=. Cheap, and converts silent corruption into a clear error. Downside: a cluster already storing such a value starts failing validation, though its configuration is already being corrupted today. - Give v1alpha2 a structural home for OIDC. Change
AuthenticationSpec.OIDCinpkg/apis/kops/v1alpha2/cluster.gofromjson:"-"tojson:"oidc,omitempty"so the settings persist without the string encoding, leaving thekubeAPIServer.oidc*flags as a read-only migration path. The conversion already writes both forms, so an older kOps reading the newer state store still finds the legacy flags; the read path would needauthentication.oidcto win when both are present. This mirrors what #18740 does forspec.cloudProvider.{aws,gce}.binariesLocation, which is the same class of problem: a structured internal field with no structured v1alpha2 home.
Related. A neighbouring crash in the same block — an oidcRequiredClaim entry with
no = at all panicked with index out of range [1] with length 1 — was found at the
same time and is being fixed separately.
Found while adding round trip test coverage for Cluster and InstanceGroup, which
had been excluded from TestRoundTripTypes in pkg/apis/kops/install/roundtrip_test.go.
Source: kubernetes/kops