Skip to content

Commit 89c619f

Browse files
committed
Disallow k8s.io and kubernetes.io namespaced extra key in structured authn config
Signed-off-by: Anish Ramasekar <[email protected]>
1 parent 00236ae commit 89c619f

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

staging/src/k8s.io/apiserver/pkg/apis/apiserver/validation/validation.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,11 @@ func validateClaimMappings(compiler authenticationcel.Compiler, state *validatio
347347
if mapping.Key != strings.ToLower(mapping.Key) {
348348
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), mapping.Key, "key must be lowercase"))
349349
}
350+
351+
if isKubernetesDomainPrefix(mapping.Key) {
352+
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), mapping.Key, "k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use"))
353+
}
354+
350355
if seenExtraKeys.Has(mapping.Key) {
351356
allErrs = append(allErrs, field.Duplicate(fldPath.Child("key"), mapping.Key))
352357
continue
@@ -386,6 +391,24 @@ func validateClaimMappings(compiler authenticationcel.Compiler, state *validatio
386391
return allErrs
387392
}
388393

394+
func isKubernetesDomainPrefix(key string) bool {
395+
domainPrefix := getDomainPrefix(key)
396+
if domainPrefix == "kubernetes.io" || strings.HasSuffix(domainPrefix, ".kubernetes.io") {
397+
return true
398+
}
399+
if domainPrefix == "k8s.io" || strings.HasSuffix(domainPrefix, ".k8s.io") {
400+
return true
401+
}
402+
return false
403+
}
404+
405+
func getDomainPrefix(key string) string {
406+
if parts := strings.SplitN(key, "/", 2); len(parts) == 2 {
407+
return parts[0]
408+
}
409+
return ""
410+
}
411+
389412
func usesEmailClaim(ast *celgo.Ast) bool {
390413
return hasSelectExp(ast.Expr(), "claims", "email")
391414
}

staging/src/k8s.io/apiserver/pkg/apis/apiserver/validation/validation_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,69 @@ func TestValidateClaimMappings(t *testing.T) {
13351335
structuredAuthnFeatureEnabled: true,
13361336
want: `issuer.claimMappings.extra[0].key: Invalid value: "example.org/Foo": key must be lowercase`,
13371337
},
1338+
{
1339+
name: "extra mapping key prefix is k8.io",
1340+
in: api.ClaimMappings{
1341+
Username: api.PrefixedClaimOrExpression{Expression: "claims.username"},
1342+
Groups: api.PrefixedClaimOrExpression{Expression: "claims.groups"},
1343+
Extra: []api.ExtraMapping{
1344+
{Key: "k8s.io/foo", ValueExpression: "claims.extra"},
1345+
},
1346+
},
1347+
structuredAuthnFeatureEnabled: true,
1348+
want: `issuer.claimMappings.extra[0].key: Invalid value: "k8s.io/foo": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use`,
1349+
},
1350+
{
1351+
name: "extra mapping key prefix contains k8.io",
1352+
in: api.ClaimMappings{
1353+
Username: api.PrefixedClaimOrExpression{Expression: "claims.username"},
1354+
Groups: api.PrefixedClaimOrExpression{Expression: "claims.groups"},
1355+
Extra: []api.ExtraMapping{
1356+
{Key: "example.k8s.io/foo", ValueExpression: "claims.extra"},
1357+
},
1358+
},
1359+
structuredAuthnFeatureEnabled: true,
1360+
want: `issuer.claimMappings.extra[0].key: Invalid value: "example.k8s.io/foo": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use`,
1361+
},
1362+
{
1363+
name: "extra mapping key prefix is kubernetes.io",
1364+
in: api.ClaimMappings{
1365+
Username: api.PrefixedClaimOrExpression{Expression: "claims.username"},
1366+
Groups: api.PrefixedClaimOrExpression{Expression: "claims.groups"},
1367+
Extra: []api.ExtraMapping{
1368+
{Key: "kubernetes.io/foo", ValueExpression: "claims.extra"},
1369+
},
1370+
},
1371+
structuredAuthnFeatureEnabled: true,
1372+
want: `issuer.claimMappings.extra[0].key: Invalid value: "kubernetes.io/foo": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use`,
1373+
},
1374+
{
1375+
name: "extra mapping key prefix contains kubernetes.io",
1376+
in: api.ClaimMappings{
1377+
Username: api.PrefixedClaimOrExpression{Expression: "claims.username"},
1378+
Groups: api.PrefixedClaimOrExpression{Expression: "claims.groups"},
1379+
Extra: []api.ExtraMapping{
1380+
{Key: "example.kubernetes.io/foo", ValueExpression: "claims.extra"},
1381+
},
1382+
},
1383+
structuredAuthnFeatureEnabled: true,
1384+
want: `issuer.claimMappings.extra[0].key: Invalid value: "example.kubernetes.io/foo": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use`,
1385+
},
1386+
{
1387+
name: "extra mapping key prefix with ak8s.io, *.ak8s.io, bkubernetes.io, *.bkubernetes.io are still valid",
1388+
in: api.ClaimMappings{
1389+
Username: api.PrefixedClaimOrExpression{Expression: "claims.username"},
1390+
Groups: api.PrefixedClaimOrExpression{Expression: "claims.groups"},
1391+
Extra: []api.ExtraMapping{
1392+
{Key: "ak8s.io/foo", ValueExpression: "claims.extra"},
1393+
{Key: "example.ak8s.io/foo", ValueExpression: "claims.extra"},
1394+
{Key: "bkubernetes.io/foo", ValueExpression: "claims.extra"},
1395+
{Key: "example.bkubernetes.io/foo", ValueExpression: "claims.extra"},
1396+
},
1397+
},
1398+
structuredAuthnFeatureEnabled: true,
1399+
want: "",
1400+
},
13381401
{
13391402
name: "valid claim mappings but uses email without verification",
13401403
in: api.ClaimMappings{

0 commit comments

Comments
 (0)