WIP: Prototype to provide user-defined upsteam-to-downstream identity transformations/filters via Starlark or CEL functions #694
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Problem Statement
During login, when an identity is established from an upstream OIDC or LDAP provider, then a Pinniped admin might like to perform arbitrary transformations like adding a prefix to usernames or group names, removing unwanted groups, down-casing usernames or group names, rejecting authentication based on group memberships, etc. This is logged as issue #558.
Hopefully this feature can pave the way towards supporting multiple simultaneous upstream identity providers for a single
FederationDomain
in the Supervisor. Once you are able to do things like prefix usernames and group names, then you can ensure that downstream usernames and group names from different simultaneous IDPs are unique and won't clash.To support this feature, we need a way for users to craft their own arbitrary transformations in some kind of language.
Update February 2023 - Using CEL
In the 1.5 years since this prototype PR was first created, the Kubernetes project has adopted the CEL language as its preferred embedded language. The most recent release of Kubernetes contains at least two different usages of CEL, and there are more proposed as KEPs for the future. Also, the CEL language has progressed, and there are now extensions available to offer more functionality for string manipulation.
CEL offers many of the same benefits of Starlark in terms of being performant, thread-safe, sandboxed, international (supports UTF-8), simple, cancellable, and extendable.
CEL differs from Starlark in several ways. In CEL, the user cannot define functions, and cannot import libraries, although the system in which it is embedded can extend the CEL language using Go (similar to Starlark). CEL expressions can only have one return value, which impacts the design of the API, e.g. the username transformations would need to be separate CEL expressions from the groups transformations.
This PR has now been updated to also include an implementation of identity transformations using CEL, alongside the original Starlark proof of concept. The implementation using CEL is in the
internal/idtransform
andinternal/celformer
directories in this PR.The intention is to choose either Starlark or CEL (not both), whichever is the best fit for our needs. Kubernetes broadly adopting CEL seems like a good argument to lean towards using CEL, assuming all other considerations were determined to be roughly equal. Kubernetes admins will need to learn CEL anyways as more CEL-based features are added to Kubernetes.
The rest of the description of this PR below is from 1.5 year ago when Starlark was investigated as a possible solution.
Old Starlark Investigation Notes
Using Starlark as Part of the Solution
Why consider using Starlark for custom user-defined upsteam-to-downstream identity transformations/filters?
Examples
Here is an example Starlark script to add a prefix to every upstream username and group name, and also downcase every upstream username and group name:
Here is an example Starlark script to reject logins from any user who does not belong to the upstream group "admins".
Some possible example use cases for upstream-to-downstream identity transformations include:
Some more “creative” (maybe less likely to be needed) use cases include:
The Rest of the Solution
It would be easy to allow users to define such scripts as a string on a CRD, in a Secret, or wherever we like. For example, the
FederationDomain
CRD could have a field to define a custom transformation Starlark script which would be applied to each login via an IDP. These details are not yet designed.If desired, we could allow a user-defined list of transform functions to be applied in order, since the input and output types are the similar enough that they are easy to chain together. This might be fancier than needed.
Broadly speaking, our Kube controllers would parse/load the user-defined Starlark scripts into memory using
starformer.New()
. Then our authentication code would execute the user-defined Starlark hooks during each login, which are thread-safe and performant, usingstarformer.Transform()
. Thestarformer.Transformer
instances, which are returned bystarformer.New()
, would probably live in our existing in-memory caches that are loaded by our controllers and used by our authentication code.Limitations
Note that Starlark does not allow scripts to perform IO by default. This is a helpful feature. However, it also means that base Starlark will not allow configurations where an administrator wants to make HTTP calls to an external authorization engine to perform authentication policy checks. However, the Golang implementation of Starlark does allow language extensions to be authored in Golang, so it would be theoretically possible for us to create such an extension if desired.
Alternatives Considered
Release Notes
Release note: