Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CEL for StructuredAuthenticationConfig #121078

Merged

Conversation

aramase
Copy link
Member

@aramase aramase commented Oct 9, 2023

  • Add additional fields to JWTAuthenticator in AuthenticationConfiguration v1alpha1
  • Add support for CEL expressions and integrate with OIDC authenticator

fixes #119235

/kind feature
/sig auth
/triage accepted
/milestone v1.29
/priority important-soon

Adds CEL expressions to v1alpha1 AuthenticationConfiguration.
[KEP]: https://github.com/kubernetes/enhancements/tree/master/keps/sig-auth/3331-structured-authentication-configuration

@k8s-ci-robot
Copy link
Contributor

@aramase: You must be a member of the kubernetes/milestone-maintainers GitHub team to set the milestone. If you believe you should be able to issue the /milestone command, please contact your Milestone Maintainers Team and have them propose you as an additional delegate for this responsibility.

In response to this:

TODO

fixes #119235

/kind feature
/sig auth
/triage accepted
/milestone v1.29
/priority important-soon

TODO
[KEP]: https://github.com/kubernetes/enhancements/tree/master/keps/sig-auth/3331-structured-authentication-configuration

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. kind/feature Categorizes issue or PR as related to a new feature. sig/auth Categorizes an issue or PR as relevant to SIG Auth. triage/accepted Indicates an issue or PR is ready to be actively worked on. priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Oct 9, 2023
@aramase aramase changed the title Implement CEL for StructuredAuthenticationConfig [WIP] Implement CEL for StructuredAuthenticationConfig Oct 9, 2023
@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. area/apiserver kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. labels Oct 9, 2023
@aramase aramase force-pushed the aramase/f/kep_3331_cel_integration branch from 569c36f to 790305f Compare October 11, 2023 16:47
@k8s-ci-robot
Copy link
Contributor

@aramase: The label(s) kind/api-review cannot be applied, because the repository doesn't have them.

In response to this:

/kind api-review

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@aramase
Copy link
Member Author

aramase commented Oct 11, 2023

/label api-review

@k8s-ci-robot k8s-ci-robot added the api-review Categorizes an issue or PR as actively needing an API review. label Oct 11, 2023
@aramase aramase force-pushed the aramase/f/kep_3331_cel_integration branch 3 times, most recently from c258db8 to 38283b9 Compare October 12, 2023 07:28
@liggitt liggitt added this to Assigned in API Reviews Oct 12, 2023
@liggitt liggitt moved this from Assigned to In progress in API Reviews Oct 12, 2023
Copy link
Member

@enj enj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial API review on 10-12-23

