From 916c7867f7ea766824728851a25b01ebbc600491 Mon Sep 17 00:00:00 2001 From: Anish Ramasekar Date: Mon, 17 Mar 2025 15:18:05 -0700 Subject: [PATCH 1/3] fix godoc for email_verified requirement when username contains claims.email Using 'claims.?email_verified.orValue(true) == true' in the example validation rule. By explicitly comparing the value to true, we let type-checking see the result will be a boolean, and to make sure a non-boolean email_verified claim will be caught at runtime. Signed-off-by: Anish Ramasekar --- .../src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go | 4 +++- .../src/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go b/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go index dee2c115a15..0a50799c26e 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go @@ -352,7 +352,9 @@ type ClaimMappings struct { // If username.expression uses 'claims.email', then 'claims.email_verified' must be used in // username.expression or extra[*].valueExpression or claimValidationRules[*].expression. // An example claim validation rule expression that matches the validation automatically - // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true)'. + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. By explicitly comparing + // the value to true, we let type-checking see the result will be a boolean, and to make sure a non-boolean email_verified + // claim will be caught at runtime. // // In the flag based approach, the --oidc-username-claim and --oidc-username-prefix are optional. If --oidc-username-claim is not set, // the default value is "sub". For the authentication config, there is no defaulting for claim or prefix. The claim and prefix must be set explicitly. diff --git a/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go b/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go index a0e13593b3b..72fe602b95d 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1beta1/types.go @@ -323,7 +323,9 @@ type ClaimMappings struct { // If username.expression uses 'claims.email', then 'claims.email_verified' must be used in // username.expression or extra[*].valueExpression or claimValidationRules[*].expression. // An example claim validation rule expression that matches the validation automatically - // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true)'. + // applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. By explicitly comparing + // the value to true, we let type-checking see the result will be a boolean, and to make sure a non-boolean email_verified + // claim will be caught at runtime. // // In the flag based approach, the --oidc-username-claim and --oidc-username-prefix are optional. If --oidc-username-claim is not set, // the default value is "sub". For the authentication config, there is no defaulting for claim or prefix. The claim and prefix must be set explicitly. From af291a44c3a2e31ef58851d27aaa70e9a02fedaa Mon Sep 17 00:00:00 2001 From: Anish Ramasekar Date: Mon, 17 Mar 2025 15:38:35 -0700 Subject: [PATCH 2/3] Add unit test to validate email_verified in claim validation rules Signed-off-by: Anish Ramasekar --- .../apiserver/validation/validation_test.go | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/staging/src/k8s.io/apiserver/pkg/apis/apiserver/validation/validation_test.go b/staging/src/k8s.io/apiserver/pkg/apis/apiserver/validation/validation_test.go index 2e39d375f1c..6d761b59318 100644 --- a/staging/src/k8s.io/apiserver/pkg/apis/apiserver/validation/validation_test.go +++ b/staging/src/k8s.io/apiserver/pkg/apis/apiserver/validation/validation_test.go @@ -585,6 +585,61 @@ func TestValidateAuthenticationConfiguration(t *testing.T) { }, want: "", }, + { + name: "valid authentication configuration that uses verified email via claim validation rule", + in: &api.AuthenticationConfiguration{ + JWT: []api.JWTAuthenticator{ + { + Issuer: api.Issuer{ + URL: "https://issuer-url", + Audiences: []string{"audience"}, + }, + ClaimValidationRules: []api.ClaimValidationRule{ + { + // By explicitly comparing the value to true, we let type-checking see the result will be + // a boolean, and to make sure a non-boolean email_verified claim will be caught at runtime. + Expression: `claims.?email_verified.orValue(true) == true`, + }, + }, + // allow email claim only when email_verified is present and true + ClaimMappings: api.ClaimMappings{ + Username: api.PrefixedClaimOrExpression{ + Expression: `{claims.?email: "panda"}`, + }, + }, + }, + }, + }, + want: "", + }, + { + name: "valid authentication configuration that uses verified email via claim validation rule incorrectly", + in: &api.AuthenticationConfiguration{ + JWT: []api.JWTAuthenticator{ + { + Issuer: api.Issuer{ + URL: "https://issuer-url", + Audiences: []string{"audience"}, + }, + ClaimValidationRules: []api.ClaimValidationRule{ + { + // This expression was previously documented in the godoc for the JWT authenticator + // and was incorrect. It was changed to the above expression in the previous test case. + // Testing the old expression here to confirm it fails validation. + Expression: `claims.?email_verified.orValue(true)`, + }, + }, + // allow email claim only when email_verified is present and true + ClaimMappings: api.ClaimMappings{ + Username: api.PrefixedClaimOrExpression{ + Expression: `{claims.?email: "panda"}`, + }, + }, + }, + }, + }, + want: `[jwt[0].claimValidationRules[0].expression: Invalid value: "claims.?email_verified.orValue(true)": must evaluate to bool, jwt[0].claimMappings.username.expression: Invalid value: "{claims.?email: \"panda\"}": claims.email_verified must be used in claimMappings.username.expression or claimMappings.extra[*].valueExpression or claimValidationRules[*].expression when claims.email is used in claimMappings.username.expression]`, + }, { name: "valid authentication configuration", in: &api.AuthenticationConfiguration{ From 349e079abebe66fcaf06a19da560fd13787ea027 Mon Sep 17 00:00:00 2001 From: Anish Ramasekar Date: Mon, 17 Mar 2025 16:01:36 -0700 Subject: [PATCH 3/3] Update release notes in changelog-1.30 to fix example claim validation rule Signed-off-by: Anish Ramasekar --- CHANGELOG/CHANGELOG-1.30.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG/CHANGELOG-1.30.md b/CHANGELOG/CHANGELOG-1.30.md index b269ada4bab..c87cfd0d87f 100644 --- a/CHANGELOG/CHANGELOG-1.30.md +++ b/CHANGELOG/CHANGELOG-1.30.md @@ -1584,7 +1584,7 @@ name | architectures ([#123344](https://github.com/kubernetes/kubernetes/pull/123344), [@nilekhc](https://github.com/nilekhc)) - When configuring a JWT authenticator: - If `username.expression` used 'claims.email', then 'claims.email_verified' must have been used in `username.expression` or `extra[*].valueExpression` or `claimValidationRules[*].expression`. An example claim validation rule expression that matches the validation automatically applied when `username.claim` is set to 'email' is 'claims.?email_verified.orValue(true)'. + If `username.expression` used 'claims.email', then 'claims.email_verified' must have been used in `username.expression` or `extra[*].valueExpression` or `claimValidationRules[*].expression`. An example claim validation rule expression that matches the validation automatically applied when `username.claim` is set to 'email' is 'claims.?email_verified.orValue(true) == true'. ([#123737](https://github.com/kubernetes/kubernetes/pull/123737), [@enj](https://github.com/enj)) - `readOnly` volumes now support recursive read-only mounts for kernel versions >= 5.12." ([#123180](https://github.com/kubernetes/kubernetes/pull/123180), [@AkihiroSuda](https://github.com/AkihiroSuda)) @@ -2416,7 +2416,7 @@ name | architectures If username.expression uses 'claims.email', then 'claims.email_verified' must be used in username.expression or extra[*].valueExpression or claimValidationRules[*].expression. An example claim validation rule expression that matches the validation automatically - applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true)'. ([#123737](https://github.com/kubernetes/kubernetes/pull/123737), [@enj](https://github.com/enj)) [SIG API Machinery and Auth] + applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'. ([#123737](https://github.com/kubernetes/kubernetes/pull/123737), [@enj](https://github.com/enj)) [SIG API Machinery and Auth] ### Feature