mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-02-11 23:31:49 +00:00
Merge pull request #2491 from vmware/jwtauthenticator_new_features
add new features in JWTAuthenticator CRD
This commit is contained in:
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.26/README.adoc
generated
229
generated/1.26/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.27/README.adoc
generated
229
generated/1.27/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.28/README.adoc
generated
229
generated/1.28/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.29/README.adoc
generated
229
generated/1.29/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-29-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.30/README.adoc
generated
229
generated/1.30/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.3/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-30-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.31/README.adoc
generated
229
generated/1.31/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-31-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.32/README.adoc
generated
229
generated/1.32/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-32-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/1.33/README.adoc
generated
229
generated/1.33/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -58,37 +58,219 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec for configuring the authenticator.
|
||||
description: spec for configuring the authenticator.
|
||||
properties:
|
||||
audience:
|
||||
description: Audience is the required value of the "aud" JWT claim.
|
||||
description: audience is the required value of the "aud" JWT claim.
|
||||
minLength: 1
|
||||
type: string
|
||||
claimValidationRules:
|
||||
description: |-
|
||||
claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: ClaimValidationRule provides the configuration for
|
||||
a single claim validation rule.
|
||||
properties:
|
||||
claim:
|
||||
description: |-
|
||||
claim is the name of a required claim.
|
||||
Only string claim keys are supported.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must produce a boolean.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when expression returns false.
|
||||
message is a literal string.
|
||||
Mutually exclusive with claim and requiredValue.
|
||||
type: string
|
||||
requiredValue:
|
||||
description: |-
|
||||
requiredValue is the value of a required claim.
|
||||
Only string claim values are supported.
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
Mutually exclusive with expression and message.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
claims:
|
||||
description: |-
|
||||
Claims allows customization of the claims that will be mapped to user identity
|
||||
claims allows customization of the claims that will be mapped to user identity
|
||||
for Kubernetes access.
|
||||
properties:
|
||||
extra:
|
||||
description: |-
|
||||
extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
auth extras via client certificates. When configured, these extras will appear in client
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
auth extras, as described by
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
|
||||
expression must produce a string or string array value.
|
||||
If the value is empty, the extra mapping will not be present.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
hard-coded extra key/value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "'bar'"
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
|
||||
hard-coded key, value copying claim value
|
||||
- key: "acme.io/foo"
|
||||
valueExpression: "claims.some_claim"
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
|
||||
hard-coded key, value derived from claim value
|
||||
- key: "acme.io/admin"
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
This will result in:
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
items:
|
||||
description: ExtraMapping provides the configuration for a single
|
||||
extra mapping.
|
||||
properties:
|
||||
key:
|
||||
description: |-
|
||||
key is a string to use as the extra attribute key.
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
be valid HTTP Path characters as defined by RFC 3986.
|
||||
key must be lowercase.
|
||||
Required to be unique.
|
||||
Additionally, the key must not contain an equals sign ("=").
|
||||
type: string
|
||||
valueExpression:
|
||||
description: |-
|
||||
valueExpression is a CEL expression to extract extra attribute value.
|
||||
valueExpression must produce a string or string array value.
|
||||
"", [], and null values are treated as the extra mapping not being present.
|
||||
Empty string values contained within a string array are filtered out.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- valueExpression
|
||||
type: object
|
||||
type: array
|
||||
groups:
|
||||
description: |-
|
||||
Groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups".
|
||||
groups is the name of the claim which should be read to extract the user's
|
||||
group membership from the JWT token. When not specified, it will default to "groups",
|
||||
unless groupsExpression is specified.
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
groupsExpression:
|
||||
description: |-
|
||||
groupsExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's group memberships.
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
|
||||
The expression must produce a string or string array value.
|
||||
"", [], and null values are treated as the group mapping not being present.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
determine the user's group membership from the JWT token.
|
||||
type: string
|
||||
username:
|
||||
description: |-
|
||||
Username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username".
|
||||
username is the name of the claim which should be read to extract the
|
||||
username from the JWT token. When not specified, it will default to "username",
|
||||
unless usernameExpression is specified.
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
usernameExpression:
|
||||
description: |-
|
||||
usernameExpression represents an expression which will be evaluated by CEL.
|
||||
The expression's result will become the user's username.
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
|
||||
The expression must produce a non-empty string value.
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
the 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'.
|
||||
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.
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
- 'claims' is a map of claim names to claim values.
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to
|
||||
determine the user's username from the JWT token.
|
||||
type: string
|
||||
type: object
|
||||
issuer:
|
||||
description: |-
|
||||
Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
also used to validate the "iss" JWT claim.
|
||||
minLength: 1
|
||||
pattern: ^https://
|
||||
type: string
|
||||
tls:
|
||||
description: TLS configuration for communicating with the OIDC provider.
|
||||
description: tls is the configuration for communicating with the OIDC
|
||||
provider via TLS.
|
||||
properties:
|
||||
certificateAuthorityData:
|
||||
description: X.509 Certificate Authority (base64-encoded PEM bundle).
|
||||
@@ -128,12 +310,47 @@ spec:
|
||||
- name
|
||||
type: object
|
||||
type: object
|
||||
userValidationRules:
|
||||
description: |-
|
||||
userValidationRules are rules that are applied to final user before completing authentication.
|
||||
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.
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
configuration will cause the user's login to fail.
|
||||
items:
|
||||
description: UserValidationRule provides the configuration for a
|
||||
single user info validation rule.
|
||||
properties:
|
||||
expression:
|
||||
description: |-
|
||||
expression represents the expression which will be evaluated by CEL.
|
||||
Must return true for the validation to pass.
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
type: string
|
||||
message:
|
||||
description: |-
|
||||
message customizes the returned error message when rule returns false.
|
||||
message is a literal string.
|
||||
type: string
|
||||
required:
|
||||
- expression
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- audience
|
||||
- issuer
|
||||
type: object
|
||||
status:
|
||||
description: Status of the authenticator.
|
||||
description: status of the authenticator.
|
||||
properties:
|
||||
conditions:
|
||||
description: Represents the observations of the authenticator's current
|
||||
|
||||
229
generated/latest/README.adoc
generated
229
generated/latest/README.adoc
generated
@@ -60,6 +60,78 @@ certificate bundle. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-claimvalidationrule"]
|
||||
==== ClaimValidationRule
|
||||
|
||||
ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`claim`* __string__ | claim is the name of a required claim. +
|
||||
Only string claim keys are supported. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`requiredValue`* __string__ | requiredValue is the value of a required claim. +
|
||||
Only string claim values are supported. +
|
||||
If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string. +
|
||||
Mutually exclusive with expression and message. +
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must produce a boolean. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
| *`message`* __string__ | message customizes the returned error message when expression returns false. +
|
||||
message is a literal string. +
|
||||
Mutually exclusive with claim and requiredValue. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-extramapping"]
|
||||
==== ExtraMapping
|
||||
|
||||
ExtraMapping provides the configuration for a single extra mapping.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`key`* __string__ | key is a string to use as the extra attribute key. +
|
||||
key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid +
|
||||
subdomain as defined by RFC 1123. All characters trailing the first "/" must +
|
||||
be valid HTTP Path characters as defined by RFC 3986. +
|
||||
key must be lowercase. +
|
||||
Required to be unique. +
|
||||
Additionally, the key must not contain an equals sign ("="). +
|
||||
| *`valueExpression`* __string__ | valueExpression is a CEL expression to extract extra attribute value. +
|
||||
valueExpression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the extra mapping not being present. +
|
||||
Empty string values contained within a string array are filtered out. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticator"]
|
||||
==== JWTAuthenticator
|
||||
|
||||
@@ -78,8 +150,8 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
| Field | Description
|
||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | Spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | Status of the authenticator. +
|
||||
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]__ | spec for configuring the authenticator. +
|
||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus[$$JWTAuthenticatorStatus$$]__ | status of the authenticator. +
|
||||
|===
|
||||
|
||||
|
||||
@@ -100,7 +172,7 @@ signature, existence of claims, etc.) and extract the username and groups from t
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec"]
|
||||
==== JWTAuthenticatorSpec
|
||||
|
||||
Spec for configuring a JWT authenticator.
|
||||
JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -110,19 +182,32 @@ Spec for configuring a JWT authenticator.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
| *`issuer`* __string__ | issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is +
|
||||
also used to validate the "iss" JWT claim. +
|
||||
| *`audience`* __string__ | Audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | Claims allows customization of the claims that will be mapped to user identity +
|
||||
| *`audience`* __string__ | audience is the required value of the "aud" JWT claim. +
|
||||
| *`claims`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwttokenclaims[$$JWTTokenClaims$$]__ | claims allows customization of the claims that will be mapped to user identity +
|
||||
for Kubernetes access. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | TLS configuration for communicating with the OIDC provider. +
|
||||
| *`claimValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-claimvalidationrule[$$ClaimValidationRule$$] array__ | claimValidationRules are rules that are applied to validate token claims to authenticate users. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`userValidationRules`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-uservalidationrule[$$UserValidationRule$$] array__ | userValidationRules are rules that are applied to final user before completing authentication. +
|
||||
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. +
|
||||
The validation rules are logically ANDed together and must all return true for the validation to pass. +
|
||||
This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, mistakes in this +
|
||||
configuration will cause the user's login to fail. +
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-tlsspec[$$TLSSpec$$]__ | tls is the configuration for communicating with the OIDC provider via TLS. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorstatus"]
|
||||
==== JWTAuthenticatorStatus
|
||||
|
||||
Status of a JWT authenticator.
|
||||
JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
@@ -151,10 +236,103 @@ for Kubernetes access.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`groups`* __string__ | Groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups". +
|
||||
| *`username`* __string__ | Username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username". +
|
||||
| *`username`* __string__ | username is the name of the claim which should be read to extract the +
|
||||
username from the JWT token. When not specified, it will default to "username", +
|
||||
unless usernameExpression is specified. +
|
||||
|
||||
Mutually exclusive with usernameExpression. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`usernameExpression`* __string__ | usernameExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's username. +
|
||||
|
||||
usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to the expected type without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended usernames. +
|
||||
|
||||
The expression must produce a non-empty string value. +
|
||||
If the expression uses 'claims.email', then 'claims.email_verified' must be used in +
|
||||
the 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'. +
|
||||
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. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with username. Use either username or usernameExpression to +
|
||||
determine the user's username from the JWT token. +
|
||||
| *`groups`* __string__ | groups is the name of the claim which should be read to extract the user's +
|
||||
group membership from the JWT token. When not specified, it will default to "groups", +
|
||||
unless groupsExpression is specified. +
|
||||
|
||||
Mutually exclusive with groupsExpression. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`groupsExpression`* __string__ | groupsExpression represents an expression which will be evaluated by CEL. +
|
||||
The expression's result will become the user's group memberships. +
|
||||
|
||||
groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to one of the expected types without errors, or else the user's login will fail. +
|
||||
Additionally, mistakes in this configuration can cause the users to have unintended group memberships. +
|
||||
|
||||
The expression must produce a string or string array value. +
|
||||
"", [], and null values are treated as the group mapping not being present. +
|
||||
|
||||
CEL expressions have access to the contents of the token claims, organized into CEL variable: +
|
||||
- 'claims' is a map of claim names to claim values. +
|
||||
For example, a variable named 'sub' can be accessed as 'claims.sub'. +
|
||||
Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
Mutually exclusive with groups. Use either groups or groupsExpression to +
|
||||
determine the user's group membership from the JWT token. +
|
||||
| *`extra`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-extramapping[$$ExtraMapping$$] array__ | extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration +
|
||||
as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication. +
|
||||
|
||||
However, note that the Pinniped Concierge issues client certificates to users for the purpose +
|
||||
of authenticating, and the Kubernetes API server does not have any mechanism for transmitting +
|
||||
auth extras via client certificates. When configured, these extras will appear in client +
|
||||
certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational +
|
||||
Units (OU). However, when this client certificate is presented to Kubernetes for authentication, +
|
||||
Kubernetes will ignore these extras. This is probably only useful if you are using a custom +
|
||||
authenticating proxy in front of your Kubernetes API server which can translate these OUs into +
|
||||
auth extras, as described by +
|
||||
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy. +
|
||||
This is an advanced configuration option. During an end-user login flow, each of these CEL expressions +
|
||||
must evaluate to either a string or an array of strings, or else the user's login will fail. +
|
||||
|
||||
These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("="). +
|
||||
|
||||
expression must produce a string or string array value. +
|
||||
If the value is empty, the extra mapping will not be present. +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
|
||||
hard-coded extra key/value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "'bar'" +
|
||||
This will result in an extra attribute - acme.io/foo: ["bar"] +
|
||||
|
||||
hard-coded key, value copying claim value +
|
||||
- key: "acme.io/foo" +
|
||||
valueExpression: "claims.some_claim" +
|
||||
This will result in an extra attribute - acme.io/foo: [value of some_claim] +
|
||||
|
||||
hard-coded key, value derived from claim value +
|
||||
- key: "acme.io/admin" +
|
||||
valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""' +
|
||||
This will result in: +
|
||||
- if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"] +
|
||||
- if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added +
|
||||
|===
|
||||
|
||||
|
||||
@@ -178,6 +356,33 @@ Any changes to the CA bundle in the secret or configmap will be dynamically relo
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-uservalidationrule"]
|
||||
==== UserValidationRule
|
||||
|
||||
UserValidationRule provides the configuration for a single user info validation rule.
|
||||
|
||||
.Appears In:
|
||||
****
|
||||
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-jwtauthenticatorspec[$$JWTAuthenticatorSpec$$]
|
||||
****
|
||||
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`expression`* __string__ | expression represents the expression which will be evaluated by CEL. +
|
||||
Must return true for the validation to pass. +
|
||||
|
||||
CEL expressions have access to the contents of UserInfo, organized into CEL variable: +
|
||||
- 'user' - authentication.k8s.io/v1, Kind=UserInfo object +
|
||||
Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition. +
|
||||
API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io +
|
||||
|
||||
Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/ +
|
||||
| *`message`* __string__ | message customizes the returned error message when rule returns false. +
|
||||
message is a literal string. +
|
||||
|===
|
||||
|
||||
|
||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-33-apis-concierge-authentication-v1alpha1-webhookauthenticator"]
|
||||
==== WebhookAuthenticator
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
JWTAuthenticatorPhaseError JWTAuthenticatorPhase = "Error"
|
||||
)
|
||||
|
||||
// Status of a JWT authenticator.
|
||||
// JWTAuthenticatorStatus is the status of a JWT authenticator.
|
||||
type JWTAuthenticatorStatus struct {
|
||||
// Represents the observations of the authenticator's current state.
|
||||
// +patchMergeKey=type
|
||||
@@ -26,46 +26,255 @@ type JWTAuthenticatorStatus struct {
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||
|
||||
// Phase summarizes the overall status of the JWTAuthenticator.
|
||||
// +kubebuilder:default=Pending
|
||||
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||
Phase JWTAuthenticatorPhase `json:"phase,omitempty"`
|
||||
}
|
||||
|
||||
// Spec for configuring a JWT authenticator.
|
||||
// JWTAuthenticatorSpec is the spec for configuring a JWT authenticator.
|
||||
type JWTAuthenticatorSpec struct {
|
||||
// Issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// issuer is the OIDC issuer URL that will be used to discover public signing keys. Issuer is
|
||||
// also used to validate the "iss" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:Pattern=`^https://`
|
||||
Issuer string `json:"issuer"`
|
||||
|
||||
// Audience is the required value of the "aud" JWT claim.
|
||||
// audience is the required value of the "aud" JWT claim.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
Audience string `json:"audience"`
|
||||
|
||||
// Claims allows customization of the claims that will be mapped to user identity
|
||||
// claims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
// +optional
|
||||
Claims JWTTokenClaims `json:"claims"`
|
||||
|
||||
// TLS configuration for communicating with the OIDC provider.
|
||||
// claimValidationRules are rules that are applied to validate token claims to authenticate users.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
ClaimValidationRules []ClaimValidationRule `json:"claimValidationRules,omitempty"`
|
||||
|
||||
// userValidationRules are rules that are applied to final user before completing authentication.
|
||||
// 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.
|
||||
// The validation rules are logically ANDed together and must all return true for the validation to pass.
|
||||
// This is similar to claimValidationRules from Kubernetes AuthenticationConfiguration as documented in
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, mistakes in this
|
||||
// configuration will cause the user's login to fail.
|
||||
// +optional
|
||||
UserValidationRules []UserValidationRule `json:"userValidationRules,omitempty"`
|
||||
|
||||
// tls is the configuration for communicating with the OIDC provider via TLS.
|
||||
// +optional
|
||||
TLS *TLSSpec `json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// ClaimValidationRule provides the configuration for a single claim validation rule.
|
||||
type ClaimValidationRule struct {
|
||||
// claim is the name of a required claim.
|
||||
// Only string claim keys are supported.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
Claim string `json:"claim,omitempty"`
|
||||
|
||||
// requiredValue is the value of a required claim.
|
||||
// Only string claim values are supported.
|
||||
// If claim is set and requiredValue is not set, the claim must be present with a value set to the empty string.
|
||||
// Mutually exclusive with expression and message.
|
||||
// +optional
|
||||
RequiredValue string `json:"requiredValue,omitempty"`
|
||||
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must produce a boolean.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Expression string `json:"expression,omitempty"`
|
||||
|
||||
// message customizes the returned error message when expression returns false.
|
||||
// message is a literal string.
|
||||
// Mutually exclusive with claim and requiredValue.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// UserValidationRule provides the configuration for a single user info validation rule.
|
||||
type UserValidationRule struct {
|
||||
// expression represents the expression which will be evaluated by CEL.
|
||||
// Must return true for the validation to pass.
|
||||
//
|
||||
// CEL expressions have access to the contents of UserInfo, organized into CEL variable:
|
||||
// - 'user' - authentication.k8s.io/v1, Kind=UserInfo object
|
||||
// Refer to https://github.com/kubernetes/api/blob/release-1.28/authentication/v1/types.go#L105-L122 for the definition.
|
||||
// API documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#userinfo-v1-authentication-k8s-io
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
Expression string `json:"expression"`
|
||||
|
||||
// message customizes the returned error message when rule returns false.
|
||||
// message is a literal string.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// JWTTokenClaims allows customization of the claims that will be mapped to user identity
|
||||
// for Kubernetes access.
|
||||
type JWTTokenClaims struct {
|
||||
// Groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups".
|
||||
// username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username",
|
||||
// unless usernameExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with usernameExpression. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
|
||||
// usernameExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's username.
|
||||
//
|
||||
// usernameExpression is similar to claimMappings.username.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to the expected type without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended usernames.
|
||||
//
|
||||
// The expression must produce a non-empty string value.
|
||||
// If the expression uses 'claims.email', then 'claims.email_verified' must be used in
|
||||
// the 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'.
|
||||
// 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.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with username. Use either username or usernameExpression to
|
||||
// determine the user's username from the JWT token.
|
||||
// +optional
|
||||
UsernameExpression string `json:"usernameExpression,omitempty"`
|
||||
|
||||
// groups is the name of the claim which should be read to extract the user's
|
||||
// group membership from the JWT token. When not specified, it will default to "groups",
|
||||
// unless groupsExpression is specified.
|
||||
//
|
||||
// Mutually exclusive with groupsExpression. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Groups string `json:"groups"`
|
||||
|
||||
// Username is the name of the claim which should be read to extract the
|
||||
// username from the JWT token. When not specified, it will default to "username".
|
||||
// groupsExpression represents an expression which will be evaluated by CEL.
|
||||
// The expression's result will become the user's group memberships.
|
||||
//
|
||||
// groupsExpression is similar to claimMappings.groups.expression from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to one of the expected types without errors, or else the user's login will fail.
|
||||
// Additionally, mistakes in this configuration can cause the users to have unintended group memberships.
|
||||
//
|
||||
// The expression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the group mapping not being present.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// Mutually exclusive with groups. Use either groups or groupsExpression to
|
||||
// determine the user's group membership from the JWT token.
|
||||
// +optional
|
||||
Username string `json:"username"`
|
||||
GroupsExpression string `json:"groupsExpression,omitempty"`
|
||||
|
||||
// extra is similar to claimMappings.extra from Kubernetes AuthenticationConfiguration
|
||||
// as documented in https://kubernetes.io/docs/reference/access-authn-authz/authentication.
|
||||
//
|
||||
// However, note that the Pinniped Concierge issues client certificates to users for the purpose
|
||||
// of authenticating, and the Kubernetes API server does not have any mechanism for transmitting
|
||||
// auth extras via client certificates. When configured, these extras will appear in client
|
||||
// certificates issued by the Pinniped Supervisor in the x509 Subject field as Organizational
|
||||
// Units (OU). However, when this client certificate is presented to Kubernetes for authentication,
|
||||
// Kubernetes will ignore these extras. This is probably only useful if you are using a custom
|
||||
// authenticating proxy in front of your Kubernetes API server which can translate these OUs into
|
||||
// auth extras, as described by
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy.
|
||||
// This is an advanced configuration option. During an end-user login flow, each of these CEL expressions
|
||||
// must evaluate to either a string or an array of strings, or else the user's login will fail.
|
||||
//
|
||||
// These keys must be a domain-prefixed path (such as "acme.io/foo") and must not contain an equals sign ("=").
|
||||
//
|
||||
// expression must produce a string or string array value.
|
||||
// If the value is empty, the extra mapping will not be present.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// hard-coded extra key/value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "'bar'"
|
||||
// This will result in an extra attribute - acme.io/foo: ["bar"]
|
||||
//
|
||||
// hard-coded key, value copying claim value
|
||||
// - key: "acme.io/foo"
|
||||
// valueExpression: "claims.some_claim"
|
||||
// This will result in an extra attribute - acme.io/foo: [value of some_claim]
|
||||
//
|
||||
// hard-coded key, value derived from claim value
|
||||
// - key: "acme.io/admin"
|
||||
// valueExpression: '(has(claims.is_admin) && claims.is_admin) ? "true":""'
|
||||
// This will result in:
|
||||
// - if is_admin claim is present and true, extra attribute - acme.io/admin: ["true"]
|
||||
// - if is_admin claim is present and false or is_admin claim is not present, no extra attribute will be added
|
||||
//
|
||||
// +optional
|
||||
Extra []ExtraMapping `json:"extra,omitempty"`
|
||||
}
|
||||
|
||||
// ExtraMapping provides the configuration for a single extra mapping.
|
||||
type ExtraMapping struct {
|
||||
// key is a string to use as the extra attribute key.
|
||||
// key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
|
||||
// subdomain as defined by RFC 1123. All characters trailing the first "/" must
|
||||
// be valid HTTP Path characters as defined by RFC 3986.
|
||||
// key must be lowercase.
|
||||
// Required to be unique.
|
||||
// Additionally, the key must not contain an equals sign ("=").
|
||||
// +required
|
||||
Key string `json:"key"`
|
||||
|
||||
// valueExpression is a CEL expression to extract extra attribute value.
|
||||
// valueExpression must produce a string or string array value.
|
||||
// "", [], and null values are treated as the extra mapping not being present.
|
||||
// Empty string values contained within a string array are filtered out.
|
||||
//
|
||||
// CEL expressions have access to the contents of the token claims, organized into CEL variable:
|
||||
// - 'claims' is a map of claim names to claim values.
|
||||
// For example, a variable named 'sub' can be accessed as 'claims.sub'.
|
||||
// Nested claims can be accessed using dot notation, e.g. 'claims.foo.bar'.
|
||||
//
|
||||
// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
|
||||
//
|
||||
// +required
|
||||
ValueExpression string `json:"valueExpression"`
|
||||
}
|
||||
|
||||
// JWTAuthenticator describes the configuration of a JWT authenticator.
|
||||
@@ -86,14 +295,14 @@ type JWTAuthenticator struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec for configuring the authenticator.
|
||||
// spec for configuring the authenticator.
|
||||
Spec JWTAuthenticatorSpec `json:"spec"`
|
||||
|
||||
// Status of the authenticator.
|
||||
// status of the authenticator.
|
||||
Status JWTAuthenticatorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// List of JWTAuthenticator objects.
|
||||
// JWTAuthenticatorList is a list of JWTAuthenticator objects.
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type JWTAuthenticatorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
@@ -29,6 +29,38 @@ func (in *CertificateAuthorityDataSourceSpec) DeepCopy() *CertificateAuthorityDa
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClaimValidationRule) DeepCopyInto(out *ClaimValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClaimValidationRule.
|
||||
func (in *ClaimValidationRule) DeepCopy() *ClaimValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClaimValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExtraMapping) DeepCopyInto(out *ExtraMapping) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMapping.
|
||||
func (in *ExtraMapping) DeepCopy() *ExtraMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExtraMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticator) DeepCopyInto(out *JWTAuthenticator) {
|
||||
*out = *in
|
||||
@@ -93,7 +125,17 @@ func (in *JWTAuthenticatorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTAuthenticatorSpec) DeepCopyInto(out *JWTAuthenticatorSpec) {
|
||||
*out = *in
|
||||
out.Claims = in.Claims
|
||||
in.Claims.DeepCopyInto(&out.Claims)
|
||||
if in.ClaimValidationRules != nil {
|
||||
in, out := &in.ClaimValidationRules, &out.ClaimValidationRules
|
||||
*out = make([]ClaimValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.UserValidationRules != nil {
|
||||
in, out := &in.UserValidationRules, &out.UserValidationRules
|
||||
*out = make([]UserValidationRule, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.TLS != nil {
|
||||
in, out := &in.TLS, &out.TLS
|
||||
*out = new(TLSSpec)
|
||||
@@ -138,6 +180,11 @@ func (in *JWTAuthenticatorStatus) DeepCopy() *JWTAuthenticatorStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JWTTokenClaims) DeepCopyInto(out *JWTTokenClaims) {
|
||||
*out = *in
|
||||
if in.Extra != nil {
|
||||
in, out := &in.Extra, &out.Extra
|
||||
*out = make([]ExtraMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -172,6 +219,22 @@ func (in *TLSSpec) DeepCopy() *TLSSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserValidationRule) DeepCopyInto(out *UserValidationRule) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserValidationRule.
|
||||
func (in *UserValidationRule) DeepCopy() *UserValidationRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserValidationRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookAuthenticator) DeepCopyInto(out *WebhookAuthenticator) {
|
||||
*out = *in
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${ROOT}"
|
||||
|
||||
# Print the Go version.
|
||||
@@ -15,6 +15,17 @@ lint_version="v$(cat hack/lib/lint-version.txt)"
|
||||
|
||||
# Find the toolchain version from our go.mod file. "go install" pays attention to $GOTOOLCHAIN.
|
||||
GOTOOLCHAIN=$(sed -rn 's/^toolchain (go[0-9\.]+)$/\1/p' go.mod)
|
||||
if [[ -z "$GOTOOLCHAIN" ]]; then
|
||||
# Did not find toolchain directive. The directive is not needed in a go.mod file when it would be the same
|
||||
# version as the go directive, so it will not always be there. Try using go directive instead.
|
||||
GOTOOLCHAIN=$(sed -rn 's/^go ([0-9]+\.[0-9]+\.[0-9]+)$/\1/p' go.mod)
|
||||
if [[ -z "$GOTOOLCHAIN" ]]; then
|
||||
echo "ERROR: Could not find Go patch version from go.mod file."
|
||||
exit 1
|
||||
fi
|
||||
GOTOOLCHAIN="go${GOTOOLCHAIN}"
|
||||
fi
|
||||
|
||||
export GOTOOLCHAIN
|
||||
|
||||
echo "Installing golangci-lint@${lint_version} using toolchain ${GOTOOLCHAIN}"
|
||||
@@ -22,6 +33,9 @@ echo "Installing golangci-lint@${lint_version} using toolchain ${GOTOOLCHAIN}"
|
||||
# Install the same version of the linter that the pipelines will use
|
||||
# so you can get the same results when running the linter locally.
|
||||
go install -v "github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${lint_version}"
|
||||
|
||||
echo "Finished installing golangci-lint@${lint_version} using toolchain ${GOTOOLCHAIN}"
|
||||
|
||||
golangci-lint --version
|
||||
|
||||
echo "Finished. You may need to run 'rehash' in your current shell before using the new version (e.g. if you are using gvm)."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
# Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#
|
||||
@@ -535,6 +535,9 @@ export PINNIPED_TEST_CLI_OIDC_CLIENT_ID=pinniped-cli
|
||||
export PINNIPED_TEST_CLI_OIDC_CALLBACK_URL=http://127.0.0.1:48095/callback
|
||||
export PINNIPED_TEST_CLI_OIDC_USERNAME=pinny@example.com
|
||||
export PINNIPED_TEST_CLI_OIDC_PASSWORD=${dex_test_password}
|
||||
export PINNIPED_TEST_CLI_OIDC_USERNAME_CLAIM=email
|
||||
export PINNIPED_TEST_CLI_OIDC_GROUPS_CLAIM=groups
|
||||
export PINNIPED_TEST_CLI_OIDC_EXPECTED_GROUPS= # Dex's local user store does not let us configure groups.
|
||||
export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_ISSUER=https://dex.tools.svc.cluster.local/dex
|
||||
export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_ISSUER_CA_BUNDLE="${test_ca_bundle_pem}"
|
||||
export PINNIPED_TEST_SUPERVISOR_UPSTREAM_OIDC_ADDITIONAL_SCOPES="offline_access,email"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package certauthority implements a simple x509 certificate authority suitable for use in an aggregated API service.
|
||||
@@ -170,8 +170,8 @@ func (c *CA) Pool() *x509.CertPool {
|
||||
|
||||
// IssueClientCert issues a new client certificate with username and groups included in the Kube-style
|
||||
// certificate subject for the given identity and duration.
|
||||
func (c *CA) IssueClientCert(username string, groups []string, ttl time.Duration) (*tls.Certificate, error) {
|
||||
return c.issueCert(x509.ExtKeyUsageClientAuth, pkix.Name{CommonName: username, Organization: groups}, nil, nil, ttl)
|
||||
func (c *CA) IssueClientCert(username string, groups []string, extras []string, ttl time.Duration) (*tls.Certificate, error) {
|
||||
return c.issueCert(x509.ExtKeyUsageClientAuth, pkix.Name{CommonName: username, Organization: groups, OrganizationalUnit: extras}, nil, nil, ttl)
|
||||
}
|
||||
|
||||
// IssueServerCert issues a new server certificate for the given identity and duration.
|
||||
@@ -182,8 +182,8 @@ func (c *CA) IssueServerCert(dnsNames []string, ips []net.IP, ttl time.Duration)
|
||||
|
||||
// IssueClientCertPEM is similar to IssueClientCert, but returns the new cert as a pair of PEM-formatted byte slices
|
||||
// for the certificate and private key, along with the notBefore and notAfter values.
|
||||
func (c *CA) IssueClientCertPEM(username string, groups []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
return toPEM(c.IssueClientCert(username, groups, ttl))
|
||||
func (c *CA) IssueClientCertPEM(username string, groups []string, extras []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
return toPEM(c.IssueClientCert(username, groups, extras, ttl))
|
||||
}
|
||||
|
||||
// IssueServerCertPEM is similar to IssueServerCert, but returns the new cert as a pair of PEM-formatted byte slices
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package certauthority
|
||||
@@ -326,7 +326,7 @@ func TestIssue(t *testing.T) {
|
||||
require.Equal(t, now.Add(-5*time.Minute), got.Leaf.NotBefore) // always back-dated
|
||||
require.Equal(t, now.Add(10*time.Minute), got.Leaf.NotAfter)
|
||||
}
|
||||
got, err = tt.ca.IssueClientCert("test-user", []string{"group1", "group2"}, 10*time.Minute)
|
||||
got, err = tt.ca.IssueClientCert("test-user", []string{"group1", "group2"}, []string{"extra1=val1", "extra2=val2"}, 10*time.Minute)
|
||||
if tt.wantErr != "" {
|
||||
require.EqualError(t, err, tt.wantErr)
|
||||
require.Nil(t, got)
|
||||
@@ -378,28 +378,29 @@ func TestIssueMethods(t *testing.T) {
|
||||
t.Run("client certs", func(t *testing.T) {
|
||||
user := "test-username"
|
||||
groups := []string{"group1", "group2"}
|
||||
extras := []string{"extra1=val1", "extra2=val2"}
|
||||
|
||||
clientCert, err := ca.IssueClientCert(user, groups, ttl)
|
||||
clientCert, err := ca.IssueClientCert(user, groups, extras, ttl)
|
||||
require.NoError(t, err)
|
||||
certPEM, keyPEM, err := ToPEM(clientCert)
|
||||
require.NoError(t, err)
|
||||
validateClientCert(t, ca.Bundle(), certPEM, keyPEM, user, groups, ttl)
|
||||
validateClientCert(t, ca.Bundle(), certPEM, keyPEM, user, groups, extras, ttl)
|
||||
|
||||
pem, err := ca.IssueClientCertPEM(user, groups, ttl)
|
||||
pem, err := ca.IssueClientCertPEM(user, groups, extras, ttl)
|
||||
require.NoError(t, err)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, user, groups, ttl)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, user, groups, extras, ttl)
|
||||
|
||||
pem, err = ca.IssueClientCertPEM(user, nil, ttl)
|
||||
pem, err = ca.IssueClientCertPEM(user, nil, nil, ttl)
|
||||
require.NoError(t, err)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, user, nil, ttl)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, user, nil, nil, ttl)
|
||||
|
||||
pem, err = ca.IssueClientCertPEM(user, []string{}, ttl)
|
||||
pem, err = ca.IssueClientCertPEM(user, []string{}, []string{}, ttl)
|
||||
require.NoError(t, err)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, user, nil, ttl)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, user, nil, nil, ttl)
|
||||
|
||||
pem, err = ca.IssueClientCertPEM("", []string{}, ttl)
|
||||
pem, err = ca.IssueClientCertPEM("", []string{}, []string{}, ttl)
|
||||
require.NoError(t, err)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, "", nil, ttl)
|
||||
validateClientCert(t, ca.Bundle(), pem.CertPEM, pem.KeyPEM, "", nil, nil, ttl)
|
||||
})
|
||||
|
||||
t.Run("server certs", func(t *testing.T) {
|
||||
@@ -434,13 +435,14 @@ func TestIssueMethods(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func validateClientCert(t *testing.T, caBundle []byte, certPEM []byte, keyPEM []byte, expectedUser string, expectedGroups []string, expectedTTL time.Duration) {
|
||||
func validateClientCert(t *testing.T, caBundle []byte, certPEM []byte, keyPEM []byte, expectedUser string, expectedGroups []string, expectedExtras []string, expectedTTL time.Duration) {
|
||||
const fudgeFactor = 10 * time.Second
|
||||
v := testutil.ValidateClientCertificate(t, string(caBundle), string(certPEM))
|
||||
v.RequireLifetime(time.Now(), time.Now().Add(expectedTTL), certBackdate+fudgeFactor)
|
||||
v.RequireMatchesPrivateKey(string(keyPEM))
|
||||
v.RequireCommonName(expectedUser)
|
||||
v.RequireOrganizations(expectedGroups)
|
||||
v.RequireOrganizationalUnits(expectedExtras)
|
||||
v.RequireEmptyDNSNames()
|
||||
v.RequireEmptyIPs()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package dynamiccertauthority implements a x509 certificate authority capable of issuing
|
||||
@@ -34,7 +34,7 @@ func (c *ca) Name() string {
|
||||
|
||||
// IssueClientCertPEM issues a new client certificate for the given identity and duration, returning it as a
|
||||
// pair of PEM-formatted byte slices for the certificate and private key, along with the notBefore and notAfter values.
|
||||
func (c *ca) IssueClientCertPEM(username string, groups []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
func (c *ca) IssueClientCertPEM(username string, groups []string, extras []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
caCrtPEM, caKeyPEM := c.provider.CurrentCertKeyContent()
|
||||
// in the future we could split dynamiccert.Private into two interfaces (Private and PrivateRead)
|
||||
// and have this code take PrivateRead as input. We would then add ourselves as a listener to
|
||||
@@ -44,5 +44,5 @@ func (c *ca) IssueClientCertPEM(username string, groups []string, ttl time.Durat
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ca.IssueClientCertPEM(username, groups, ttl)
|
||||
return ca.IssueClientCertPEM(username, groups, extras, ttl)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package dynamiccertauthority
|
||||
@@ -91,8 +91,7 @@ func TestCAIssuePEM(t *testing.T) {
|
||||
}
|
||||
for _, step := range steps {
|
||||
t.Run(step.name, func(t *testing.T) {
|
||||
// Can't run these steps in parallel, because each one depends on the previous steps being
|
||||
// run.
|
||||
// Can't run these steps in parallel, because each one depends on the previous steps being run.
|
||||
|
||||
pem, err := issuePEM(provider, ca, step.caCrtPEM, step.caKeyPEM)
|
||||
|
||||
@@ -108,6 +107,7 @@ func TestCAIssuePEM(t *testing.T) {
|
||||
crtAssertions := testutil.ValidateClientCertificate(t, string(caCrtPEM), string(pem.CertPEM))
|
||||
crtAssertions.RequireCommonName("some-username")
|
||||
crtAssertions.RequireOrganizations([]string{"some-group1", "some-group2"})
|
||||
crtAssertions.RequireOrganizationalUnits([]string{"extra1=val1", "extra2=val2"})
|
||||
crtAssertions.RequireLifetime(time.Now(), time.Now().Add(time.Hour*24), time.Minute*10)
|
||||
crtAssertions.RequireMatchesPrivateKey(string(pem.KeyPEM))
|
||||
}
|
||||
@@ -124,5 +124,10 @@ func issuePEM(provider dynamiccert.Provider, ca clientcertissuer.ClientCertIssue
|
||||
}
|
||||
|
||||
// otherwise check to see if there is an issuing error
|
||||
return ca.IssueClientCertPEM("some-username", []string{"some-group1", "some-group2"}, time.Hour*24)
|
||||
return ca.IssueClientCertPEM(
|
||||
"some-username",
|
||||
[]string{"some-group1", "some-group2"},
|
||||
[]string{"extra1=val1", "extra2=val2"},
|
||||
time.Hour*24,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2021-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package clientcertissuer
|
||||
@@ -18,7 +18,7 @@ const defaultCertIssuerErr = constable.Error("failed to issue cert")
|
||||
|
||||
type ClientCertIssuer interface {
|
||||
Name() string
|
||||
IssueClientCertPEM(username string, groups []string, ttl time.Duration) (pem *cert.PEM, err error)
|
||||
IssueClientCertPEM(username string, groups []string, extras []string, ttl time.Duration) (pem *cert.PEM, err error)
|
||||
}
|
||||
|
||||
var _ ClientCertIssuer = ClientCertIssuers{}
|
||||
@@ -38,11 +38,11 @@ func (c ClientCertIssuers) Name() string {
|
||||
return strings.Join(names, ",")
|
||||
}
|
||||
|
||||
func (c ClientCertIssuers) IssueClientCertPEM(username string, groups []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
func (c ClientCertIssuers) IssueClientCertPEM(username string, groups []string, extras []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
errs := make([]error, 0, len(c))
|
||||
|
||||
for _, issuer := range c {
|
||||
pem, err := issuer.IssueClientCertPEM(username, groups, ttl)
|
||||
pem, err := issuer.IssueClientCertPEM(username, groups, extras, ttl)
|
||||
if err == nil {
|
||||
return pem, nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2023-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package clientcertissuer
|
||||
@@ -67,6 +67,11 @@ func TestName(t *testing.T) {
|
||||
func TestIssueClientCertPEM(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
username := "test-username"
|
||||
groups := []string{"group1", "group2"}
|
||||
extras := []string{"extra1=val1", "extra2=val2"}
|
||||
ttl := 32 * time.Second
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
buildIssuerMocks func() ClientCertIssuers
|
||||
@@ -85,7 +90,7 @@ func TestIssueClientCertPEM(t *testing.T) {
|
||||
errClientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
errClientCertIssuer.EXPECT().Name().Return("error cert issuer")
|
||||
errClientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM("username", []string{"group1", "group2"}, 32*time.Second).
|
||||
IssueClientCertPEM(username, groups, extras, ttl).
|
||||
Return(nil, errors.New("error from wrapped cert issuer"))
|
||||
return ClientCertIssuers{errClientCertIssuer}
|
||||
},
|
||||
@@ -96,7 +101,7 @@ func TestIssueClientCertPEM(t *testing.T) {
|
||||
buildIssuerMocks: func() ClientCertIssuers {
|
||||
validClientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
validClientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM("username", []string{"group1", "group2"}, 32*time.Second).
|
||||
IssueClientCertPEM(username, groups, extras, ttl).
|
||||
Return(&cert.PEM{CertPEM: []byte("cert"), KeyPEM: []byte("key")}, nil)
|
||||
return ClientCertIssuers{validClientCertIssuer}
|
||||
},
|
||||
@@ -109,12 +114,12 @@ func TestIssueClientCertPEM(t *testing.T) {
|
||||
errClientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
errClientCertIssuer.EXPECT().Name().Return("error cert issuer")
|
||||
errClientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM("username", []string{"group1", "group2"}, 32*time.Second).
|
||||
IssueClientCertPEM(username, groups, extras, ttl).
|
||||
Return(nil, errors.New("error from wrapped cert issuer"))
|
||||
|
||||
validClientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
validClientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM("username", []string{"group1", "group2"}, 32*time.Second).
|
||||
IssueClientCertPEM(username, groups, extras, ttl).
|
||||
Return(&cert.PEM{CertPEM: []byte("cert"), KeyPEM: []byte("key")}, nil)
|
||||
return ClientCertIssuers{
|
||||
errClientCertIssuer,
|
||||
@@ -130,13 +135,13 @@ func TestIssueClientCertPEM(t *testing.T) {
|
||||
err1ClientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
err1ClientCertIssuer.EXPECT().Name().Return("error1 cert issuer")
|
||||
err1ClientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM("username", []string{"group1", "group2"}, 32*time.Second).
|
||||
IssueClientCertPEM(username, groups, extras, ttl).
|
||||
Return(nil, errors.New("error1 from wrapped cert issuer"))
|
||||
|
||||
err2ClientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
err2ClientCertIssuer.EXPECT().Name().Return("error2 cert issuer")
|
||||
err2ClientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM("username", []string{"group1", "group2"}, 32*time.Second).
|
||||
IssueClientCertPEM(username, groups, extras, ttl).
|
||||
Return(nil, errors.New("error2 from wrapped cert issuer"))
|
||||
|
||||
return ClientCertIssuers{
|
||||
@@ -154,7 +159,7 @@ func TestIssueClientCertPEM(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pem, err := testcase.buildIssuerMocks().
|
||||
IssueClientCertPEM("username", []string{"group1", "group2"}, 32*time.Second)
|
||||
IssueClientCertPEM(username, groups, extras, ttl)
|
||||
|
||||
if testcase.wantErrorMessage != "" {
|
||||
require.ErrorContains(t, err, testcase.wantErrorMessage)
|
||||
|
||||
@@ -2579,7 +2579,7 @@ type clientCert struct {
|
||||
|
||||
func newClientCert(t *testing.T, ca *certauthority.CA, username string, groups []string) clientCert {
|
||||
t.Helper()
|
||||
clientCertPEM, err := ca.IssueClientCertPEM(username, groups, time.Hour)
|
||||
clientCertPEM, err := ca.IssueClientCertPEM(username, groups, nil, time.Hour)
|
||||
require.NoError(t, err)
|
||||
return clientCert{
|
||||
certPEM: clientCertPEM.CertPEM,
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright 2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package jwtcachefiller
|
||||
|
||||
import (
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
||||
)
|
||||
|
||||
// convertJWTAuthenticatorSpecType converts a Pinniped CRD spec type into the very similar
|
||||
// Kubernetes library apiserver.JWTAuthenticator type. It applies a default value for username and group claims,
|
||||
// but is otherwise a straight conversion. The Pinniped type includes TLS configuration which does not need
|
||||
// to be converted because that is applied elsewhere.
|
||||
func convertJWTAuthenticatorSpecType(spec *authenticationv1alpha1.JWTAuthenticatorSpec) apiserver.JWTAuthenticator {
|
||||
return apiserver.JWTAuthenticator{
|
||||
Issuer: convertIssuerType(spec),
|
||||
ClaimMappings: convertClaimMappingsType(spec.Claims),
|
||||
ClaimValidationRules: convertClaimValidationRulesType(spec.ClaimValidationRules),
|
||||
UserValidationRules: convertUserValidationRulesType(spec.UserValidationRules),
|
||||
}
|
||||
}
|
||||
|
||||
func convertIssuerType(spec *authenticationv1alpha1.JWTAuthenticatorSpec) apiserver.Issuer {
|
||||
var aud []string
|
||||
if len(spec.Audience) > 0 {
|
||||
aud = []string{spec.Audience}
|
||||
}
|
||||
|
||||
return apiserver.Issuer{
|
||||
URL: spec.Issuer,
|
||||
Audiences: aud,
|
||||
}
|
||||
}
|
||||
|
||||
func convertClaimMappingsType(claims authenticationv1alpha1.JWTTokenClaims) apiserver.ClaimMappings {
|
||||
usernameClaim := claims.Username
|
||||
if usernameClaim == "" && claims.UsernameExpression == "" {
|
||||
usernameClaim = defaultUsernameClaim
|
||||
}
|
||||
|
||||
var usernamePrefix *string
|
||||
if usernameClaim != "" {
|
||||
// Must be set only when username claim name is set.
|
||||
usernamePrefix = ptr.To("")
|
||||
}
|
||||
|
||||
groupsClaim := claims.Groups
|
||||
if groupsClaim == "" && claims.GroupsExpression == "" {
|
||||
groupsClaim = defaultGroupsClaim
|
||||
}
|
||||
|
||||
var groupsPrefix *string
|
||||
if groupsClaim != "" {
|
||||
// Must be set only when groups claim name is set.
|
||||
groupsPrefix = ptr.To("")
|
||||
}
|
||||
|
||||
return apiserver.ClaimMappings{
|
||||
Username: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: usernameClaim,
|
||||
Prefix: usernamePrefix,
|
||||
Expression: claims.UsernameExpression,
|
||||
},
|
||||
Groups: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: groupsClaim,
|
||||
Prefix: groupsPrefix,
|
||||
Expression: claims.GroupsExpression,
|
||||
},
|
||||
Extra: convertExtraType(claims.Extra),
|
||||
}
|
||||
}
|
||||
|
||||
func convertUserValidationRulesType(rules []authenticationv1alpha1.UserValidationRule) []apiserver.UserValidationRule {
|
||||
if len(rules) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
apiServerRules := make([]apiserver.UserValidationRule, len(rules))
|
||||
|
||||
for i := range rules {
|
||||
apiServerRules[i] = apiserver.UserValidationRule{
|
||||
Expression: rules[i].Expression,
|
||||
Message: rules[i].Message,
|
||||
}
|
||||
}
|
||||
|
||||
return apiServerRules
|
||||
}
|
||||
|
||||
func convertClaimValidationRulesType(rules []authenticationv1alpha1.ClaimValidationRule) []apiserver.ClaimValidationRule {
|
||||
if len(rules) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
apiServerRules := make([]apiserver.ClaimValidationRule, len(rules))
|
||||
|
||||
for i := range rules {
|
||||
apiServerRules[i] = apiserver.ClaimValidationRule{
|
||||
Claim: rules[i].Claim,
|
||||
RequiredValue: rules[i].RequiredValue,
|
||||
Expression: rules[i].Expression,
|
||||
Message: rules[i].Message,
|
||||
}
|
||||
}
|
||||
|
||||
return apiServerRules
|
||||
}
|
||||
|
||||
func convertExtraType(extras []authenticationv1alpha1.ExtraMapping) []apiserver.ExtraMapping {
|
||||
if len(extras) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
apiServerExtras := make([]apiserver.ExtraMapping, len(extras))
|
||||
|
||||
for i := range extras {
|
||||
apiServerExtras[i] = apiserver.ExtraMapping{
|
||||
Key: extras[i].Key,
|
||||
ValueExpression: extras[i].ValueExpression,
|
||||
}
|
||||
}
|
||||
|
||||
return apiServerExtras
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
// Copyright 2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package jwtcachefiller
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
||||
)
|
||||
|
||||
func Test_convertJWTAuthenticatorSpecType(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
spec *authenticationv1alpha1.JWTAuthenticatorSpec
|
||||
want apiserver.JWTAuthenticator
|
||||
}{
|
||||
{
|
||||
name: "defaults the username and groups claims when the usernameExpression and groupExpression are not set",
|
||||
spec: &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: "https://example.com",
|
||||
},
|
||||
want: apiserver.JWTAuthenticator{
|
||||
Issuer: apiserver.Issuer{
|
||||
URL: "https://example.com",
|
||||
},
|
||||
ClaimMappings: apiserver.ClaimMappings{
|
||||
Username: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: "username",
|
||||
Prefix: ptr.To(""),
|
||||
},
|
||||
Groups: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: "groups",
|
||||
Prefix: ptr.To(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "does not default the username and groups claims an prefixes when the usernameExpression and groupExpression are set",
|
||||
spec: &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: "https://example.com",
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
UsernameExpression: `"foo"`,
|
||||
GroupsExpression: `["foo"]`,
|
||||
},
|
||||
},
|
||||
want: apiserver.JWTAuthenticator{
|
||||
Issuer: apiserver.Issuer{
|
||||
URL: "https://example.com",
|
||||
},
|
||||
ClaimMappings: apiserver.ClaimMappings{
|
||||
Username: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: "",
|
||||
Prefix: nil,
|
||||
Expression: `"foo"`,
|
||||
},
|
||||
Groups: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: "",
|
||||
Prefix: nil,
|
||||
Expression: `["foo"]`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "converts every field except for TLS",
|
||||
spec: &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: "https://example.com",
|
||||
Audience: "example-aud",
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Username: "some-username-claim",
|
||||
Groups: "some-groups-claim",
|
||||
Extra: []authenticationv1alpha1.ExtraMapping{
|
||||
{
|
||||
Key: "key1",
|
||||
ValueExpression: "expr1",
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
ValueExpression: "expr2",
|
||||
},
|
||||
},
|
||||
},
|
||||
ClaimValidationRules: []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Claim: "claim-claim1",
|
||||
RequiredValue: "claim-value1",
|
||||
Expression: "claim-expr1",
|
||||
Message: "claim-msg1",
|
||||
},
|
||||
{
|
||||
Claim: "claim-claim2",
|
||||
RequiredValue: "claim-value2",
|
||||
Expression: "claim-expr2",
|
||||
Message: "claim-msg2",
|
||||
},
|
||||
},
|
||||
UserValidationRules: []authenticationv1alpha1.UserValidationRule{
|
||||
{
|
||||
Expression: "user-expr1",
|
||||
Message: "user-msg1",
|
||||
},
|
||||
{
|
||||
Expression: "user-expr2",
|
||||
Message: "user-msg2",
|
||||
},
|
||||
},
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: "CA bundle value - does not need to be converted",
|
||||
},
|
||||
},
|
||||
want: apiserver.JWTAuthenticator{
|
||||
Issuer: apiserver.Issuer{
|
||||
URL: "https://example.com",
|
||||
Audiences: []string{"example-aud"},
|
||||
},
|
||||
ClaimMappings: apiserver.ClaimMappings{
|
||||
Username: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: "some-username-claim",
|
||||
Prefix: ptr.To(""),
|
||||
},
|
||||
Groups: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: "some-groups-claim",
|
||||
Prefix: ptr.To(""),
|
||||
},
|
||||
Extra: []apiserver.ExtraMapping{
|
||||
{
|
||||
Key: "key1",
|
||||
ValueExpression: "expr1",
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
ValueExpression: "expr2",
|
||||
},
|
||||
},
|
||||
},
|
||||
ClaimValidationRules: []apiserver.ClaimValidationRule{
|
||||
{
|
||||
Claim: "claim-claim1",
|
||||
RequiredValue: "claim-value1",
|
||||
Expression: "claim-expr1",
|
||||
Message: "claim-msg1",
|
||||
},
|
||||
{
|
||||
Claim: "claim-claim2",
|
||||
RequiredValue: "claim-value2",
|
||||
Expression: "claim-expr2",
|
||||
Message: "claim-msg2",
|
||||
},
|
||||
},
|
||||
UserValidationRules: []apiserver.UserValidationRule{
|
||||
{
|
||||
Expression: "user-expr1",
|
||||
Message: "user-msg1",
|
||||
},
|
||||
{
|
||||
Expression: "user-expr2",
|
||||
Message: "user-msg2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Equal(t, tt.want, convertJWTAuthenticatorSpecType(tt.spec))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package jwtcachefiller implements a controller for filling an authncache.Cache with each
|
||||
@@ -23,12 +23,14 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver/validation"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
authenticationcel "k8s.io/apiserver/pkg/authentication/cel"
|
||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/utils/clock"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
||||
oidcapi "go.pinniped.dev/generated/latest/apis/supervisor/oidc"
|
||||
@@ -108,11 +110,13 @@ type tokenAuthenticatorCloser interface {
|
||||
|
||||
type cachedJWTAuthenticator struct {
|
||||
authenticator.Token
|
||||
issuer string
|
||||
audience string
|
||||
claims authenticationv1alpha1.JWTTokenClaims
|
||||
caBundleHash tlsconfigutil.CABundleHash
|
||||
cancel context.CancelFunc
|
||||
issuer string
|
||||
audience string
|
||||
claims authenticationv1alpha1.JWTTokenClaims
|
||||
userValidationRules []authenticationv1alpha1.UserValidationRule
|
||||
claimValidationRules []authenticationv1alpha1.ClaimValidationRule
|
||||
caBundleHash tlsconfigutil.CABundleHash
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (c *cachedJWTAuthenticator) Close() {
|
||||
@@ -353,7 +357,9 @@ func (c *jwtCacheFillerController) havePreviouslyValidated(
|
||||
// If any spec field has changed, then we need a new in-memory authenticator.
|
||||
if authenticatorFromCache.issuer == spec.Issuer &&
|
||||
authenticatorFromCache.audience == spec.Audience &&
|
||||
authenticatorFromCache.claims == spec.Claims &&
|
||||
equality.Semantic.DeepEqual(authenticatorFromCache.claims, spec.Claims) &&
|
||||
equality.Semantic.DeepEqual(authenticatorFromCache.userValidationRules, spec.UserValidationRules) &&
|
||||
equality.Semantic.DeepEqual(authenticatorFromCache.claimValidationRules, spec.ClaimValidationRules) &&
|
||||
tlsBundleOk && // if there was any error while validating the latest CA bundle, then do not consider it previously validated
|
||||
authenticatorFromCache.caBundleHash.Equal(caBundleHash) {
|
||||
return true, true
|
||||
@@ -657,33 +663,51 @@ func (c *jwtCacheFillerController) newCachedJWTAuthenticator(
|
||||
return nil, conditions, nil
|
||||
}
|
||||
|
||||
usernameClaim := spec.Claims.Username
|
||||
if usernameClaim == "" {
|
||||
usernameClaim = defaultUsernameClaim
|
||||
apiServerJWTAuthenticator := convertJWTAuthenticatorSpecType(spec)
|
||||
|
||||
// Reuse the validation code from Kubernetes structured auth config. Most importantly,
|
||||
// this validates the claim mapping extras, claim validation rules, and user validation
|
||||
// rules for us.
|
||||
errList := validation.ValidateAuthenticationConfiguration(
|
||||
authenticationcel.NewDefaultCompiler(),
|
||||
&apiserver.AuthenticationConfiguration{JWT: []apiserver.JWTAuthenticator{apiServerJWTAuthenticator}},
|
||||
[]string{},
|
||||
)
|
||||
|
||||
// In addition to all the validations checked by ValidateAuthenticationConfiguration(),
|
||||
// we do not want to allow equal signs in key names. This is because we want to be able to
|
||||
// add the keyname to a client certificate's OU as "keyName=value".
|
||||
for i, mapping := range spec.Claims.Extra {
|
||||
if strings.Contains(mapping.Key, "=") {
|
||||
// Use the same field path that ValidateAuthenticationConfiguration() would build, for consistency.
|
||||
fieldPath := field.NewPath("jwt").Index(0).
|
||||
Child("claimMappings").
|
||||
Child("extra").Index(i).
|
||||
Child("key")
|
||||
errList = append(errList, field.Invalid(fieldPath, mapping.Key,
|
||||
"Pinniped does not allow extra key names to contain equals sign",
|
||||
))
|
||||
}
|
||||
}
|
||||
groupsClaim := spec.Claims.Groups
|
||||
if groupsClaim == "" {
|
||||
groupsClaim = defaultGroupsClaim
|
||||
|
||||
if errList != nil {
|
||||
rewriteJWTAuthenticatorErrors(errList)
|
||||
|
||||
errText := "could not initialize jwt authenticator"
|
||||
err := errList.ToAggregate()
|
||||
msg := fmt.Sprintf("%s: %s", errText, err.Error())
|
||||
conditions = append(conditions, &metav1.Condition{
|
||||
Type: typeAuthenticatorValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: reasonInvalidAuthenticator,
|
||||
Message: msg,
|
||||
})
|
||||
return nil, conditions, nil
|
||||
}
|
||||
|
||||
cancelCtx, cancel := context.WithCancel(context.Background())
|
||||
oidcAuthenticator, err := oidc.New(cancelCtx, oidc.Options{
|
||||
JWTAuthenticator: apiserver.JWTAuthenticator{
|
||||
Issuer: apiserver.Issuer{
|
||||
URL: spec.Issuer,
|
||||
Audiences: []string{spec.Audience},
|
||||
},
|
||||
ClaimMappings: apiserver.ClaimMappings{
|
||||
Username: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: usernameClaim,
|
||||
Prefix: ptr.To(""),
|
||||
},
|
||||
Groups: apiserver.PrefixedClaimOrExpression{
|
||||
Claim: groupsClaim,
|
||||
Prefix: ptr.To(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
JWTAuthenticator: apiServerJWTAuthenticator,
|
||||
KeySet: keySet,
|
||||
SupportedSigningAlgs: defaultSupportedSigningAlgos(),
|
||||
Client: client,
|
||||
@@ -706,17 +730,54 @@ func (c *jwtCacheFillerController) newCachedJWTAuthenticator(
|
||||
// resync err, lots of possible issues that may or may not be machine related
|
||||
return nil, conditions, fmt.Errorf("%s: %w", errText, err)
|
||||
}
|
||||
|
||||
conditions = append(conditions, successfulAuthenticatorValidCondition())
|
||||
|
||||
return &cachedJWTAuthenticator{
|
||||
Token: oidcAuthenticator,
|
||||
issuer: spec.Issuer,
|
||||
audience: spec.Audience,
|
||||
claims: spec.Claims,
|
||||
caBundleHash: caBundleHash,
|
||||
cancel: cancel,
|
||||
Token: oidcAuthenticator,
|
||||
issuer: spec.Issuer,
|
||||
audience: spec.Audience,
|
||||
claims: spec.Claims,
|
||||
userValidationRules: spec.UserValidationRules,
|
||||
claimValidationRules: spec.ClaimValidationRules,
|
||||
caBundleHash: caBundleHash,
|
||||
cancel: cancel,
|
||||
}, conditions, nil
|
||||
}
|
||||
|
||||
// We don't have any control over the error strings created by ValidateAuthenticationConfiguration(), but we
|
||||
// can rewrite them to make them more consistent with our JWTAuthenticator CRD field names where they don't agree.
|
||||
func rewriteJWTAuthenticatorErrors(errList field.ErrorList) {
|
||||
// ValidateAuthenticationConfiguration() will prefix all our errors with "jwt[0]." because we always pass it
|
||||
// exactly one jwtAuthenticator to validate.
|
||||
undesirablePrefix := fmt.Sprintf("%s.", field.NewPath("jwt").Index(0).String())
|
||||
|
||||
// Replace these to make the spec names consistent with how they are named in the JWTAuthenticator CRD.
|
||||
replacements := []struct {
|
||||
str string
|
||||
repl string
|
||||
}{
|
||||
// replace these more specific strings first
|
||||
{str: "claimMappings.username.expression", repl: "claims.usernameExpression"},
|
||||
{str: "claimMappings.groups.expression", repl: "claims.groupsExpression"},
|
||||
|
||||
// then replace these less specific strings (substrings of the strings above) if they still exist
|
||||
{str: "claimMappings.username", repl: "claims.username"},
|
||||
{str: "claimMappings.groups", repl: "claims.groups"},
|
||||
|
||||
// and also replace this one
|
||||
{str: "claimMappings.extra", repl: "claims.extra"},
|
||||
}
|
||||
|
||||
for _, err := range errList {
|
||||
err.Field = strings.TrimPrefix(err.Field, undesirablePrefix)
|
||||
for _, spec := range replacements {
|
||||
err.Field = strings.ReplaceAll(err.Field, spec.str, spec.repl)
|
||||
err.Detail = strings.ReplaceAll(err.Detail, spec.str, spec.repl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *jwtCacheFillerController) updateStatus(
|
||||
ctx context.Context,
|
||||
original *authenticationv1alpha1.JWTAuthenticator,
|
||||
|
||||
@@ -360,6 +360,111 @@ func TestController(t *testing.T) {
|
||||
Groups: customGroupsClaim,
|
||||
},
|
||||
}
|
||||
someJWTAuthenticatorSpecWithManyOptionalValues := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Username: "my-custom-username-claim", // note: can't specify this and usernameExpression at the same time
|
||||
Groups: customGroupsClaim, // note: can't specify this and groupsExpression at the same time
|
||||
Extra: []authenticationv1alpha1.ExtraMapping{
|
||||
{
|
||||
Key: "example.com/key-name", // must be a domain and path
|
||||
ValueExpression: `"extra-value"`, // needs to be a valid CEL expression that returns a string or list of strings
|
||||
},
|
||||
},
|
||||
},
|
||||
ClaimValidationRules: []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Claim: "iss", // note: can't specify this and Expression/Message at the same time
|
||||
RequiredValue: goodIssuer,
|
||||
},
|
||||
},
|
||||
UserValidationRules: []authenticationv1alpha1.UserValidationRule{
|
||||
{
|
||||
Expression: "true", // must be a valid CEL expression that returns a boolean
|
||||
Message: "user-msg1",
|
||||
},
|
||||
},
|
||||
}
|
||||
someJWTAuthenticatorSpecWithUsernameAndGroupExpressions := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
UsernameExpression: "claims.otherUsernameClaim",
|
||||
GroupsExpression: "has(claims.otherGroupsClaim) ? claims.otherGroupsClaim : []", // handles the case where the claim does not exist in the JWT
|
||||
},
|
||||
}
|
||||
invalidClaimsExtraJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Extra: []authenticationv1alpha1.ExtraMapping{
|
||||
{
|
||||
Key: "this-is-an-invalid-key", // this should cause a validation error in the Kubernetes library validator
|
||||
ValueExpression: `"extra-value"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
invalidClaimValidationRulesJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
ClaimValidationRules: []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Expression: "this is an invalid cel expression",
|
||||
},
|
||||
},
|
||||
}
|
||||
invalidUserValidationRulesJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
UserValidationRules: []authenticationv1alpha1.UserValidationRule{
|
||||
{
|
||||
Expression: "this is an invalid cel expression",
|
||||
},
|
||||
},
|
||||
}
|
||||
invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Username: "user",
|
||||
UsernameExpression: `"user"`,
|
||||
Groups: "groups",
|
||||
GroupsExpression: `["group1"]`,
|
||||
},
|
||||
}
|
||||
invalidClaimsUsernameExpressUsesClaimsDotEmailWrongJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
UsernameExpression: "claims.email",
|
||||
},
|
||||
}
|
||||
invalidClaimsExtraContainsEqualSignJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: goodIssuer,
|
||||
Audience: goodAudience,
|
||||
TLS: goodOIDCIssuerServerTLSSpec,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Extra: []authenticationv1alpha1.ExtraMapping{
|
||||
{
|
||||
Key: "example.com/legal-key",
|
||||
ValueExpression: `"extra-value"`,
|
||||
},
|
||||
{
|
||||
Key: "example.com/key=contains-equals-sign", // this should cause a validation error in our own code
|
||||
ValueExpression: `"extra-value"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
otherJWTAuthenticatorSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: someOtherIssuer,
|
||||
Audience: goodAudience,
|
||||
@@ -549,6 +654,16 @@ func TestController(t *testing.T) {
|
||||
Message: "unable to validate; see other conditions for details",
|
||||
}
|
||||
}
|
||||
sadAuthenticatorValid := func(msg string, time metav1.Time, observedGeneration int64) metav1.Condition {
|
||||
return metav1.Condition{
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
ObservedGeneration: observedGeneration,
|
||||
LastTransitionTime: time,
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
// NOTE: we can't reach this error the way our code is written.
|
||||
// We check many things and fail early, resulting in an "Unknown" Authenticator status.
|
||||
// The only possible fail for the Authenticator itself would require us to allow more
|
||||
@@ -717,6 +832,7 @@ func TestController(t *testing.T) {
|
||||
wantActions func() []coretesting.Action
|
||||
wantUsernameClaim string
|
||||
wantGroupsClaim string
|
||||
wantExtras map[string][]string
|
||||
wantNamesOfJWTAuthenticatorsInCache []string
|
||||
skipTestingCachedAuthenticator bool
|
||||
}{
|
||||
@@ -1108,6 +1224,79 @@ func TestController(t *testing.T) {
|
||||
wantGroupsClaim: someJWTAuthenticatorSpecWithGroupsClaim.Claims.Groups,
|
||||
wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"},
|
||||
},
|
||||
{
|
||||
name: "Sync: JWTAuthenticator with many optional values: loop will complete successfully and update status conditions",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpecWithManyOptionalValues,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Ready"}`, goodIssuer),
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"added or updated jwt authenticator in cache","jwtAuthenticator":"test-name","issuer":"%s","isOverwrite":false}`, goodIssuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpecWithManyOptionalValues,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
Phase: "Ready",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
wantUsernameClaim: "my-custom-username-claim",
|
||||
wantGroupsClaim: someJWTAuthenticatorSpecWithGroupsClaim.Claims.Groups,
|
||||
wantExtras: map[string][]string{"example.com/key-name": {"extra-value"}},
|
||||
wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"},
|
||||
},
|
||||
{
|
||||
name: "Sync: JWTAuthenticator with usernameExpression and groupsExpression values: loop will complete successfully and update status conditions",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpecWithUsernameAndGroupExpressions,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Ready"}`, goodIssuer),
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"added or updated jwt authenticator in cache","jwtAuthenticator":"test-name","issuer":"%s","isOverwrite":false}`, goodIssuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpecWithUsernameAndGroupExpressions,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
Phase: "Ready",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
wantUsernameClaim: "otherUsernameClaim",
|
||||
wantGroupsClaim: "otherGroupsClaim",
|
||||
wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"},
|
||||
},
|
||||
{
|
||||
name: "Sync: JWTAuthenticator with new spec.tls fields: loop will close previous instance of JWTAuthenticator and complete successfully and update status conditions",
|
||||
cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) {
|
||||
@@ -1302,6 +1491,114 @@ func TestController(t *testing.T) {
|
||||
wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"},
|
||||
wantClose: true,
|
||||
},
|
||||
{
|
||||
name: "Sync: JWTAuthenticator with new spec.userValidationRules field: loop will close previous instance of JWTAuthenticator and complete successfully and update status conditions",
|
||||
cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) {
|
||||
oldCA, err := base64.StdEncoding.DecodeString(someJWTAuthenticatorSpec.TLS.CertificateAuthorityData)
|
||||
require.NoError(t, err)
|
||||
cacheValue := newCacheValue(t, *someJWTAuthenticatorSpec, string(oldCA), wantClose)
|
||||
cacheValue.userValidationRules = []authenticationv1alpha1.UserValidationRule{
|
||||
{
|
||||
Expression: "true",
|
||||
Message: "some old rule",
|
||||
},
|
||||
}
|
||||
cache.Store(
|
||||
authncache.Key{
|
||||
Name: "test-name",
|
||||
Kind: "JWTAuthenticator",
|
||||
APIGroup: authenticationv1alpha1.SchemeGroupVersion.Group,
|
||||
},
|
||||
cacheValue,
|
||||
)
|
||||
},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Ready"}`, goodIssuer),
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"added or updated jwt authenticator in cache","jwtAuthenticator":"test-name","issuer":"%s","isOverwrite":true}`, goodIssuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
Phase: "Ready",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"},
|
||||
wantClose: true,
|
||||
},
|
||||
{
|
||||
name: "Sync: JWTAuthenticator with new spec.claimValidationRules field: loop will close previous instance of JWTAuthenticator and complete successfully and update status conditions",
|
||||
cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) {
|
||||
oldCA, err := base64.StdEncoding.DecodeString(someJWTAuthenticatorSpec.TLS.CertificateAuthorityData)
|
||||
require.NoError(t, err)
|
||||
cacheValue := newCacheValue(t, *someJWTAuthenticatorSpec, string(oldCA), wantClose)
|
||||
cacheValue.claimValidationRules = []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Claim: "iss",
|
||||
RequiredValue: "some old value",
|
||||
},
|
||||
}
|
||||
cache.Store(
|
||||
authncache.Key{
|
||||
Name: "test-name",
|
||||
Kind: "JWTAuthenticator",
|
||||
APIGroup: authenticationv1alpha1.SchemeGroupVersion.Group,
|
||||
},
|
||||
cacheValue,
|
||||
)
|
||||
},
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Ready"}`, goodIssuer),
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"added or updated jwt authenticator in cache","jwtAuthenticator":"test-name","issuer":"%s","isOverwrite":true}`, goodIssuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *someJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
Phase: "Ready",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
wantNamesOfJWTAuthenticatorsInCache: []string{"test-name"},
|
||||
wantClose: true,
|
||||
},
|
||||
{
|
||||
name: "Sync: previously cached authenticator gets new spec fields, but status update fails: loop will leave it in the cache and avoid calling close",
|
||||
cache: func(t *testing.T, cache *authncache.Cache, wantClose bool) {
|
||||
@@ -2280,6 +2577,292 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
wantSyncErr: testutil.WantExactErrorString("error for JWTAuthenticator test-name: could not fetch keys: fetching keys oidc: get keys failed: 404 Not Found 404 page not found\n"),
|
||||
},
|
||||
{
|
||||
name: "newCachedJWTAuthenticator: validateAuthenticationConfiguration: for any error in claims.extra: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsExtraJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"invalid jwt authenticator","jwtAuthenticator":"test-name","issuer":"%s","removedFromCache":false}`, invalidClaimsExtraJWTAuthenticatorSpec.Issuer),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Error"}`, invalidClaimsExtraJWTAuthenticatorSpec.Issuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsExtraJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
happyIssuerURLValid(frozenMetav1Now, 0),
|
||||
happyDiscoveryURLValid(frozenMetav1Now, 0),
|
||||
sadAuthenticatorValid(
|
||||
`could not initialize jwt authenticator: claims.extra[0].key: Invalid value: "this-is-an-invalid-key": must be a domain-prefixed path (such as "acme.io/foo")`,
|
||||
frozenMetav1Now,
|
||||
0,
|
||||
),
|
||||
happyJWKSURLValid(frozenMetav1Now, 0),
|
||||
happyJWKSFetch(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newCachedJWTAuthenticator: validateAuthenticationConfiguration: for any error in claimValidationRules: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimValidationRulesJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"invalid jwt authenticator","jwtAuthenticator":"test-name","issuer":"%s","removedFromCache":false}`, invalidClaimValidationRulesJWTAuthenticatorSpec.Issuer),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Error"}`, invalidClaimValidationRulesJWTAuthenticatorSpec.Issuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimValidationRulesJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
happyIssuerURLValid(frozenMetav1Now, 0),
|
||||
happyDiscoveryURLValid(frozenMetav1Now, 0),
|
||||
sadAuthenticatorValid(
|
||||
"could not initialize jwt authenticator: claimValidationRules[0].expression: Invalid value: \"this is an invalid cel expression\": "+
|
||||
"compilation failed: ERROR: <input>:1:6: Syntax error: mismatched input 'is' expecting <EOF>\n | this is an invalid cel expression\n | .....^",
|
||||
frozenMetav1Now,
|
||||
0,
|
||||
),
|
||||
happyJWKSURLValid(frozenMetav1Now, 0),
|
||||
happyJWKSFetch(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newCachedJWTAuthenticator: validateAuthenticationConfiguration: for any error in userValidationRules: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidUserValidationRulesJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"invalid jwt authenticator","jwtAuthenticator":"test-name","issuer":"%s","removedFromCache":false}`, invalidUserValidationRulesJWTAuthenticatorSpec.Issuer),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Error"}`, invalidUserValidationRulesJWTAuthenticatorSpec.Issuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidUserValidationRulesJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
happyIssuerURLValid(frozenMetav1Now, 0),
|
||||
happyDiscoveryURLValid(frozenMetav1Now, 0),
|
||||
sadAuthenticatorValid(
|
||||
"could not initialize jwt authenticator: userValidationRules[0].expression: Invalid value: \"this is an invalid cel expression\": "+
|
||||
"compilation failed: ERROR: <input>:1:6: Syntax error: mismatched input 'is' expecting <EOF>\n | this is an invalid cel expression\n | .....^",
|
||||
frozenMetav1Now,
|
||||
0,
|
||||
),
|
||||
happyJWKSURLValid(frozenMetav1Now, 0),
|
||||
happyJWKSFetch(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newCachedJWTAuthenticator: validateAuthenticationConfiguration: when username and usernameExpression and/or groups and groupsExpression are both set: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"invalid jwt authenticator","jwtAuthenticator":"test-name","issuer":"%s","removedFromCache":false}`, invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec.Issuer),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Error"}`, invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec.Issuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsMutualExclusiveRulesBothSetJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
happyIssuerURLValid(frozenMetav1Now, 0),
|
||||
happyDiscoveryURLValid(frozenMetav1Now, 0),
|
||||
sadAuthenticatorValid(
|
||||
`could not initialize jwt authenticator: [claims.username: Invalid value: "": claim and expression can't both be set, claims.groups: Invalid value: "": claim and expression can't both be set]`,
|
||||
frozenMetav1Now,
|
||||
0,
|
||||
),
|
||||
happyJWKSURLValid(frozenMetav1Now, 0),
|
||||
happyJWKSFetch(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newCachedJWTAuthenticator: validateAuthenticationConfiguration: when usernameExpression uses claims.email without using claims.email_verified elsewhere: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsUsernameExpressUsesClaimsDotEmailWrongJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"invalid jwt authenticator","jwtAuthenticator":"test-name","issuer":"%s","removedFromCache":false}`, invalidClaimsUsernameExpressUsesClaimsDotEmailWrongJWTAuthenticatorSpec.Issuer),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Error"}`, invalidClaimsUsernameExpressUsesClaimsDotEmailWrongJWTAuthenticatorSpec.Issuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsUsernameExpressUsesClaimsDotEmailWrongJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
happyIssuerURLValid(frozenMetav1Now, 0),
|
||||
happyDiscoveryURLValid(frozenMetav1Now, 0),
|
||||
sadAuthenticatorValid(
|
||||
`could not initialize jwt authenticator: claims.usernameExpression: Invalid value: "claims.email": `+
|
||||
`claims.email_verified must be used in claims.usernameExpression or claims.extra[*].valueExpression or `+
|
||||
`claimValidationRules[*].expression when claims.email is used in claims.usernameExpression`,
|
||||
frozenMetav1Now,
|
||||
0,
|
||||
),
|
||||
happyJWKSURLValid(frozenMetav1Now, 0),
|
||||
happyJWKSFetch(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newCachedJWTAuthenticator: when any claims.extra[].key contains an equals sign: loop will fail sync, will write failed and unknown status conditions, but will not enqueue a resync due to user config error",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsExtraContainsEqualSignJWTAuthenticatorSpec,
|
||||
},
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).syncIndividualJWTAuthenticator","message":"invalid jwt authenticator","jwtAuthenticator":"test-name","issuer":"%s","removedFromCache":false}`, invalidClaimsExtraContainsEqualSignJWTAuthenticatorSpec.Issuer),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"jwtcachefiller-controller","caller":"jwtcachefiller/jwtcachefiller.go:<line>$jwtcachefiller.(*jwtCacheFillerController).updateStatus","message":"jwtauthenticator status successfully updated","jwtAuthenticator":"test-name","issuer":"%s","phase":"Error"}`, invalidClaimsExtraContainsEqualSignJWTAuthenticatorSpec.Issuer),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(jwtAuthenticatorsGVR, "", &authenticationv1alpha1.JWTAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: *invalidClaimsExtraContainsEqualSignJWTAuthenticatorSpec,
|
||||
Status: authenticationv1alpha1.JWTAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodIssuer, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
happyIssuerURLValid(frozenMetav1Now, 0),
|
||||
happyDiscoveryURLValid(frozenMetav1Now, 0),
|
||||
sadAuthenticatorValid(
|
||||
`could not initialize jwt authenticator: claims.extra[1].key: Invalid value: "example.com/key=contains-equals-sign": Pinniped does not allow extra key names to contain equals sign`,
|
||||
frozenMetav1Now,
|
||||
0,
|
||||
),
|
||||
happyJWKSURLValid(frozenMetav1Now, 0),
|
||||
happyJWKSFetch(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(jwtAuthenticatorsGVR, jwtAUthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(jwtAuthenticatorsGVR, "", metav1.ListOptions{Watch: true}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "updateStatus: called with matching original and updated conditions: will not make request to update conditions",
|
||||
jwtAuthenticators: []runtime.Object{
|
||||
@@ -2484,6 +3067,15 @@ func TestController(t *testing.T) {
|
||||
cachedAuthenticator, ok := temp.(tokenAuthenticatorCloser)
|
||||
require.True(t, ok)
|
||||
|
||||
usernameClaimIsCelExpression := false
|
||||
if temp.(*cachedJWTAuthenticator).claims.UsernameExpression != "" {
|
||||
usernameClaimIsCelExpression = true
|
||||
}
|
||||
groupsClaimIsCelExpression := false
|
||||
if temp.(*cachedJWTAuthenticator).claims.GroupsExpression != "" {
|
||||
groupsClaimIsCelExpression = true
|
||||
}
|
||||
|
||||
// Schedule it to be closed at the end of the test.
|
||||
t.Cleanup(cachedAuthenticator.Close)
|
||||
|
||||
@@ -2511,12 +3103,19 @@ func TestController(t *testing.T) {
|
||||
group1,
|
||||
goodUsername,
|
||||
tt.wantUsernameClaim,
|
||||
usernameClaimIsCelExpression,
|
||||
tt.wantGroupsClaim,
|
||||
groupsClaimIsCelExpression,
|
||||
tt.wantExtras,
|
||||
goodIssuer,
|
||||
) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if test.skip != nil {
|
||||
test.skip(t) // give the test a chance to skip itself if it wants to
|
||||
}
|
||||
|
||||
wellKnownClaims := josejwt.Claims{
|
||||
Issuer: goodIssuer,
|
||||
Subject: goodSubject,
|
||||
@@ -2592,7 +3191,10 @@ func testTableForAuthenticateTokenTests(
|
||||
group1 string,
|
||||
goodUsername string,
|
||||
expectedUsernameClaim string,
|
||||
usernameClaimIsCelExpression bool,
|
||||
expectedGroupsClaim string,
|
||||
groupsClaimIsCelExpression bool,
|
||||
expectedExtras map[string][]string,
|
||||
issuer string,
|
||||
) []struct {
|
||||
name string
|
||||
@@ -2602,7 +3204,22 @@ func testTableForAuthenticateTokenTests(
|
||||
wantAuthenticated bool
|
||||
wantErr testutil.RequireErrorStringFunc
|
||||
distributedGroupsClaimURL string
|
||||
skip func(t *testing.T)
|
||||
} {
|
||||
expectedErrForBadTokenWithGroupsAsMap := func() testutil.RequireErrorStringFunc {
|
||||
if groupsClaimIsCelExpression {
|
||||
return testutil.WantExactErrorString(`oidc: error evaluating group claim expression: expression must return a string or a list of strings`)
|
||||
}
|
||||
return testutil.WantExactErrorString(`oidc: parse groups claim "` + expectedGroupsClaim + `": json: cannot unmarshal object into Go value of type string`)
|
||||
}
|
||||
|
||||
expectedErrForTokenDoesNotHaveUsernameClaim := func() testutil.RequireErrorStringFunc {
|
||||
if usernameClaimIsCelExpression {
|
||||
return testutil.WantMatchingErrorString(`oidc: error evaluating username claim expression: expression '.+' resulted in error: no such key: ` + expectedUsernameClaim)
|
||||
}
|
||||
return testutil.WantExactErrorString(`oidc: parse username claims "` + expectedUsernameClaim + `": claim not present`)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
jwtClaims func(wellKnownClaims *josejwt.Claims, groups *any, username *string)
|
||||
@@ -2611,12 +3228,14 @@ func testTableForAuthenticateTokenTests(
|
||||
wantAuthenticated bool
|
||||
wantErr testutil.RequireErrorStringFunc
|
||||
distributedGroupsClaimURL string
|
||||
skip func(t *testing.T)
|
||||
}{
|
||||
{
|
||||
name: "good token without groups and with EC signature",
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodUsername,
|
||||
Name: goodUsername,
|
||||
Extra: expectedExtras,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
@@ -2630,7 +3249,8 @@ func testTableForAuthenticateTokenTests(
|
||||
},
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodUsername,
|
||||
Name: goodUsername,
|
||||
Extra: expectedExtras,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
@@ -2644,6 +3264,7 @@ func testTableForAuthenticateTokenTests(
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodUsername,
|
||||
Groups: []string{group0, group1},
|
||||
Extra: expectedExtras,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
@@ -2657,16 +3278,27 @@ func testTableForAuthenticateTokenTests(
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodUsername,
|
||||
Groups: []string{"some-distributed-group-1", "some-distributed-group-2"},
|
||||
Extra: expectedExtras,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
skip: func(t *testing.T) {
|
||||
if groupsClaimIsCelExpression {
|
||||
t.Skip("skipping test because Kubernetes does not support using a CEL expression for groups mapping with distributed claims")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "distributed groups returns a 404",
|
||||
jwtClaims: func(claims *josejwt.Claims, groups *any, username *string) {
|
||||
},
|
||||
distributedGroupsClaimURL: issuer + "/not_found_claim_source",
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: could not expand distributed claims: while getting distributed claim "` + expectedGroupsClaim + `": error while getting distributed claim JWT: 404 Not Found`),
|
||||
wantErr: testutil.WantExactErrorString(`oidc: could not expand distributed claims: while getting distributed claim "` + expectedGroupsClaim + `": error while getting distributed claim JWT: 404 Not Found`),
|
||||
skip: func(t *testing.T) {
|
||||
if groupsClaimIsCelExpression {
|
||||
t.Skip("skipping test because Kubernetes does not support using a CEL expression for groups mapping with distributed claims")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "distributed groups doesn't return the right claim",
|
||||
@@ -2674,6 +3306,11 @@ func testTableForAuthenticateTokenTests(
|
||||
},
|
||||
distributedGroupsClaimURL: issuer + "/wrong_claim_source",
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: could not expand distributed claims: jwt returned by distributed claim endpoint "` + issuer + `/wrong_claim_source" did not contain claim: `),
|
||||
skip: func(t *testing.T) {
|
||||
if groupsClaimIsCelExpression {
|
||||
t.Skip("skipping test because Kubernetes does not support using a CEL expression for groups mapping with distributed claims")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "good token with groups as string",
|
||||
@@ -2684,6 +3321,7 @@ func testTableForAuthenticateTokenTests(
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodUsername,
|
||||
Groups: []string{group0},
|
||||
Extra: expectedExtras,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
@@ -2695,7 +3333,8 @@ func testTableForAuthenticateTokenTests(
|
||||
},
|
||||
wantResponse: &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
Name: goodUsername,
|
||||
Name: goodUsername,
|
||||
Extra: expectedExtras,
|
||||
},
|
||||
},
|
||||
wantAuthenticated: true,
|
||||
@@ -2705,7 +3344,7 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtClaims: func(_ *josejwt.Claims, groups *any, username *string) {
|
||||
*groups = map[string]string{"not an array": "or a string"}
|
||||
},
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: parse groups claim "` + expectedGroupsClaim + `": json: cannot unmarshal object into Go value of type string`),
|
||||
wantErr: expectedErrForBadTokenWithGroupsAsMap(),
|
||||
},
|
||||
{
|
||||
name: "bad token with wrong issuer",
|
||||
@@ -2720,14 +3359,14 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtClaims: func(claims *josejwt.Claims, _ *any, username *string) {
|
||||
claims.Audience = nil
|
||||
},
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: expected audience "some-audience" got \[\]`),
|
||||
wantErr: testutil.WantExactErrorString(`oidc: verify token: oidc: expected audience "some-audience" got []`),
|
||||
},
|
||||
{
|
||||
name: "bad token with wrong audience",
|
||||
jwtClaims: func(claims *josejwt.Claims, _ *any, username *string) {
|
||||
claims.Audience = []string{"wrong-audience"}
|
||||
},
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: expected audience "some-audience" got \["wrong-audience"\]`),
|
||||
wantErr: testutil.WantExactErrorString(`oidc: verify token: oidc: expected audience "some-audience" got ["wrong-audience"]`),
|
||||
},
|
||||
{
|
||||
name: "bad token with nbf in the future",
|
||||
@@ -2755,7 +3394,7 @@ func testTableForAuthenticateTokenTests(
|
||||
jwtClaims: func(claims *josejwt.Claims, _ *any, username *string) {
|
||||
*username = ""
|
||||
},
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: parse username claims "` + expectedUsernameClaim + `": claim not present`),
|
||||
wantErr: expectedErrForTokenDoesNotHaveUsernameClaim(),
|
||||
},
|
||||
{
|
||||
name: "signing key is wrong",
|
||||
@@ -2765,7 +3404,7 @@ func testTableForAuthenticateTokenTests(
|
||||
require.NoError(t, err)
|
||||
*algo = jose.ES256
|
||||
},
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: failed to verify signature: failed to verify id token signature`),
|
||||
wantErr: testutil.WantExactErrorString(`oidc: verify token: failed to verify signature: failed to verify id token signature`),
|
||||
},
|
||||
{
|
||||
name: "signing algo is unsupported",
|
||||
@@ -2775,7 +3414,7 @@ func testTableForAuthenticateTokenTests(
|
||||
require.NoError(t, err)
|
||||
*algo = jose.ES384
|
||||
},
|
||||
wantErr: testutil.WantMatchingErrorString(`oidc: verify token: oidc: id token signed with unsupported algorithm, expected \["RS256" "ES256"\] got "ES384"`),
|
||||
wantErr: testutil.WantExactErrorString(`oidc: verify token: oidc: id token signed with unsupported algorithm, expected ["RS256" "ES256"] got "ES384"`),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2828,10 +3467,12 @@ func newCacheValue(t *testing.T, spec authenticationv1alpha1.JWTAuthenticatorSpe
|
||||
})
|
||||
|
||||
return &cachedJWTAuthenticator{
|
||||
issuer: spec.Issuer,
|
||||
audience: spec.Audience,
|
||||
claims: spec.Claims,
|
||||
caBundleHash: tlsconfigutil.NewCABundleHash([]byte(caBundle)),
|
||||
issuer: spec.Issuer,
|
||||
audience: spec.Audience,
|
||||
claims: spec.Claims,
|
||||
userValidationRules: spec.UserValidationRules,
|
||||
claimValidationRules: spec.ClaimValidationRules,
|
||||
caBundleHash: tlsconfigutil.NewCABundleHash([]byte(caBundle)),
|
||||
cancel: func() {
|
||||
wasClosed = true
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2021-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package impersonatorconfig
|
||||
@@ -1145,7 +1145,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
mTLSClientCertCAPrivateKeyPEM, err = mTLSClientCertCA.PrivateKeyToPEM()
|
||||
r.NoError(err)
|
||||
mTLSClientCertCASecret = newSigningKeySecret(mTLSClientCertCASecretName, mTLSClientCertCACertPEM, mTLSClientCertCAPrivateKeyPEM)
|
||||
validClientCert, err = mTLSClientCertCA.IssueClientCert("username", nil, time.Hour)
|
||||
validClientCert, err = mTLSClientCertCA.IssueClientCert("username", nil, nil, time.Hour)
|
||||
r.NoError(err)
|
||||
|
||||
externalCA = newCA()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
@@ -46,18 +46,18 @@ func (m *MockClientCertIssuer) EXPECT() *MockClientCertIssuerMockRecorder {
|
||||
}
|
||||
|
||||
// IssueClientCertPEM mocks base method.
|
||||
func (m *MockClientCertIssuer) IssueClientCertPEM(username string, groups []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
func (m *MockClientCertIssuer) IssueClientCertPEM(username string, groups, extras []string, ttl time.Duration) (*cert.PEM, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IssueClientCertPEM", username, groups, ttl)
|
||||
ret := m.ctrl.Call(m, "IssueClientCertPEM", username, groups, extras, ttl)
|
||||
ret0, _ := ret[0].(*cert.PEM)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// IssueClientCertPEM indicates an expected call of IssueClientCertPEM.
|
||||
func (mr *MockClientCertIssuerMockRecorder) IssueClientCertPEM(username, groups, ttl any) *gomock.Call {
|
||||
func (mr *MockClientCertIssuerMockRecorder) IssueClientCertPEM(username, groups, extras, ttl any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IssueClientCertPEM", reflect.TypeOf((*MockClientCertIssuer)(nil).IssueClientCertPEM), username, groups, ttl)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IssueClientCertPEM", reflect.TypeOf((*MockClientCertIssuer)(nil).IssueClientCertPEM), username, groups, extras, ttl)
|
||||
}
|
||||
|
||||
// Name mocks base method.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -16,6 +19,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
@@ -158,7 +162,12 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
|
||||
return authenticationFailedResponse(), nil
|
||||
}
|
||||
|
||||
pem, err := r.issuer.IssueClientCertPEM(userInfo.GetName(), userInfo.GetGroups(), clientCertificateTTL)
|
||||
pem, err := r.issuer.IssueClientCertPEM(
|
||||
userInfo.GetName(),
|
||||
userInfo.GetGroups(),
|
||||
extrasAsKeyValues(userInfo.GetExtra()),
|
||||
clientCertificateTTL,
|
||||
)
|
||||
if err != nil {
|
||||
r.auditLogger.Audit(auditevent.TokenCredentialRequestUnexpectedError, &plog.AuditParams{
|
||||
ReqCtx: ctx,
|
||||
@@ -179,6 +188,7 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
|
||||
PIIKeysAndValues: []any{
|
||||
"username", userInfo.GetName(),
|
||||
"groups", userInfo.GetGroups(),
|
||||
"extras", userInfo.GetExtra(),
|
||||
},
|
||||
KeysAndValues: []any{
|
||||
"issuedClientCert", map[string]string{
|
||||
@@ -200,6 +210,18 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
|
||||
}, nil
|
||||
}
|
||||
|
||||
func extrasAsKeyValues(extras map[string][]string) []string {
|
||||
var kvExtras []string
|
||||
for k, v := range extras {
|
||||
for _, vv := range v {
|
||||
// Note that this will result in a key getting repeated if it has multiple values.
|
||||
kvExtras = append(kvExtras, fmt.Sprintf("%s=%s", k, vv))
|
||||
}
|
||||
}
|
||||
slices.Sort(kvExtras)
|
||||
return kvExtras
|
||||
}
|
||||
|
||||
func validateRequest(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (*loginapi.TokenCredentialRequest, error) {
|
||||
credentialRequest, ok := obj.(*loginapi.TokenCredentialRequest)
|
||||
if !ok {
|
||||
@@ -245,23 +267,81 @@ func validateUserInfo(userInfo user.Info) error {
|
||||
return errors.New("UIDs are not supported")
|
||||
}
|
||||
|
||||
// certs cannot assert extras, but starting in K8s 1.32 the authenticator will always provide this information
|
||||
if len(userInfo.GetExtra()) == 0 { // it's ok for this to be empty...
|
||||
return nil
|
||||
allErrs := validateExtraKeys(userInfo.GetExtra())
|
||||
if allErrs != nil {
|
||||
return fmt.Errorf("authenticator returned illegal userInfo extra key(s): %w", allErrs.ToAggregate())
|
||||
}
|
||||
|
||||
// ... but if it's not empty, should have only exactly this one key.
|
||||
if len(userInfo.GetExtra()) > 1 {
|
||||
return errors.New("extra may have only one key 'authentication.kubernetes.io/credential-id'")
|
||||
}
|
||||
|
||||
_, ok := userInfo.GetExtra()["authentication.kubernetes.io/credential-id"]
|
||||
if !ok {
|
||||
return errors.New("extra may have only one key 'authentication.kubernetes.io/credential-id'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateExtraKeys(extras map[string][]string) field.ErrorList {
|
||||
// Prevent WebhookAuthenticators from returning illegal extras.
|
||||
//
|
||||
// JWTAuthenticators are already effectively prevented from returning illegal extras because we validate
|
||||
// the extra key names that are configured on the JWTAuthenticator CRD, but it shouldn't hurt to check again
|
||||
// here for JWTAuthenticators too.
|
||||
//
|
||||
// These validations are inspired by those done in k8s.io/apiserver@v0.33.2/pkg/apis/apiserver/validation/validation.go.
|
||||
//
|
||||
// Keys must be a domain-prefix path (e.g. example.org/foo).
|
||||
// All characters before the first "/" must be a valid subdomain as defined by RFC 1123.
|
||||
// All characters trailing the first "/" must be valid HTTP Path characters as defined by RFC 3986.
|
||||
// k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use and cannot be used.
|
||||
// Keys must be lowercase.
|
||||
var allErrs field.ErrorList
|
||||
|
||||
// Sort the keys for stable order of error messages.
|
||||
keys := make([]string, 0, len(extras))
|
||||
for k := range extras {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, extraKey := range keys {
|
||||
path := field.NewPath(fmt.Sprintf("userInfo extra key %q", extraKey))
|
||||
|
||||
// This is a special key that is always added by authenticators starting in K8s 1.32, so always allow it.
|
||||
if extraKey == "authentication.kubernetes.io/credential-id" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Noe that IsDomainPrefixedPath also checks for empty keys.
|
||||
allErrs = append(allErrs, utilvalidation.IsDomainPrefixedPath(path, extraKey)...)
|
||||
|
||||
// Cannot use reserved prefixes.
|
||||
if isKubernetesDomainPrefix(extraKey) {
|
||||
allErrs = append(allErrs, field.Invalid(path, extraKey, "k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use"))
|
||||
}
|
||||
|
||||
// We can't allow equals signs in the key name, because we need to be able to encode the key names and values
|
||||
// into the client cert as OU "keyName=value".
|
||||
if strings.Contains(extraKey, "=") {
|
||||
allErrs = append(allErrs, field.Invalid(path, extraKey, "Pinniped does not allow extra key names to contain equals sign"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func isKubernetesDomainPrefix(key string) bool {
|
||||
domainPrefix := getDomainPrefix(key)
|
||||
if domainPrefix == "kubernetes.io" || strings.HasSuffix(domainPrefix, ".kubernetes.io") {
|
||||
return true
|
||||
}
|
||||
if domainPrefix == "k8s.io" || strings.HasSuffix(domainPrefix, ".k8s.io") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getDomainPrefix(key string) string {
|
||||
if parts := strings.SplitN(key, "/", 2); len(parts) == 2 {
|
||||
return parts[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func authenticationFailedResponse() *loginapi.TokenCredentialRequest {
|
||||
m := "authentication failed"
|
||||
return &loginapi.TokenCredentialRequest{
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestCreate(t *testing.T) {
|
||||
ctrl.Finish()
|
||||
})
|
||||
|
||||
it("CreateSucceedsWhenGivenATokenAndTheWebhookAuthenticatesTheToken", func() {
|
||||
it("CreateSucceedsWhenGivenATokenAndTheAuthenticatorAuthenticatesTheToken", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
@@ -106,6 +106,7 @@ func TestCreate(t *testing.T) {
|
||||
clientCertIssuer.EXPECT().IssueClientCertPEM(
|
||||
"test-user",
|
||||
[]string{"test-group-1", "test-group-2"},
|
||||
nil,
|
||||
5*time.Minute,
|
||||
).Return(&cert.PEM{
|
||||
CertPEM: []byte("test-cert"),
|
||||
@@ -150,6 +151,7 @@ func TestCreate(t *testing.T) {
|
||||
"personalInfo": map[string]any{
|
||||
"username": "test-user",
|
||||
"groups": []any{"test-group-1", "test-group-2"},
|
||||
"extras": map[string]any{},
|
||||
},
|
||||
}),
|
||||
}
|
||||
@@ -167,7 +169,7 @@ func TestCreate(t *testing.T) {
|
||||
|
||||
clientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
clientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
IssueClientCertPEM(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
Return(nil, fmt.Errorf("some certificate authority error"))
|
||||
|
||||
storage := NewREST(requestAuthenticator, clientCertIssuer, schema.GroupResource{}, auditLogger)
|
||||
@@ -193,7 +195,7 @@ func TestCreate(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenGivenATokenAndTheWebhookReturnsNilUser", func() {
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenGivenATokenAndTheAuthenticatorReturnsNilUser", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
@@ -222,12 +224,12 @@ func TestCreate(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenWebhookFails", func() {
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenAuthenticatorFails", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
requestAuthenticator.EXPECT().AuthenticateTokenCredentialRequest(gomock.Any(), req).
|
||||
Return(nil, errors.New("some webhook error"))
|
||||
Return(nil, errors.New("some authentication error"))
|
||||
|
||||
storage := NewREST(requestAuthenticator, nil, schema.GroupResource{}, auditLogger)
|
||||
|
||||
@@ -248,12 +250,12 @@ func TestCreate(t *testing.T) {
|
||||
"name": "fake-authenticator-name",
|
||||
},
|
||||
"reason": "authenticator returned an error",
|
||||
"err": "some webhook error",
|
||||
"err": "some authentication error",
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenWebhookReturnsAnEmptyUsername", func() {
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenAuthenticatorReturnsAnEmptyUsername", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
@@ -289,7 +291,7 @@ func TestCreate(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenWebhookReturnsAUserWithUID", func() {
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenAuthenticatorReturnsAUserWithUID", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
@@ -329,47 +331,7 @@ func TestCreate(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenWebhookReturnsAUserWithExtra", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
requestAuthenticator.EXPECT().AuthenticateTokenCredentialRequest(gomock.Any(), req).
|
||||
Return(&user.DefaultInfo{
|
||||
Name: "test-user",
|
||||
Groups: []string{"test-group-1", "test-group-2"},
|
||||
Extra: map[string][]string{"test-key": {"test-val-1", "test-val-2"}},
|
||||
}, nil)
|
||||
|
||||
storage := NewREST(requestAuthenticator, nil, schema.GroupResource{}, auditLogger)
|
||||
|
||||
response, err := callCreate(storage, req)
|
||||
|
||||
requireSuccessfulResponseWithAuthenticationFailureMessage(t, err, response)
|
||||
|
||||
wantAuditLog = []testutil.WantedAuditLog{
|
||||
testutil.WantAuditLog("TokenCredentialRequest Token Received", map[string]any{
|
||||
"auditID": "fake-audit-id",
|
||||
"tokenID": tokenToHash(req.Spec.Token),
|
||||
}),
|
||||
testutil.WantAuditLog("TokenCredentialRequest Unsupported UserInfo", map[string]any{
|
||||
"auditID": "fake-audit-id",
|
||||
"authenticator": map[string]any{
|
||||
"apiGroup": "fake-api-group.com",
|
||||
"kind": "FakeAuthenticatorKind",
|
||||
"name": "fake-authenticator-name",
|
||||
},
|
||||
"reason": "unsupported value in userInfo returned by authenticator",
|
||||
"err": "extra may have only one key 'authentication.kubernetes.io/credential-id'",
|
||||
"userInfoExtrasCount": float64(1),
|
||||
"personalInfo": map[string]any{
|
||||
"userInfoName": "test-user",
|
||||
"userInfoUID": "",
|
||||
},
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenWebhookReturnsAUserWithTooManyExtra", func() {
|
||||
it("CreateSucceedsWhenAuthenticatorReturnsAUserWithExtras", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
@@ -378,55 +340,22 @@ func TestCreate(t *testing.T) {
|
||||
Name: "test-user",
|
||||
Groups: []string{"test-group-1", "test-group-2"},
|
||||
Extra: map[string][]string{
|
||||
"test-key": {"test-val-1", "test-val-2"},
|
||||
"authentication.kubernetes.io/credential-id": {"some-value"},
|
||||
"authentication.kubernetes.io/credential-id": {"test-val-1", "test-val-2"},
|
||||
"example.com/extra1": {"test-val-a"},
|
||||
"example.com/extra2": {"test-val-b"},
|
||||
},
|
||||
}, nil)
|
||||
|
||||
storage := NewREST(requestAuthenticator, nil, schema.GroupResource{}, auditLogger)
|
||||
|
||||
response, err := callCreate(storage, req)
|
||||
|
||||
requireSuccessfulResponseWithAuthenticationFailureMessage(t, err, response)
|
||||
|
||||
wantAuditLog = []testutil.WantedAuditLog{
|
||||
testutil.WantAuditLog("TokenCredentialRequest Token Received", map[string]any{
|
||||
"auditID": "fake-audit-id",
|
||||
"tokenID": tokenToHash(req.Spec.Token),
|
||||
}),
|
||||
testutil.WantAuditLog("TokenCredentialRequest Unsupported UserInfo", map[string]any{
|
||||
"auditID": "fake-audit-id",
|
||||
"authenticator": map[string]any{
|
||||
"apiGroup": "fake-api-group.com",
|
||||
"kind": "FakeAuthenticatorKind",
|
||||
"name": "fake-authenticator-name",
|
||||
},
|
||||
"reason": "unsupported value in userInfo returned by authenticator",
|
||||
"err": "extra may have only one key 'authentication.kubernetes.io/credential-id'",
|
||||
"userInfoExtrasCount": float64(2),
|
||||
"personalInfo": map[string]any{
|
||||
"userInfoName": "test-user",
|
||||
"userInfoUID": "",
|
||||
},
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWhenWebhookReturnsAUserWithValidExtra", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
requestAuthenticator.EXPECT().AuthenticateTokenCredentialRequest(gomock.Any(), req).
|
||||
Return(&user.DefaultInfo{
|
||||
Name: "test-user",
|
||||
Groups: []string{"test-group-1", "test-group-2"},
|
||||
Extra: map[string][]string{"authentication.kubernetes.io/credential-id": {"test-val-1", "test-val-2"}},
|
||||
}, nil)
|
||||
|
||||
clientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
clientCertIssuer.EXPECT().IssueClientCertPEM(
|
||||
"test-user",
|
||||
[]string{"test-group-1", "test-group-2"},
|
||||
[]string{
|
||||
"authentication.kubernetes.io/credential-id=test-val-1",
|
||||
"authentication.kubernetes.io/credential-id=test-val-2",
|
||||
"example.com/extra1=test-val-a",
|
||||
"example.com/extra2=test-val-b",
|
||||
},
|
||||
5*time.Minute,
|
||||
).Return(&cert.PEM{
|
||||
CertPEM: []byte("test-cert"),
|
||||
@@ -471,6 +400,51 @@ func TestCreate(t *testing.T) {
|
||||
"personalInfo": map[string]any{
|
||||
"username": "test-user",
|
||||
"groups": []any{"test-group-1", "test-group-2"},
|
||||
"extras": map[string]any{
|
||||
"authentication.kubernetes.io/credential-id": []any{"test-val-1", "test-val-2"},
|
||||
"example.com/extra1": []any{"test-val-a"},
|
||||
"example.com/extra2": []any{"test-val-b"},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
it("CreateSucceedsWithAnUnauthenticatedStatusWhenWebhookReturnsAUserWithInvalidExtraKey", func() {
|
||||
req := validCredentialRequest()
|
||||
|
||||
requestAuthenticator := mockcredentialrequest.NewMockTokenCredentialRequestAuthenticator(ctrl)
|
||||
requestAuthenticator.EXPECT().AuthenticateTokenCredentialRequest(gomock.Any(), req).
|
||||
Return(&user.DefaultInfo{
|
||||
Name: "test-user",
|
||||
Groups: []string{"test-group-1", "test-group-2"},
|
||||
Extra: map[string][]string{"key-name": {"test-val-1", "test-val-2"}},
|
||||
}, nil)
|
||||
|
||||
storage := NewREST(requestAuthenticator, nil, schema.GroupResource{}, auditLogger)
|
||||
|
||||
response, err := callCreate(storage, req)
|
||||
|
||||
requireSuccessfulResponseWithAuthenticationFailureMessage(t, err, response)
|
||||
|
||||
wantAuditLog = []testutil.WantedAuditLog{
|
||||
testutil.WantAuditLog("TokenCredentialRequest Token Received", map[string]any{
|
||||
"auditID": "fake-audit-id",
|
||||
"tokenID": tokenToHash(req.Spec.Token),
|
||||
}),
|
||||
testutil.WantAuditLog("TokenCredentialRequest Unsupported UserInfo", map[string]any{
|
||||
"auditID": "fake-audit-id",
|
||||
"authenticator": map[string]any{
|
||||
"apiGroup": "fake-api-group.com",
|
||||
"kind": "FakeAuthenticatorKind",
|
||||
"name": "fake-authenticator-name",
|
||||
},
|
||||
"reason": "unsupported value in userInfo returned by authenticator",
|
||||
"err": `authenticator returned illegal userInfo extra key(s): userInfo extra key "key-name": Invalid value: "key-name": must be a domain-prefixed path (such as "acme.io/foo")`,
|
||||
"userInfoExtrasCount": float64(1),
|
||||
"personalInfo": map[string]any{
|
||||
"userInfoName": "test-user",
|
||||
"userInfoUID": "",
|
||||
},
|
||||
}),
|
||||
}
|
||||
@@ -552,6 +526,7 @@ func TestCreate(t *testing.T) {
|
||||
"personalInfo": map[string]any{
|
||||
"username": "test-user",
|
||||
"groups": []any{},
|
||||
"extras": map[string]any{},
|
||||
},
|
||||
}),
|
||||
}
|
||||
@@ -606,6 +581,7 @@ func TestCreate(t *testing.T) {
|
||||
"personalInfo": map[string]any{
|
||||
"username": "test-user",
|
||||
"groups": []any{},
|
||||
"extras": map[string]any{},
|
||||
},
|
||||
}),
|
||||
}
|
||||
@@ -697,7 +673,7 @@ func requireSuccessfulResponseWithAuthenticationFailureMessage(t *testing.T, err
|
||||
func successfulIssuer(ctrl *gomock.Controller, fakeNow time.Time) clientcertissuer.ClientCertIssuer {
|
||||
clientCertIssuer := mockissuer.NewMockClientCertIssuer(ctrl)
|
||||
clientCertIssuer.EXPECT().
|
||||
IssueClientCertPEM(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
IssueClientCertPEM(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
Return(&cert.PEM{
|
||||
CertPEM: []byte("test-cert"),
|
||||
KeyPEM: []byte("test-key"),
|
||||
@@ -706,3 +682,112 @@ func successfulIssuer(ctrl *gomock.Controller, fakeNow time.Time) clientcertissu
|
||||
}, nil)
|
||||
return clientCertIssuer
|
||||
}
|
||||
|
||||
func TestValidateExtraKeys(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
extras map[string][]string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "allowed extras keys cause no error",
|
||||
extras: map[string][]string{
|
||||
"foo.com/example": {"foo"},
|
||||
"x.y.z.foo.io/some-path": {"bar"},
|
||||
"authentication.kubernetes.io/credential-id": {"baz"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty extras keys cause error",
|
||||
extras: map[string][]string{
|
||||
"": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `userInfo extra key "": Required value`,
|
||||
},
|
||||
{
|
||||
name: "extras keys not prefixed by domain name cause error",
|
||||
extras: map[string][]string{
|
||||
"foo": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `userInfo extra key "foo": Invalid value: "foo": must be a domain-prefixed path (such as "acme.io/foo")`,
|
||||
},
|
||||
{
|
||||
name: "extras keys with upper case chars cause error",
|
||||
extras: map[string][]string{
|
||||
"fooBar.com/value": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `userInfo extra key "fooBar.com/value": Invalid value: "fooBar.com": ` +
|
||||
`a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', ` +
|
||||
`and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is ` +
|
||||
`'[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')`,
|
||||
},
|
||||
{
|
||||
name: "extras keys with unexpected chars in domain name cause error",
|
||||
extras: map[string][]string{
|
||||
"foobar🦭.com/path": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `userInfo extra key "foobar🦭.com/path": Invalid value: "foobar🦭.com": ` +
|
||||
`a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', ` +
|
||||
`and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is ` +
|
||||
`'[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')`,
|
||||
},
|
||||
{
|
||||
name: "extras keys with unexpected chars in path cause error",
|
||||
extras: map[string][]string{
|
||||
"foobar.com/🦭": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `userInfo extra key "foobar.com/🦭": Invalid value: "🦭": ` +
|
||||
`Invalid path (regex used for validation is '[A-Za-z0-9/\-._~%!$&'()*+,;=:]+')`,
|
||||
},
|
||||
{
|
||||
name: "extras keys with k8s.io cause error",
|
||||
extras: map[string][]string{
|
||||
"k8s.io/some-path": {"foo"},
|
||||
"sub.k8s.io/some-path": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `[` +
|
||||
`userInfo extra key "k8s.io/some-path": Invalid value: "k8s.io/some-path": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use, ` +
|
||||
`userInfo extra key "sub.k8s.io/some-path": Invalid value: "sub.k8s.io/some-path": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use` +
|
||||
`]`,
|
||||
},
|
||||
{
|
||||
name: "extras keys with kubernetes.io cause error",
|
||||
extras: map[string][]string{
|
||||
"kubernetes.io/some-path": {"foo"},
|
||||
"sub.kubernetes.io/some-path": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `[` +
|
||||
`userInfo extra key "kubernetes.io/some-path": Invalid value: "kubernetes.io/some-path": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use, ` +
|
||||
`userInfo extra key "sub.kubernetes.io/some-path": Invalid value: "sub.kubernetes.io/some-path": k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use` +
|
||||
`]`,
|
||||
},
|
||||
{
|
||||
name: "extras keys with equals sign cause error",
|
||||
extras: map[string][]string{
|
||||
"foobar.com/some=path": {"foo"},
|
||||
"foo.io/some-path": {"bar"},
|
||||
},
|
||||
wantErr: `userInfo extra key "foobar.com/some=path": Invalid value: "foobar.com/some=path": Pinniped does not allow extra key names to contain equals sign`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := validateExtraKeys(tt.extras)
|
||||
|
||||
if tt.wantErr == "" {
|
||||
require.Nilf(t, err, "wanted no error but got %s", err.ToAggregate())
|
||||
} else {
|
||||
require.EqualError(t, err.ToAggregate(), tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package testutil
|
||||
@@ -122,11 +122,18 @@ func (v *ValidCert) RequireCommonName(commonName string) {
|
||||
require.Equal(v.t, commonName, v.parsed.Subject.CommonName)
|
||||
}
|
||||
|
||||
// RequireOrganizations asserts that the certificate contains the provided orgs in the subject.
|
||||
func (v *ValidCert) RequireOrganizations(orgs []string) {
|
||||
v.t.Helper()
|
||||
require.Equal(v.t, orgs, v.parsed.Subject.Organization)
|
||||
}
|
||||
|
||||
// RequireOrganizationalUnits asserts that the certificate contains the provided organizational units in the subject.
|
||||
func (v *ValidCert) RequireOrganizationalUnits(ous []string) {
|
||||
v.t.Helper()
|
||||
require.Equal(v.t, ous, v.parsed.Subject.OrganizationalUnit)
|
||||
}
|
||||
|
||||
// CreateCertificate creates a certificate with the provided time bounds, and returns the PEM
|
||||
// representation of the certificate and its private key. The returned certificate is capable of
|
||||
// signing child certificates.
|
||||
|
||||
@@ -209,6 +209,7 @@ func TestAuditLogsDuringLogin_Disruptive(t *testing.T) {
|
||||
"personalInfo": map[string]any{
|
||||
"username": "redacted",
|
||||
"groups": []any{"redacted 2 values"},
|
||||
"extras": map[string]any{"redacted": "redacted 1 keys"},
|
||||
},
|
||||
},
|
||||
}, allConciergeTCRLogs)
|
||||
@@ -342,6 +343,25 @@ func TestAuditLogsDuringLogin_Disruptive(t *testing.T) {
|
||||
for _, log := range allConciergeTCRLogs {
|
||||
require.NotEmpty(t, log["issuedClientCert"])
|
||||
delete(log, "issuedClientCert")
|
||||
|
||||
// The value at the extras key "authentication.kubernetes.io/credential-id" will be a JWT ID,
|
||||
// which is hard to predict, so just assert that it is there without worrying about its exact value.
|
||||
require.Contains(t, log, "personalInfo")
|
||||
personalInfo, ok := log["personalInfo"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, personalInfo["extras"])
|
||||
extras, ok := personalInfo["extras"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.Contains(t, extras, "authentication.kubernetes.io/credential-id")
|
||||
require.Len(t, extras, 1) // should be the only key
|
||||
id := extras["authentication.kubernetes.io/credential-id"]
|
||||
idValues, ok := id.([]any)
|
||||
require.True(t, ok)
|
||||
require.Len(t, idValues, 1)
|
||||
require.Regexp(t, "JTI=.+", idValues[0])
|
||||
// Now that we have made assertions about all the expected extras,
|
||||
// delete it so we can compare the rest using equals below.
|
||||
delete(personalInfo, "extras")
|
||||
}
|
||||
|
||||
// All values in the personalInfo map should not be redacted anymore.
|
||||
@@ -357,6 +377,7 @@ func TestAuditLogsDuringLogin_Disruptive(t *testing.T) {
|
||||
"personalInfo": map[string]any{
|
||||
"username": expectedUsername,
|
||||
"groups": expectedGroups,
|
||||
// note: also has an "extras" key, which we deleted from the actual value above
|
||||
},
|
||||
},
|
||||
}, allConciergeTCRLogs)
|
||||
|
||||
@@ -222,7 +222,7 @@ func TestCLILoginOIDC_Browser(t *testing.T) {
|
||||
cacheKey := oidcclient.SessionCacheKey{
|
||||
Issuer: env.CLIUpstreamOIDC.Issuer,
|
||||
ClientID: env.CLIUpstreamOIDC.ClientID,
|
||||
Scopes: []string{"email", "offline_access", "openid", "profile"},
|
||||
Scopes: []string{"email", "groups", "offline_access", "openid", "profile"}, // in alphabetical order
|
||||
RedirectURI: strings.ReplaceAll(env.CLIUpstreamOIDC.CallbackURL, "127.0.0.1", "localhost"),
|
||||
}
|
||||
cached := cache.GetToken(cacheKey)
|
||||
@@ -413,7 +413,7 @@ func oidcLoginCommand(ctx context.Context, t *testing.T, pinnipedExe string, ses
|
||||
cmd := exec.CommandContext(ctx, pinnipedExe, "login", "oidc",
|
||||
"--issuer", env.CLIUpstreamOIDC.Issuer,
|
||||
"--client-id", env.CLIUpstreamOIDC.ClientID,
|
||||
"--scopes", "offline_access,openid,email,profile",
|
||||
"--scopes", "offline_access,openid,email,profile,groups",
|
||||
"--listen-port", callbackURL.Port(),
|
||||
"--session-cache", sessionCachePath,
|
||||
"--credential-cache", t.TempDir()+"/credentials.yaml",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package integration
|
||||
@@ -6,7 +6,9 @@ package integration
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -23,12 +25,306 @@ import (
|
||||
"go.pinniped.dev/test/testlib"
|
||||
)
|
||||
|
||||
// TestCredentialRequest_Browser cannot run in parallel because runPinnipedLoginOIDC uses a fixed port
|
||||
// for its localhost listener via --listen-port=env.CLIUpstreamOIDC.CallbackURL.Port() per oidcLoginCommand.
|
||||
// Since ports are global to the process, tests using oidcLoginCommand must be run serially.
|
||||
func TestCredentialRequest_Browser(t *testing.T) {
|
||||
env := testlib.IntegrationEnv(t).WithCapability(testlib.ClusterSigningKeyIsAvailable)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Minute)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
jwtAuthenticatorTypedLocalObjectReference := func(a *authenticationv1alpha1.JWTAuthenticator) corev1.TypedLocalObjectReference {
|
||||
return corev1.TypedLocalObjectReference{
|
||||
APIGroup: &authenticationv1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "JWTAuthenticator",
|
||||
Name: a.Name,
|
||||
}
|
||||
}
|
||||
|
||||
expectedExtras := func(t *testing.T, jwt string) []string {
|
||||
// Dex tokens do not include a jti claim, so check if it exists.
|
||||
claims := getJWTClaims(t, jwt)
|
||||
_, ok := claims["jti"]
|
||||
if !ok {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// Okta tokens contain a jti, so use it to make the expected value.
|
||||
jti := getJWTClaimAsString(t, jwt, "jti")
|
||||
require.NotEmpty(t, jti)
|
||||
return []string{
|
||||
// The Kubernetes jwtAuthenticator will automatically add this extra when there is a jti claim.
|
||||
fmt.Sprintf("authentication.kubernetes.io/credential-id=JTI=%s", jti),
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
authenticator func(context.Context, *testing.T) corev1.TypedLocalObjectReference
|
||||
token func(t *testing.T) (tokenToSubmit string, wantUsername string, wantGroups []string, wantExtras []string)
|
||||
}{
|
||||
{
|
||||
name: "webhook",
|
||||
authenticator: func(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
return testlib.CreateTestWebhookAuthenticator(ctx, t, &env.TestWebhook, authenticationv1alpha1.WebhookAuthenticatorPhaseReady)
|
||||
},
|
||||
token: func(t *testing.T) (string, string, []string, []string) {
|
||||
return env.TestUser.Token, env.TestUser.ExpectedUsername, env.TestUser.ExpectedGroups, []string{}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "minimal jwt authenticator",
|
||||
authenticator: func(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
authenticator := testlib.CreateTestJWTAuthenticator(ctx, t, authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.CLIUpstreamOIDC.Issuer,
|
||||
Audience: env.CLIUpstreamOIDC.ClientID,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Username: env.CLIUpstreamOIDC.UsernameClaim,
|
||||
Groups: env.CLIUpstreamOIDC.GroupsClaim,
|
||||
},
|
||||
TLS: tlsSpecForCLIUpstreamOIDC(t),
|
||||
}, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
|
||||
|
||||
return jwtAuthenticatorTypedLocalObjectReference(authenticator)
|
||||
},
|
||||
token: func(t *testing.T) (string, string, []string, []string) {
|
||||
pinnipedExe := testlib.PinnipedCLIPath(t)
|
||||
credOutput, _ := runPinnipedLoginOIDC(ctx, t, pinnipedExe)
|
||||
token := credOutput.Status.Token
|
||||
|
||||
// Sanity check that the JWT contains the expected username claim.
|
||||
username := getJWTClaimAsString(t, token, env.CLIUpstreamOIDC.UsernameClaim)
|
||||
require.Equal(t, env.CLIUpstreamOIDC.Username, username)
|
||||
|
||||
// Sanity check that the JWT contains the expected groups claim.
|
||||
// Dex doesn't return groups, so only check where we are expecting groups.
|
||||
if len(env.CLIUpstreamOIDC.ExpectedGroups) > 0 {
|
||||
groups := getJWTClaimAsStringSlice(t, token, env.CLIUpstreamOIDC.GroupsClaim)
|
||||
t.Logf("found groups in JWT token: %#v", groups)
|
||||
require.ElementsMatch(t, groups, env.CLIUpstreamOIDC.ExpectedGroups)
|
||||
}
|
||||
|
||||
return token, env.CLIUpstreamOIDC.Username, env.CLIUpstreamOIDC.ExpectedGroups, expectedExtras(t, token)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jwt authenticator with username and groups CEL expressions and additional extras and validation rules which allow auth",
|
||||
authenticator: func(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
authenticator := testlib.CreateTestJWTAuthenticator(ctx, t, authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.CLIUpstreamOIDC.Issuer,
|
||||
Audience: env.CLIUpstreamOIDC.ClientID,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
UsernameExpression: "claims.sub",
|
||||
GroupsExpression: `["group1", "group2"]`,
|
||||
Extra: []authenticationv1alpha1.ExtraMapping{
|
||||
{
|
||||
Key: "example.com/sub",
|
||||
ValueExpression: "claims.sub",
|
||||
},
|
||||
{
|
||||
Key: "example.com/const",
|
||||
ValueExpression: `"some-value"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
ClaimValidationRules: []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Claim: env.CLIUpstreamOIDC.UsernameClaim,
|
||||
RequiredValue: env.CLIUpstreamOIDC.Username,
|
||||
},
|
||||
{
|
||||
Expression: fmt.Sprintf("claims.%s == '%s'", env.CLIUpstreamOIDC.UsernameClaim, env.CLIUpstreamOIDC.Username),
|
||||
Message: "only one specific user is allowed",
|
||||
},
|
||||
},
|
||||
UserValidationRules: []authenticationv1alpha1.UserValidationRule{
|
||||
{
|
||||
Expression: "!user.username.startsWith('system:')",
|
||||
Message: "username cannot used reserved system: prefix",
|
||||
},
|
||||
},
|
||||
TLS: tlsSpecForCLIUpstreamOIDC(t),
|
||||
}, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
|
||||
|
||||
return jwtAuthenticatorTypedLocalObjectReference(authenticator)
|
||||
},
|
||||
token: func(t *testing.T) (string, string, []string, []string) {
|
||||
pinnipedExe := testlib.PinnipedCLIPath(t)
|
||||
credOutput, _ := runPinnipedLoginOIDC(ctx, t, pinnipedExe)
|
||||
token := credOutput.Status.Token
|
||||
|
||||
subject := getJWTClaimAsString(t, token, "sub")
|
||||
require.NotEmpty(t, subject)
|
||||
|
||||
wantExtras := expectedExtras(t, token)
|
||||
wantExtras = append(wantExtras, fmt.Sprintf("example.com/sub=%s", subject))
|
||||
wantExtras = append(wantExtras, "example.com/const=some-value")
|
||||
|
||||
return token, subject, []string{"group1", "group2"}, wantExtras
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
authenticatorRefToSubmit := test.authenticator(ctx, t)
|
||||
tokenToSubmit, wantUsername, wantGroups, wantExtras := test.token(t)
|
||||
|
||||
var response *loginv1alpha1.TokenCredentialRequest
|
||||
testlib.RequireEventually(t, func(requireEventually *require.Assertions) {
|
||||
var err error
|
||||
response, err = testlib.CreateTokenCredentialRequest(ctx, t,
|
||||
loginv1alpha1.TokenCredentialRequestSpec{Token: tokenToSubmit, Authenticator: authenticatorRefToSubmit},
|
||||
)
|
||||
requireEventually.NoError(err, "the request should never fail at the HTTP level")
|
||||
requireEventually.NotNil(response)
|
||||
requireEventually.NotNil(response.Status.Credential, "the response should contain a credential")
|
||||
requireEventually.Emptyf(response.Status.Message, "value is: %q", safeDerefStringPtr(response.Status.Message))
|
||||
requireEventually.NotNil(response.Status.Credential)
|
||||
requireEventually.Empty(response.Spec)
|
||||
requireEventually.Empty(response.Status.Credential.Token)
|
||||
requireEventually.NotEmpty(response.Status.Credential.ClientCertificateData)
|
||||
requireEventually.Equal(wantUsername, getCommonName(t, response.Status.Credential.ClientCertificateData))
|
||||
requireEventually.ElementsMatch(wantGroups, getOrganizations(t, response.Status.Credential.ClientCertificateData))
|
||||
requireEventually.ElementsMatch(wantExtras, getOrganizationalUnits(t, response.Status.Credential.ClientCertificateData))
|
||||
requireEventually.NotEmpty(response.Status.Credential.ClientKeyData)
|
||||
requireEventually.NotNil(response.Status.Credential.ExpirationTimestamp)
|
||||
requireEventually.InDelta(5*time.Minute, time.Until(response.Status.Credential.ExpirationTimestamp.Time), float64(time.Minute))
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
|
||||
// Create a client using the certificate from the CredentialRequest.
|
||||
clientWithCertFromCredentialRequest := testlib.NewClientsetWithCertAndKey(
|
||||
t,
|
||||
response.Status.Credential.ClientCertificateData,
|
||||
response.Status.Credential.ClientKeyData,
|
||||
)
|
||||
|
||||
t.Run(
|
||||
"access as user",
|
||||
testlib.AccessAsUserTest(ctx, wantUsername, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
for _, group := range wantGroups {
|
||||
t.Run(
|
||||
"access as group "+group,
|
||||
testlib.AccessAsGroupTest(ctx, group, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// This test cannot run in parallel because runPinnipedLoginOIDC uses a fixed port
|
||||
// for its localhost listener via --listen-port=env.CLIUpstreamOIDC.CallbackURL.Port() per oidcLoginCommand.
|
||||
// Since ports are global to the process, tests using oidcLoginCommand must be run serially.
|
||||
func TestCredentialRequest_JWTAuthenticatorRulesToDisallowLogin_Browser(t *testing.T) {
|
||||
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
|
||||
|
||||
basicSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.CLIUpstreamOIDC.Issuer,
|
||||
Audience: env.CLIUpstreamOIDC.ClientID,
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Username: env.CLIUpstreamOIDC.UsernameClaim,
|
||||
Groups: env.CLIUpstreamOIDC.GroupsClaim,
|
||||
},
|
||||
TLS: tlsSpecForCLIUpstreamOIDC(t),
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
authenticator func(context.Context, *testing.T) *authenticationv1alpha1.JWTAuthenticator
|
||||
wantSuccessfulAuth bool
|
||||
}{
|
||||
{
|
||||
// Sanity check to make sure that the basic JWTAuthenticator spec works before adding rules which should cause auth failure.
|
||||
name: "JWTAuthenticator successful login",
|
||||
authenticator: func(ctx context.Context, t *testing.T) *authenticationv1alpha1.JWTAuthenticator {
|
||||
return testlib.CreateTestJWTAuthenticator(ctx, t, *basicSpec.DeepCopy(), authenticationv1alpha1.JWTAuthenticatorPhaseReady)
|
||||
},
|
||||
wantSuccessfulAuth: true,
|
||||
},
|
||||
{
|
||||
name: "JWTAuthenticator ClaimValidationRules using CEL expression should be able to prevent login",
|
||||
authenticator: func(ctx context.Context, t *testing.T) *authenticationv1alpha1.JWTAuthenticator {
|
||||
spec := basicSpec.DeepCopy()
|
||||
spec.ClaimValidationRules = []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
// This should cause the login to fail for this specific user.
|
||||
Expression: fmt.Sprintf("claims.%s != '%s'", env.CLIUpstreamOIDC.UsernameClaim, env.CLIUpstreamOIDC.Username),
|
||||
Message: "one specific user is disallowed",
|
||||
},
|
||||
}
|
||||
return testlib.CreateTestJWTAuthenticator(ctx, t, *spec, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "JWTAuthenticator ClaimValidationRules using RequiredValue should be able to prevent login",
|
||||
authenticator: func(ctx context.Context, t *testing.T) *authenticationv1alpha1.JWTAuthenticator {
|
||||
spec := basicSpec.DeepCopy()
|
||||
spec.ClaimValidationRules = []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Claim: "sub",
|
||||
RequiredValue: "this-will-never-be-the-sub-value",
|
||||
},
|
||||
}
|
||||
return testlib.CreateTestJWTAuthenticator(ctx, t, *spec, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "JWTAuthenticator UserValidationRules CEL expressions should be able to prevent login",
|
||||
authenticator: func(ctx context.Context, t *testing.T) *authenticationv1alpha1.JWTAuthenticator {
|
||||
spec := basicSpec.DeepCopy()
|
||||
spec.UserValidationRules = []authenticationv1alpha1.UserValidationRule{
|
||||
{
|
||||
Expression: "false",
|
||||
Message: "nobody is allowed to auth",
|
||||
},
|
||||
}
|
||||
return testlib.CreateTestJWTAuthenticator(ctx, t, *spec, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Minute)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
authenticator := test.authenticator(ctx, t)
|
||||
|
||||
pinnipedExe := testlib.PinnipedCLIPath(t)
|
||||
credOutput, _ := runPinnipedLoginOIDC(ctx, t, pinnipedExe)
|
||||
|
||||
response, err := testlib.CreateTokenCredentialRequest(ctx, t,
|
||||
loginv1alpha1.TokenCredentialRequestSpec{
|
||||
Token: credOutput.Status.Token,
|
||||
Authenticator: corev1.TypedLocalObjectReference{
|
||||
APIGroup: &authenticationv1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "JWTAuthenticator",
|
||||
Name: authenticator.Name,
|
||||
},
|
||||
},
|
||||
)
|
||||
require.NoError(t, err, testlib.Sdump(err))
|
||||
|
||||
if test.wantSuccessfulAuth {
|
||||
require.NotEmpty(t, response.Status.Credential)
|
||||
require.Empty(t, response.Status.Message)
|
||||
} else {
|
||||
require.Nil(t, response.Status.Credential)
|
||||
require.NotNil(t, response.Status.Message)
|
||||
require.Equal(t, "authentication failed", *response.Status.Message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TCRs are non-mutating and safe to run in parallel with serial tests, see main_test.go.
|
||||
func TestUnsuccessfulCredentialRequest_Parallel(t *testing.T) {
|
||||
func TestCredentialRequest_ShouldFailWhenTheAuthenticatorDoesNotExist_Parallel(t *testing.T) {
|
||||
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
t.Cleanup(cancel)
|
||||
|
||||
response, err := testlib.CreateTokenCredentialRequest(ctx, t,
|
||||
loginv1alpha1.TokenCredentialRequestSpec{
|
||||
@@ -46,110 +342,15 @@ func TestUnsuccessfulCredentialRequest_Parallel(t *testing.T) {
|
||||
require.Equal(t, "authentication failed", *response.Status.Message)
|
||||
}
|
||||
|
||||
// TestSuccessfulCredentialRequest_Browser cannot run in parallel because runPinnipedLoginOIDC uses a fixed port
|
||||
// for its localhost listener via --listen-port=env.CLIUpstreamOIDC.CallbackURL.Port() per oidcLoginCommand.
|
||||
// Since ports are global to the process, tests using oidcLoginCommand must be run serially.
|
||||
func TestSuccessfulCredentialRequest_Browser(t *testing.T) {
|
||||
env := testlib.IntegrationEnv(t).WithCapability(testlib.ClusterSigningKeyIsAvailable)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
authenticator func(context.Context, *testing.T) corev1.TypedLocalObjectReference
|
||||
token func(t *testing.T) (token string, username string, groups []string)
|
||||
}{
|
||||
{
|
||||
name: "webhook",
|
||||
authenticator: func(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
return testlib.CreateTestWebhookAuthenticator(ctx, t, &testlib.IntegrationEnv(t).TestWebhook, authenticationv1alpha1.WebhookAuthenticatorPhaseReady)
|
||||
},
|
||||
token: func(t *testing.T) (string, string, []string) {
|
||||
return testlib.IntegrationEnv(t).TestUser.Token, env.TestUser.ExpectedUsername, env.TestUser.ExpectedGroups
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jwt authenticator",
|
||||
authenticator: func(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
authenticator := testlib.CreateTestJWTAuthenticatorForCLIUpstream(ctx, t)
|
||||
return corev1.TypedLocalObjectReference{
|
||||
APIGroup: &authenticationv1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "JWTAuthenticator",
|
||||
Name: authenticator.Name,
|
||||
}
|
||||
},
|
||||
token: func(t *testing.T) (string, string, []string) {
|
||||
pinnipedExe := testlib.PinnipedCLIPath(t)
|
||||
credOutput, _ := runPinnipedLoginOIDC(ctx, t, pinnipedExe)
|
||||
token := credOutput.Status.Token
|
||||
|
||||
// By default, the JWTAuthenticator expects the username to be in the "username" claim and the
|
||||
// groups to be in the "groups" claim.
|
||||
// However, we are configuring Pinniped in the `CreateTestJWTAuthenticatorForCLIUpstream` method above
|
||||
// to read the username from the "sub" claim of the token instead.
|
||||
username, groups := getJWTSubAndGroupsClaims(t, token)
|
||||
|
||||
return token, username, groups
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
authenticator := test.authenticator(ctx, t)
|
||||
token, username, groups := test.token(t)
|
||||
|
||||
var response *loginv1alpha1.TokenCredentialRequest
|
||||
testlib.RequireEventually(t, func(requireEventually *require.Assertions) {
|
||||
var err error
|
||||
response, err = testlib.CreateTokenCredentialRequest(ctx, t,
|
||||
loginv1alpha1.TokenCredentialRequestSpec{Token: token, Authenticator: authenticator},
|
||||
)
|
||||
requireEventually.NoError(err, "the request should never fail at the HTTP level")
|
||||
requireEventually.NotNil(response)
|
||||
requireEventually.NotNil(response.Status.Credential, "the response should contain a credential")
|
||||
requireEventually.Emptyf(response.Status.Message, "value is: %q", safeDerefStringPtr(response.Status.Message))
|
||||
requireEventually.NotNil(response.Status.Credential)
|
||||
requireEventually.Empty(response.Spec)
|
||||
requireEventually.Empty(response.Status.Credential.Token)
|
||||
requireEventually.NotEmpty(response.Status.Credential.ClientCertificateData)
|
||||
requireEventually.Equal(username, getCommonName(t, response.Status.Credential.ClientCertificateData))
|
||||
requireEventually.ElementsMatch(groups, getOrganizations(t, response.Status.Credential.ClientCertificateData))
|
||||
requireEventually.NotEmpty(response.Status.Credential.ClientKeyData)
|
||||
requireEventually.NotNil(response.Status.Credential.ExpirationTimestamp)
|
||||
requireEventually.InDelta(5*time.Minute, time.Until(response.Status.Credential.ExpirationTimestamp.Time), float64(time.Minute))
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
|
||||
// Create a client using the certificate from the CredentialRequest.
|
||||
clientWithCertFromCredentialRequest := testlib.NewClientsetWithCertAndKey(
|
||||
t,
|
||||
response.Status.Credential.ClientCertificateData,
|
||||
response.Status.Credential.ClientKeyData,
|
||||
)
|
||||
|
||||
t.Run(
|
||||
"access as user",
|
||||
testlib.AccessAsUserTest(ctx, username, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
for _, group := range groups {
|
||||
t.Run(
|
||||
"access as group "+group,
|
||||
testlib.AccessAsGroupTest(ctx, group, clientWithCertFromCredentialRequest),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TCRs are non-mutating and safe to run in parallel with serial tests, see main_test.go.
|
||||
func TestFailedCredentialRequestWhenTheRequestIsValidButTheTokenDoesNotAuthenticateTheUser_Parallel(t *testing.T) {
|
||||
_ = testlib.IntegrationEnv(t).WithCapability(testlib.ClusterSigningKeyIsAvailable)
|
||||
func TestCredentialRequest_ShouldFailWhenTheRequestIsValidButTheTokenDoesNotAuthenticateTheUser_Parallel(t *testing.T) {
|
||||
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
|
||||
|
||||
// Create a testWebhook so we have a legitimate authenticator to pass to the
|
||||
// TokenCredentialRequest API.
|
||||
// Create a testWebhook so we have a legitimate authenticator to pass to the TokenCredentialRequest API.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
testWebhook := testlib.CreateTestWebhookAuthenticator(ctx, t, &testlib.IntegrationEnv(t).TestWebhook, authenticationv1alpha1.WebhookAuthenticatorPhaseReady)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
testWebhook := testlib.CreateTestWebhookAuthenticator(ctx, t, &env.TestWebhook, authenticationv1alpha1.WebhookAuthenticatorPhaseReady)
|
||||
|
||||
response, err := testlib.CreateTokenCredentialRequest(context.Background(), t,
|
||||
loginv1alpha1.TokenCredentialRequestSpec{Token: "not a good token", Authenticator: testWebhook},
|
||||
@@ -164,13 +365,13 @@ func TestFailedCredentialRequestWhenTheRequestIsValidButTheTokenDoesNotAuthentic
|
||||
|
||||
// TCRs are non-mutating and safe to run in parallel with serial tests, see main_test.go.
|
||||
func TestCredentialRequest_ShouldFailWhenRequestDoesNotIncludeToken_Parallel(t *testing.T) {
|
||||
_ = testlib.IntegrationEnv(t).WithCapability(testlib.ClusterSigningKeyIsAvailable)
|
||||
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
|
||||
|
||||
// Create a testWebhook so we have a legitimate authenticator to pass to the
|
||||
// TokenCredentialRequest API.
|
||||
// Create a testWebhook so we have a legitimate authenticator to pass to the TokenCredentialRequest API.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
testWebhook := testlib.CreateTestWebhookAuthenticator(ctx, t, &testlib.IntegrationEnv(t).TestWebhook, authenticationv1alpha1.WebhookAuthenticatorPhaseReady)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
testWebhook := testlib.CreateTestWebhookAuthenticator(ctx, t, &env.TestWebhook, authenticationv1alpha1.WebhookAuthenticatorPhaseReady)
|
||||
|
||||
response, err := testlib.CreateTokenCredentialRequest(context.Background(), t,
|
||||
loginv1alpha1.TokenCredentialRequestSpec{Token: "", Authenticator: testWebhook},
|
||||
@@ -210,6 +411,16 @@ func getOrganizations(t *testing.T, certPEM string) []string {
|
||||
return cert.Subject.Organization
|
||||
}
|
||||
|
||||
func getOrganizationalUnits(t *testing.T, certPEM string) []string {
|
||||
t.Helper()
|
||||
|
||||
pemBlock, _ := pem.Decode([]byte(certPEM))
|
||||
cert, err := x509.ParseCertificate(pemBlock.Bytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
return cert.Subject.OrganizationalUnit
|
||||
}
|
||||
|
||||
func safeDerefStringPtr(s *string) string {
|
||||
if s == nil {
|
||||
return "<nil>"
|
||||
@@ -217,18 +428,51 @@ func safeDerefStringPtr(s *string) string {
|
||||
return *s
|
||||
}
|
||||
|
||||
func getJWTSubAndGroupsClaims(t *testing.T, jwtToken string) (string, []string) {
|
||||
func getJWTClaimAsString(t *testing.T, jwtToken string, claimName string) string {
|
||||
t.Helper()
|
||||
claims := getJWTClaims(t, jwtToken)
|
||||
require.Contains(t, claims, claimName)
|
||||
val := claims[claimName]
|
||||
strVal, ok := val.(string)
|
||||
require.Truef(t, ok, "expected value of claim %q to be a string, but it was: %#v", claimName, claims[claimName])
|
||||
return strVal
|
||||
}
|
||||
|
||||
func getJWTClaimAsStringSlice(t *testing.T, jwtToken string, claimName string) []string {
|
||||
t.Helper()
|
||||
claims := getJWTClaims(t, jwtToken)
|
||||
require.Contains(t, claims, claimName)
|
||||
val := claims[claimName]
|
||||
anySliceVal, ok := val.([]any)
|
||||
require.Truef(t, ok, "expected value of claim %q to be a []any, but it was: %#v", claimName, claims[claimName])
|
||||
strSliceVal := make([]string, len(anySliceVal))
|
||||
for i := range anySliceVal {
|
||||
strSliceVal[i], ok = anySliceVal[i].(string)
|
||||
require.Truef(t, ok, "expected every value of array at claim %q to be a string, but one element was: %#v", claimName, anySliceVal[i])
|
||||
}
|
||||
return strSliceVal
|
||||
}
|
||||
|
||||
func getJWTClaims(t *testing.T, jwtToken string) map[string]any {
|
||||
t.Helper()
|
||||
|
||||
token, err := josejwt.ParseSigned(jwtToken, []jose.SignatureAlgorithm{jose.ES256, jose.RS256})
|
||||
require.NoError(t, err)
|
||||
|
||||
var claims struct {
|
||||
Sub string `json:"sub"`
|
||||
Groups []string `json:"groups"`
|
||||
}
|
||||
claims := map[string]any{}
|
||||
err = token.UnsafeClaimsWithoutVerification(&claims)
|
||||
require.NoError(t, err)
|
||||
|
||||
return claims.Sub, claims.Groups
|
||||
return claims
|
||||
}
|
||||
|
||||
func tlsSpecForCLIUpstreamOIDC(t *testing.T) *authenticationv1alpha1.TLSSpec {
|
||||
env := testlib.IntegrationEnv(t)
|
||||
// If the test upstream does not have a CA bundle specified, then don't configure it.
|
||||
if env.CLIUpstreamOIDC.CABundle != "" {
|
||||
return &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.CLIUpstreamOIDC.CABundle)),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2024-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package integration
|
||||
@@ -322,6 +322,308 @@ func TestConciergeJWTAuthenticatorStatus_Parallel(t *testing.T) {
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "claims cannot use both username and usernameExpression",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Username: "foo",
|
||||
UsernameExpression: "bar",
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: `could not initialize jwt authenticator: claims.username: Invalid value: "": claim and expression can't both be set`,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "claims cannot use both groups and groupsExpression",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Groups: "foo",
|
||||
GroupsExpression: "bar",
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: `could not initialize jwt authenticator: claims.groups: Invalid value: "": claim and expression can't both be set`,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "username claim expression cannot use clams.email unless it also uses claims.email_verified elsewhere",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
UsernameExpression: "claims.email",
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: `could not initialize jwt authenticator: claims.usernameExpression: Invalid value: "claims.email": ` +
|
||||
`claims.email_verified must be used in claims.usernameExpression or claims.extra[*].valueExpression or ` +
|
||||
`claimValidationRules[*].expression when claims.email is used in claims.usernameExpression`,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "username claim expression cannot use invalid CEL expression",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
UsernameExpression: "this is not a valid CEL expression",
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: "could not initialize jwt authenticator: claims.usernameExpression: Invalid value: " +
|
||||
"\"this is not a valid CEL expression\": compilation failed: ERROR: <input>:1:6: Syntax error: mismatched input 'is' expecting <EOF>\n" +
|
||||
" | this is not a valid CEL expression\n" +
|
||||
" | .....^",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "groups claim expression cannot use invalid CEL expression",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
GroupsExpression: "this is not a valid CEL expression",
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: "could not initialize jwt authenticator: claims.groupsExpression: Invalid value: " +
|
||||
"\"this is not a valid CEL expression\": compilation failed: ERROR: <input>:1:6: Syntax error: mismatched input 'is' expecting <EOF>\n" +
|
||||
" | this is not a valid CEL expression\n" +
|
||||
" | .....^",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "extra keys cannot have equal sign and must be domain-prefixed path",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{
|
||||
Extra: []authenticationv1alpha1.ExtraMapping{
|
||||
{
|
||||
Key: "a=b",
|
||||
ValueExpression: `"value"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: `could not initialize jwt authenticator: [` +
|
||||
`claims.extra[0].key: Invalid value: "a=b": must be a domain-prefixed path (such as "acme.io/foo"), ` +
|
||||
`claims.extra[0].key: Invalid value: "a=b": Pinniped does not allow extra key names to contain equals sign]`,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "claimValidationRules claim and requiredValue are mutually exclusive with expression and message",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
ClaimValidationRules: []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Claim: "foo",
|
||||
RequiredValue: "bar",
|
||||
Expression: "baz",
|
||||
Message: "bat",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: `could not initialize jwt authenticator: claimValidationRules[0]: Invalid value: "foo": claim and expression can't both be set`,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "claimValidationRules cannot use invalid CEL expressions",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
ClaimValidationRules: []authenticationv1alpha1.ClaimValidationRule{
|
||||
{
|
||||
Expression: "this is not a valid CEL expression",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: "could not initialize jwt authenticator: claimValidationRules[0].expression: Invalid value: " +
|
||||
"\"this is not a valid CEL expression\": compilation failed: ERROR: <input>:1:6: Syntax error: mismatched input 'is' expecting <EOF>\n" +
|
||||
" | this is not a valid CEL expression\n" +
|
||||
" | .....^",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "userValidationRules must use valid CEL expressions",
|
||||
spec: authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: env.SupervisorUpstreamOIDC.Issuer,
|
||||
Audience: "some-fake-audience",
|
||||
TLS: &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamOIDC.CABundle)),
|
||||
},
|
||||
UserValidationRules: []authenticationv1alpha1.UserValidationRule{
|
||||
{
|
||||
Expression: "this is not a valid CEL expression",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantPhase: authenticationv1alpha1.JWTAuthenticatorPhaseError,
|
||||
wantConditions: replaceSomeConditions(t,
|
||||
allSuccessfulJWTAuthenticatorConditions(len(env.SupervisorUpstreamOIDC.CABundle) != 0),
|
||||
[]metav1.Condition{
|
||||
{
|
||||
Type: "Ready",
|
||||
Status: "False",
|
||||
Reason: "NotReady",
|
||||
Message: "the JWTAuthenticator is not ready: see other conditions for details",
|
||||
}, {
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "False",
|
||||
Reason: "InvalidAuthenticator",
|
||||
Message: "could not initialize jwt authenticator: userValidationRules[0].expression: Invalid value: " +
|
||||
"\"this is not a valid CEL expression\": compilation failed: ERROR: <input>:1:6: Syntax error: mismatched input 'is' expecting <EOF>\n" +
|
||||
" | this is not a valid CEL expression\n" +
|
||||
" | .....^",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -479,40 +781,42 @@ func allSuccessfulJWTAuthenticatorConditions(caBundleExists bool) []metav1.Condi
|
||||
if caBundleExists {
|
||||
tlsConfigValidMsg = "spec.tls is valid: using configured CA bundle"
|
||||
}
|
||||
return []metav1.Condition{{
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "authenticator initialized",
|
||||
}, {
|
||||
Type: "DiscoveryURLValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "discovery performed successfully",
|
||||
}, {
|
||||
Type: "IssuerURLValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "issuer is a valid URL",
|
||||
}, {
|
||||
Type: "JWKSFetchValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "successfully fetched jwks",
|
||||
}, {
|
||||
Type: "JWKSURLValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "jwks_uri is a valid URL",
|
||||
}, {
|
||||
Type: "Ready",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "the JWTAuthenticator is ready",
|
||||
}, {
|
||||
Type: "TLSConfigurationValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: tlsConfigValidMsg,
|
||||
}}
|
||||
return []metav1.Condition{
|
||||
{
|
||||
Type: "AuthenticatorValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "authenticator initialized",
|
||||
}, {
|
||||
Type: "DiscoveryURLValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "discovery performed successfully",
|
||||
}, {
|
||||
Type: "IssuerURLValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "issuer is a valid URL",
|
||||
}, {
|
||||
Type: "JWKSFetchValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "successfully fetched jwks",
|
||||
}, {
|
||||
Type: "JWKSURLValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "jwks_uri is a valid URL",
|
||||
}, {
|
||||
Type: "Ready",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: "the JWTAuthenticator is ready",
|
||||
}, {
|
||||
Type: "TLSConfigurationValid",
|
||||
Status: "True",
|
||||
Reason: "Success",
|
||||
Message: tlsConfigValidMsg,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,8 +451,9 @@ func TestGetAPIResourceList(t *testing.T) { //nolint:gocyclo // each t.Run is pr
|
||||
}
|
||||
}
|
||||
|
||||
// manually update this value whenever you add additional fields to an API resource and then run the generator
|
||||
totalExpectedAPIFields := 310
|
||||
// Manually update this value whenever you add additional fields to an API resource and then run the generator.
|
||||
// This is to ensure that this test checked every field in our whole API surface area.
|
||||
totalExpectedAPIFields := 323
|
||||
|
||||
// Because we are parsing text from `kubectl explain` and because the format of that text can change
|
||||
// over time, make a rudimentary assertion that this test exercised the whole tree of all fields of all
|
||||
|
||||
@@ -555,6 +555,7 @@ func TestSupervisorFederationDomainStatus_Disruptive(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo // we have a lot of "if" conditions here, but it's okay
|
||||
func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
env := testlib.IntegrationEnv(t)
|
||||
fdClient := testlib.NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(env.SupervisorNamespace)
|
||||
@@ -566,7 +567,10 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
|
||||
// Certain non-CEL validation failures will prevent CEL validations from running,
|
||||
// and the Kubernetes API server will return this error message for those cases.
|
||||
const couldNotRunCELValidationsErrMessage = `<nil>: Invalid value: "null": some validation rules were not checked because the object was invalid; correct the existing errors to complete validation`
|
||||
const couldNotRunCELValidationsErrMessage = "some validation rules were not checked because the object was invalid; correct the existing errors to complete validation"
|
||||
const oldCouldNotRunCELValidationsErrMessage = `<nil>: Invalid value: "null": ` + couldNotRunCELValidationsErrMessage
|
||||
// Starting in beta version of Kube 1.34, they removed the quotes around the null in this message.
|
||||
const newCouldNotRunCELValidationsErrMessage = `<nil>: Invalid value: null: ` + couldNotRunCELValidationsErrMessage
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -576,11 +580,14 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
// optionally override wantErr for one or more specific versions of Kube, due to changing validation error text
|
||||
wantKube23OrOlderErrs []string
|
||||
wantKube24Through31InclusiveErrs []string
|
||||
wantKube32OrNewerErrs []string
|
||||
wantKube32Through33InclusiveErrs []string
|
||||
wantKube34OrNewerErrs []string
|
||||
|
||||
// These errors are appended to any other wanted errors when k8sAPIServerSupportsCEL is true
|
||||
wantCELErrorsForKube25Through28Inclusive []string
|
||||
wantCELErrorsForKube29Through33Inclusive []string
|
||||
wantCELErrorsForKube29OrNewer []string
|
||||
wantCELErrorsForKube34OrNewer []string
|
||||
}{
|
||||
{
|
||||
name: "issuer cannot be empty",
|
||||
@@ -644,6 +651,7 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
// For some unknown reason, Kubernetes versions 1.23 and older return errors *with indices* for this test case only.
|
||||
wantKube23OrOlderErrs: []string{`spec.identityProviders[0].transforms.constants[1]: Duplicate value: map[string]interface {}{"name":"notUnique"}`},
|
||||
wantErrs: []string{`spec.identityProviders[0].transforms.constants[1]: Duplicate value: map[string]interface {}{"name":"notUnique"}`},
|
||||
wantKube34OrNewerErrs: []string{`spec.identityProviders[0].transforms.constants[1]: Duplicate value: {"name":"notUnique"}`},
|
||||
},
|
||||
{
|
||||
name: "IDP transform constant names cannot be empty",
|
||||
@@ -685,9 +693,10 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
},
|
||||
wantKube23OrOlderErrs: []string{`spec.identityProviders.transforms.constants.name: Invalid value: "12345678901234567890123456789012345678901234567890123456789012345": spec.identityProviders.transforms.constants.name in body should be at most 64 chars long`},
|
||||
wantKube24Through31InclusiveErrs: []string{`spec.identityProviders[0].transforms.constants[0].name: Too long: may not be longer than 64`},
|
||||
wantKube32OrNewerErrs: []string{`spec.identityProviders[0].transforms.constants[0].name: Too long: may not be more than 64 bytes`},
|
||||
wantCELErrorsForKube25Through28Inclusive: []string{couldNotRunCELValidationsErrMessage},
|
||||
wantCELErrorsForKube29OrNewer: []string{couldNotRunCELValidationsErrMessage},
|
||||
wantErrs: []string{`spec.identityProviders[0].transforms.constants[0].name: Too long: may not be more than 64 bytes`},
|
||||
wantCELErrorsForKube25Through28Inclusive: []string{oldCouldNotRunCELValidationsErrMessage},
|
||||
wantCELErrorsForKube29Through33Inclusive: []string{oldCouldNotRunCELValidationsErrMessage},
|
||||
wantCELErrorsForKube34OrNewer: []string{newCouldNotRunCELValidationsErrMessage},
|
||||
},
|
||||
{
|
||||
name: "IDP transform constant names must be a legal CEL variable name",
|
||||
@@ -737,8 +746,9 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrs: []string{`spec.identityProviders[0].transforms.constants[0].type: Unsupported value: "this is invalid": supported values: "string", "stringList"`},
|
||||
wantCELErrorsForKube29OrNewer: []string{couldNotRunCELValidationsErrMessage}, // this should not be checked on kind 1.25, 1.26, 1.27, 1.28
|
||||
wantErrs: []string{`spec.identityProviders[0].transforms.constants[0].type: Unsupported value: "this is invalid": supported values: "string", "stringList"`},
|
||||
wantCELErrorsForKube29Through33Inclusive: []string{oldCouldNotRunCELValidationsErrMessage},
|
||||
wantCELErrorsForKube34OrNewer: []string{newCouldNotRunCELValidationsErrMessage},
|
||||
},
|
||||
{
|
||||
name: "IDP transform expression types must be one of the allowed enum strings",
|
||||
@@ -761,8 +771,9 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErrs: []string{`spec.identityProviders[0].transforms.expressions[0].type: Unsupported value: "this is invalid": supported values: "policy/v1", "username/v1", "groups/v1"`},
|
||||
wantCELErrorsForKube29OrNewer: []string{couldNotRunCELValidationsErrMessage}, // this should not be checked on kind 1.25, 1.26, 1.27, 1.28
|
||||
wantErrs: []string{`spec.identityProviders[0].transforms.expressions[0].type: Unsupported value: "this is invalid": supported values: "policy/v1", "username/v1", "groups/v1"`},
|
||||
wantCELErrorsForKube29Through33Inclusive: []string{oldCouldNotRunCELValidationsErrMessage},
|
||||
wantCELErrorsForKube34OrNewer: []string{newCouldNotRunCELValidationsErrMessage},
|
||||
},
|
||||
{
|
||||
name: "IDP transform expressions cannot be empty",
|
||||
@@ -872,7 +883,7 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
if len(tt.wantErrs) > 0 && len(tt.wantKube23OrOlderErrs) > 0 && len(tt.wantKube24Through31InclusiveErrs) > 0 && len(tt.wantKube32OrNewerErrs) > 0 {
|
||||
if len(tt.wantErrs) > 0 && len(tt.wantKube23OrOlderErrs) > 0 && len(tt.wantKube24Through31InclusiveErrs) > 0 && len(tt.wantKube32Through33InclusiveErrs) > 0 && len(tt.wantKube34OrNewerErrs) > 0 {
|
||||
require.Fail(t, "test setup problem: wanted every possible kind of error, which would cause tt.wantErr to be unused")
|
||||
}
|
||||
|
||||
@@ -900,16 +911,27 @@ func TestSupervisorFederationDomainCRDValidations_Parallel(t *testing.T) {
|
||||
// Also allow overriding with an exact expected error for these Kube versions.
|
||||
wantErr = tt.wantKube24Through31InclusiveErrs
|
||||
}
|
||||
if minor >= 32 && len(tt.wantKube32OrNewerErrs) > 0 {
|
||||
if minor >= 32 && minor <= 33 && len(tt.wantKube32Through33InclusiveErrs) > 0 {
|
||||
// Also allow overriding with an exact expected error for these Kube versions.
|
||||
wantErr = tt.wantKube32OrNewerErrs
|
||||
wantErr = tt.wantKube32Through33InclusiveErrs
|
||||
}
|
||||
if minor >= 34 && len(tt.wantKube34OrNewerErrs) > 0 {
|
||||
// Also allow overriding with an exact expected error for these Kube versions.
|
||||
wantErr = tt.wantKube34OrNewerErrs
|
||||
}
|
||||
|
||||
if minor >= 25 && minor <= 28 && len(tt.wantCELErrorsForKube25Through28Inclusive) > 0 {
|
||||
wantErr = append(wantErr, tt.wantCELErrorsForKube25Through28Inclusive...)
|
||||
} else if minor >= 29 && len(tt.wantCELErrorsForKube29OrNewer) > 0 {
|
||||
}
|
||||
if minor >= 29 && minor <= 33 && len(tt.wantCELErrorsForKube29Through33Inclusive) > 0 {
|
||||
wantErr = append(wantErr, tt.wantCELErrorsForKube29Through33Inclusive...)
|
||||
}
|
||||
if minor >= 29 && len(tt.wantCELErrorsForKube29OrNewer) > 0 {
|
||||
wantErr = append(wantErr, tt.wantCELErrorsForKube29OrNewer...)
|
||||
}
|
||||
if minor >= 34 && len(tt.wantCELErrorsForKube34OrNewer) > 0 {
|
||||
wantErr = append(wantErr, tt.wantCELErrorsForKube34OrNewer...)
|
||||
}
|
||||
|
||||
// Did not want any error.
|
||||
if len(wantErr) == 0 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package testlib
|
||||
@@ -6,7 +6,6 @@ package testlib
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -253,32 +252,6 @@ func WaitForWebhookAuthenticatorStatusConditions(ctx context.Context, t *testing
|
||||
}, 60*time.Second, 1*time.Second, "wanted WebhookAuthenticator conditions")
|
||||
}
|
||||
|
||||
// CreateTestJWTAuthenticatorForCLIUpstream creates and returns a test JWTAuthenticator which will be automatically
|
||||
// deleted at the end of the current test's lifetime.
|
||||
//
|
||||
// CreateTestJWTAuthenticatorForCLIUpstream gets the OIDC issuer info from IntegrationEnv().CLIUpstreamOIDC.
|
||||
func CreateTestJWTAuthenticatorForCLIUpstream(ctx context.Context, t *testing.T) *authenticationv1alpha1.JWTAuthenticator {
|
||||
t.Helper()
|
||||
testEnv := IntegrationEnv(t)
|
||||
spec := authenticationv1alpha1.JWTAuthenticatorSpec{
|
||||
Issuer: testEnv.CLIUpstreamOIDC.Issuer,
|
||||
Audience: testEnv.CLIUpstreamOIDC.ClientID,
|
||||
// The default UsernameClaim is "username" but the upstreams that we use for
|
||||
// integration tests won't necessarily have that claim, so use "sub" here.
|
||||
Claims: authenticationv1alpha1.JWTTokenClaims{Username: "sub"},
|
||||
}
|
||||
// If the test upstream does not have a CA bundle specified, then don't configure one in the
|
||||
// JWTAuthenticator. Leaving TLSSpec set to nil will result in OIDC discovery using the OS's root
|
||||
// CA store.
|
||||
if testEnv.CLIUpstreamOIDC.CABundle != "" {
|
||||
spec.TLS = &authenticationv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(testEnv.CLIUpstreamOIDC.CABundle)),
|
||||
}
|
||||
}
|
||||
authenticator := CreateTestJWTAuthenticator(ctx, t, spec, authenticationv1alpha1.JWTAuthenticatorPhaseReady)
|
||||
return authenticator
|
||||
}
|
||||
|
||||
// CreateTestJWTAuthenticator creates and returns a test JWTAuthenticator which will be automatically deleted
|
||||
// at the end of the current test's lifetime.
|
||||
func CreateTestJWTAuthenticator(
|
||||
|
||||
@@ -304,12 +304,15 @@ func loadEnvVars(t *testing.T, result *TestEnv) {
|
||||
result.ShellContainerImage = needEnv(t, "PINNIPED_TEST_SHELL_CONTAINER_IMAGE")
|
||||
|
||||
result.CLIUpstreamOIDC = TestOIDCUpstream{
|
||||
Issuer: needEnv(t, "PINNIPED_TEST_CLI_OIDC_ISSUER"),
|
||||
CABundle: base64Decoded(t, os.Getenv("PINNIPED_TEST_CLI_OIDC_ISSUER_CA_BUNDLE")),
|
||||
ClientID: needEnv(t, "PINNIPED_TEST_CLI_OIDC_CLIENT_ID"),
|
||||
CallbackURL: needEnv(t, "PINNIPED_TEST_CLI_OIDC_CALLBACK_URL"),
|
||||
Username: needEnv(t, "PINNIPED_TEST_CLI_OIDC_USERNAME"),
|
||||
Password: needEnv(t, "PINNIPED_TEST_CLI_OIDC_PASSWORD"),
|
||||
Issuer: needEnv(t, "PINNIPED_TEST_CLI_OIDC_ISSUER"),
|
||||
CABundle: base64Decoded(t, os.Getenv("PINNIPED_TEST_CLI_OIDC_ISSUER_CA_BUNDLE")),
|
||||
UsernameClaim: os.Getenv("PINNIPED_TEST_CLI_OIDC_USERNAME_CLAIM"),
|
||||
GroupsClaim: os.Getenv("PINNIPED_TEST_CLI_OIDC_GROUPS_CLAIM"),
|
||||
ClientID: needEnv(t, "PINNIPED_TEST_CLI_OIDC_CLIENT_ID"),
|
||||
CallbackURL: needEnv(t, "PINNIPED_TEST_CLI_OIDC_CALLBACK_URL"),
|
||||
Username: needEnv(t, "PINNIPED_TEST_CLI_OIDC_USERNAME"),
|
||||
Password: needEnv(t, "PINNIPED_TEST_CLI_OIDC_PASSWORD"),
|
||||
ExpectedGroups: filterEmpty(strings.Split(strings.ReplaceAll(os.Getenv("PINNIPED_TEST_CLI_OIDC_EXPECTED_GROUPS"), " ", ""), ",")),
|
||||
}
|
||||
|
||||
result.SupervisorUpstreamOIDC = TestOIDCUpstream{
|
||||
|
||||
Reference in New Issue
Block a user