// These allow invariants to be applied to incoming identities such as preventing the
// use of the system: prefix that is commonly used by Kubernetes components.
// +optional
UserInfoValidationRules []UserInfoValidationRule `json:"userInfoValidationRules,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CEL variable that contains the final user info should be called user

Suggested change
UserInfoValidationRules []UserInfoValidationRule `json:"userInfoValidationRules,omitempty"`
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specifically that all validation rules are logically ANDed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internally, we may want to combine all the CEL expressions by wrapping them in parentheses and using logical ANDs (after we benchmark to see if it worth it). On a failure, we would run the individual expressions so that we could provide the correct error message.

@liggitt liggitt moved this from In progress to Changes requested in API Reviews Oct 12, 2023
Copy link
Contributor

@cici37 cici37 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just did a quick pass, will save time for another pass on imp details and tests. Thank you!

@MaryamTavakkoli
Copy link

Hello!
Bug triage for the 1.29 release cycle is here! I want to check the status and remind you that the code freeze is starting 01:00 UTC Wednesday 1st November 2023 / 18:00 PDT Tuesday 31st October 2023 (next week), as we want to ensure that each PR has a chance to be merged.
Are we still targeting the 1.29 release?

@aramase
Copy link
Member Author

aramase commented Oct 27, 2023

Hello! Bug triage for the 1.29 release cycle is here! I want to check the status and remind you that the code freeze is starting 01:00 UTC Wednesday 1st November 2023 / 18:00 PDT Tuesday 31st October 2023 (next week), as we want to ensure that each PR has a chance to be merged. Are we still targeting the 1.29 release?

Yes, this PR is still targeted for v1.29.

staging/src/k8s.io/apiserver/pkg/apis/apiserver/types.go Outdated Show resolved Hide resolved

// CELMapper is a struct that holds the compiled expressions for
// username, groups, uid, extra, claimValidation and userValidation
type CELMapper struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-blocking since this doesn't touch the config API layer, but ClaimsMapper is a really confusing interface... each instance held in CELMapper is only valid to call one of the methods. It's weird to have to put the documentation about which uses of this interface should call which methods on the interface doc.

interaces like these would be clearer (even if the names get a little silly by the end):

Username             StringMapper
Groups               StringArrayMapper
UID                  StringMapper
Extra                MapStringStringArrayMapper
ClaimValidationRules BoolMapper
UserValidationRules  BoolMapper
type BoolMapper interface {
  MapBool(context.Context, *unstructured.Unstructured) (bool, error)
}
type StringMapper interface {
  MapString(context.Context, *unstructured.Unstructured) (string, error)
}
type StringArrayMapper interface {
  MapStringArray(context.Context, *unstructured.Unstructured) ([]string, error)
}
type MapStringStringArrayMapper interface {
  MapMapStringStringArray(context.Context, *unstructured.Unstructured) (map[string][]string, error)
}

specific implementations of those could wrap an interface like

EvalSingle(context.Context, *unstructured.Unstructured) (EvaluationResult, error)

or

EvalMultiple(context.Context, *unstructured.Unstructured) ([]EvaluationResult, error)

and type-check / accumulate

I think this could be cleaned up in 1.30 to be a lot more composable

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added this to the follow-up items list for v1.30. I'll get this cleaned up.

return nil, err
authenticator := &Authenticator{}

celMapper, fieldErr := apiservervalidation.ValidateJWTAuthenticator(opts.JWTAuthenticator)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if we're doing more than validation, rename to CompileAndValidateJWTAuthenticator?

will celMapper be nil if there are no CEL rules? will fieldErr be non-nil if the structuredauthn feature is off and JWTAuthenticator contains cel rules?

Copy link
Member Author

@aramase aramase Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will celMapper be nil if there are no CEL rules? will fieldErr be non-nil if the structuredauthn feature is off and JWTAuthenticator contains cel rules?

  1. celMapper is not nil when there are no CEL rules. The subfields will be empty if there are no expressions defined for the field.
  2. fieldErr will be non-nil if feature is off and any of the fields in JWTAuthenticator contain expressions. We have validation in all the fields that support an expression.

Comment on lines +95 to +97
compiler := authenticationcel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion()))
mapper := &authenticationcel.CELMapper{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the feature's not enabled, probably don't need to construct these, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm.. I can't tell if celMapper is conditional on the feature gate (will be nil if the feature's off) or on whether CEL expressions were used for various things (subfields will be nil if there's no CEL group expression, etc) or both.

Copy link
Member Author

@aramase aramase Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the feature's not enabled, probably don't need to construct these, right?

right now I'm passing the struct to different validate funcs that set the subfields instead of returning subfields, so we're initializing this.

hmm.. I can't tell if celMapper is conditional on the feature gate (will be nil if the feature's off) or on whether CEL expressions were used for various things (subfields will be nil if there's no CEL group expression, etc) or both.

In the current implementation, if the feature gate is not set, the subfields that contain an expression will be nil but celMapper is not nil.

We can return nil from validateJWTAuthenticator if feature gate is not set.

@aramase aramase force-pushed the aramase/f/kep_3331_cel_integration branch from e851239 to 96d94ab Compare October 31, 2023 05:25
@aramase aramase requested review from liggitt and enj October 31, 2023 06:07
@aramase aramase force-pushed the aramase/f/kep_3331_cel_integration branch 2 times, most recently from dca4357 to 905a09c Compare October 31, 2023 15:49
Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
@aramase aramase force-pushed the aramase/f/kep_3331_cel_integration branch from 905a09c to 9d1cf54 Compare October 31, 2023 17:04
}
}

compilationResults, err := validatePrefixClaimOrExpression(compiler, m.Username, fldPath.Child("username"), true, structuredAuthnFeatureEnabled)
Copy link
Member

@liggitt liggitt Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to strengthen in 1.30: if we're using the same validatePrefixClaimOrExpression function to construct the CEL mapper for both username and groups, how is it doing any kind of type checking that the result is a string (for username) or a string / string array / null (for groups)?

a username or groups expression of "true" should fail type checking, but I don't think it would, I think it would fail at runtime

obviously, things returning claims directly we can't typecheck until runtime since claims are dynamic, but things returning cel literals can be typechecked


if err != nil {
allErrs = append(allErrs, err)
} else if structuredAuthnFeatureEnabled {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't be able to get here if structuredAuthnFeatureEnabled is false, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do compile the CEL expression even when feature gate isn’t enabled and don’t short circuit on error. This is done to aggregate all errors as part of validation.

Leaving this as-is based on the slack conversation.

if m.Groups.Prefix != nil && len(m.Groups.Claim) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("groups", "claim"), "non-empty claim name is required when prefix is set"))

if structuredAuthnFeatureEnabled && len(compilationResults) > 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it shouldn't be possible to have non-zero compilation results and the feature be off, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be possible for non-zero compilation results when the feature is off as we perform validation and compiling of expression always. This was done to aggregate all errors from validation and return to user.

Comment on lines +862 to +863
switch val.Type().TypeName() {
case celgo.StringType.TypeName():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs cleanup in 1.30... I suspect there are more efficient ways to switch on the types natively in go, possibly like:

switch t := val.Value().(type) {
case nilType:
  ... no-op
case stringType:
  if len(t) > 0 {
    append
  }
case []interface{}:
  ... iterate, safely cast, skip nil and empty string, append non-empty string, error on other types
case []ref.Val{}:
  ... iterate, safely cast, skip nil and empty string, append non-empty string, error on other types
default:
  ... error, unexpected type
}


extra := make(map[string][]string, len(evalResult))
for _, result := range evalResult {
extraMapping, ok := result.ExpressionAccessor.(*authenticationcel.ExtraMappingCondition)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this cast is a code smell to clean up in 1.30 before beta... we're encapsulating the key information in the accessor, carrying it along to the evalresults, and then digging it back out here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! Have a task in #121553 to try and use generics.

Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
@aramase aramase force-pushed the aramase/f/kep_3331_cel_integration branch from 9d1cf54 to cc190e0 Compare October 31, 2023 20:18
@aramase aramase requested a review from liggitt October 31, 2023 20:25
@liggitt
Copy link
Member

liggitt commented Oct 31, 2023

/approve
for API bits

@enj has lgtm

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Oct 31, 2023
@enj
Copy link
Member

enj commented Oct 31, 2023

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Oct 31, 2023
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: b34c77509b763f829284ef76394d17d3538ccba4

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: aramase, enj, liggitt

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-review Categorizes an issue or PR as actively needing an API review. approved Indicates a PR has been approved by an approver from all required OWNERS files. area/apiserver area/test cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API kind/feature Categorizes issue or PR as related to a new feature. lgtm "Looks good to me", indicates that a PR is ready to be merged. priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/api-machinery Categorizes an issue or PR as relevant to SIG API Machinery. sig/auth Categorizes an issue or PR as relevant to SIG Auth. sig/testing Categorizes an issue or PR as relevant to SIG Testing. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. triage/accepted Indicates an issue or PR is ready to be actively worked on.
Projects
Status: API review completed, 1.29
Archived in project
Archived in project
Development

Successfully merging this pull request may close these issues.

[StructuredAuthenticationConfig] Wire CEL functions to authn config
7 participants