diff --git a/config/v1/tests/authentications.config.openshift.io/ExternalOIDCAuthConfig.yaml b/config/v1/tests/authentications.config.openshift.io/ExternalOIDCAuthConfig.yaml
new file mode 100644
index 00000000000..65af2e3bc65
--- /dev/null
+++ b/config/v1/tests/authentications.config.openshift.io/ExternalOIDCAuthConfig.yaml
@@ -0,0 +1,330 @@
+apiVersion: apiextensions.k8s.io/v1 # Hack because controller-gen complains if we don't have this
+name: "Authentication"
+crdName: authentications.config.openshift.io
+featureGates:
+- ExternalOIDCWithNewAuthConfigFields
+tests:
+ onCreate:
+ # DiscoveryURL Tests
+ - name: Valid discoveryURL
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: https://auth.example.com/.well-known/openid-configuration
+
+ - name: discoveryURL must be a valid URL
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: not-a-valid-url
+ error: "discoveryURL must be a valid URL"
+
+ - name: discoveryURL must not contain user info
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: https://user:pass@auth.example.com/
+ error: "discoveryURL must not contain user info"
+
+ - name: discoveryURL exceeds max length
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: "https://auth.example.com/$(printf 'a%.0s' {1..2050})"
+ error: "discoveryURL: Too long"
+
+ - name: discoveryURL must not contain fragment
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: https://auth.example.com/#fragment
+ error: "discoveryURL must not contain a fragment"
+
+ - name: discoveryURL must use https
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: http://auth.example.com/invalid
+ error: "discoveryURL must use https scheme"
+
+ - name: discoveryURL must not contain query
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: https://auth.example.com/path?foo=bar
+ error: "discoveryURL must not contain query parameters"
+
+ - name: discoveryURL must be different from URL
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com/
+ audiences: ['openshift-aud']
+ discoveryURL: https://auth.example.com/
+ error: "discoveryURL must be different from URL"
+
+ # AudienceMatchPolicy Tests
+
+ - name: Valid AudienceMatchPolicy
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com
+ audiences: ['openshift-aud']
+ audienceMatchPolicy: MatchAny
+
+ - name: Invalid AudienceMatchPolicy
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: TokenIssuer
+ spec:
+ issuerURL: https://auth.example.com
+ audiences: ['openshift-aud']
+ audienceMatchPolicy: InvalidPolicy
+ error: "audienceMatchPolicy: Unsupported value"
+
+ # TokenClaimValidationRule Tests
+ - name: Valid RequiredClaim rule
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://auth.example.com
+ audiences: ['openshift-aud']
+ claimValidationRules:
+ - type: RequiredClaim
+ requiredClaim:
+ claim: "role"
+ requiredValue: "admin"
+
+ - name: Missing requiredClaim when type is RequiredClaim
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://auth.example.com
+ audiences: ['openshift-aud']
+ claimValidationRules:
+ - type: RequiredClaim
+ expectedError: "requiredClaim must be set when type is 'RequiredClaim'"
+
+ - name: Valid ExpressionRule configuration
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ claimValidationRules:
+ - type: Expression
+ expressionRule:
+ expression: "claims.email.endsWith('@example.com')"
+ message: "email must be from example.com"
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ claimValidationRules:
+ - type: Expression
+ expressionRule:
+ expression: "claims.email.endsWith('@example.com')"
+ message: "email must be from example.com"
+
+ - name: Missing expressionRule for Expression type
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ claimValidationRules:
+ - type: Expression
+ expectedError: "expressionRule must be set when type is 'Expression', and forbidden otherwise"
+
+ - name: Expression too long
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ claimValidationRules:
+ - type: Expression
+ expressionRule:
+ expression: "{{longExpression}}"
+ replacements:
+ longExpression: "{{'x' * 5000}}"
+ expectedError: "expression: Too long: must have at most 4096 characters"
+
+ - name: Empty expression in expressionRule
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ claimValidationRules:
+ - type: Expression
+ expressionRule:
+ expression: ""
+ message: "must not be empty"
+ expectedError: "expression: Invalid value: \"\": validation failed: value length must be at least 1"
+
+ # TokenUserValidationRule Tests
+
+ - name: Valid TokenUserValidationRule with expression and message
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ userValidationRules:
+ - expression: "user.username.startsWith('admin')"
+ message: "Only admin users are allowed"
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ userValidationRules:
+ - expression: "user.username.startsWith('admin')"
+ message: "Only admin users are allowed"
+
+ - name: Missing expression in TokenUserValidationRule
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ userValidationRules:
+ - message: "Should never reach here"
+ expectedError: "expression: Required value"
+
+ - name: Expression too long in TokenUserValidationRule
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ userValidationRules:
+ - expression: "{{longExpression}}"
+ message: "This expression is too long"
+ replacements:
+ longExpression: "{{'x' * 5000}}"
+ expectedError: "expression: Too long: must have at most 4096 characters"
+
+ - name: Empty expression in TokenUserValidationRule
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ userValidationRules:
+ - expression: ""
+ message: "Empty expressions are invalid"
+ expectedError: "expression: Invalid value: \"\": validation failed: value length must be at least 1"
+
+ - name: Valid TokenUserValidationRule with expression only
+ initial: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ userValidationRules:
+ - expression: "user.groups.exists(g, g == 'admins')"
+ expected: |
+ apiVersion: config.openshift.io/v1
+ kind: Authentication
+ spec:
+ type: OIDC
+ oidcProviders:
+ - name: myoidc
+ issuer:
+ issuerURL: https://meh.tld
+ audiences: ['openshift-aud']
+ userValidationRules:
+ - expression: "user.groups.exists(g, g == 'admins')"
+
diff --git a/config/v1/types_authentication.go b/config/v1/types_authentication.go
index 651d8a2101c..33a4e15ae18 100644
--- a/config/v1/types_authentication.go
+++ b/config/v1/types_authentication.go
@@ -5,7 +5,7 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
-// +openshift:validation:FeatureGateAwareXValidation:featureGate=ExternalOIDC;ExternalOIDCWithUIDAndExtraClaimMappings,rule="!has(self.spec.oidcProviders) || self.spec.oidcProviders.all(p, !has(p.oidcClients) || p.oidcClients.all(specC, self.status.oidcClients.exists(statusC, statusC.componentNamespace == specC.componentNamespace && statusC.componentName == specC.componentName) || (has(oldSelf.spec.oidcProviders) && oldSelf.spec.oidcProviders.exists(oldP, oldP.name == p.name && has(oldP.oidcClients) && oldP.oidcClients.exists(oldC, oldC.componentNamespace == specC.componentNamespace && oldC.componentName == specC.componentName)))))",message="all oidcClients in the oidcProviders must match their componentName and componentNamespace to either a previously configured oidcClient or they must exist in the status.oidcClients"
+// +openshift:validation:FeatureGateAwareXValidation:featureGate=ExternalOIDC;ExternalOIDCWithUIDAndExtraClaimMappings;ExternalOIDCWithNewAuthConfigFields,rule="!has(self.spec.oidcProviders) || self.spec.oidcProviders.all(p, !has(p.oidcClients) || p.oidcClients.all(specC, self.status.oidcClients.exists(statusC, statusC.componentNamespace == specC.componentNamespace && statusC.componentName == specC.componentName) || (has(oldSelf.spec.oidcProviders) && oldSelf.spec.oidcProviders.exists(oldP, oldP.name == p.name && has(oldP.oidcClients) && oldP.oidcClients.exists(oldC, oldC.componentNamespace == specC.componentNamespace && oldC.componentName == specC.componentName)))))",message="all oidcClients in the oidcProviders must match their componentName and componentNamespace to either a previously configured oidcClient or they must exist in the status.oidcClients"
// Authentication specifies cluster-wide settings for authentication (like OAuth and
// webhook token authenticators). The canonical name of an instance is `cluster`.
@@ -91,6 +91,7 @@ type AuthenticationSpec struct {
// +kubebuilder:validation:MaxItems=1
// +openshift:enable:FeatureGate=ExternalOIDC
// +openshift:enable:FeatureGate=ExternalOIDCWithUIDAndExtraClaimMappings
+ // +openshift:enable:FeatureGate=ExternalOIDCWithNewAuthConfigFields
OIDCProviders []OIDCProvider `json:"oidcProviders,omitempty"`
}
@@ -222,11 +223,22 @@ type OIDCProvider struct {
//
// +listType=atomic
ClaimValidationRules []TokenClaimValidationRule `json:"claimValidationRules,omitempty"`
+
+ // UserValidationRules defines the set of rules used to validate claims in a user’s token.
+ // These rules determine whether a token subject is considered valid based on its claims.
+ // Each rule is evaluated independently.
+ // See the TokenUserValidationRule type for more information on rule structure.
+ // +optional
+
+ //+listType=atomic
+ // +openshift:enable:FeatureGate=ExternalOIDCWithNewAuthConfigFields
+ UserValidationRules []TokenUserValidationRule `json:"userValidationRules,omitempty"`
}
// +kubebuilder:validation:MinLength=1
type TokenAudience string
+// +openshift:validation:FeatureGateAwareXValidation:featureGate=ExternalOIDCWithNewAuthConfigFields,rule="self.discoveryURL.size() > 0 ? (self.issuerURL.size() == 0 || self.discoveryURL.find('^.+[^/]') != self.issuerURL.find('^.+[^/]')) : true",message="discoveryURL must be different from issuerURL"
type TokenIssuer struct {
// URL is the serving URL of the token issuer.
// Must use the https:// scheme.
@@ -251,8 +263,47 @@ type TokenIssuer struct {
// the "ca-bundle.crt" key.
// If unset, system trust is used instead.
CertificateAuthority ConfigMapNameReference `json:"issuerCertificateAuthority"`
+
+ // discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ // used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ // as "{url}/.well-known/openid-configuration".
+ //
+ // The discoveryURL must:
+ // - Be a valid absolute URL.
+ // - Use the HTTPS scheme.
+ // - Not contain query parameters, user info, or fragments.
+ // - Be different from the value of `url` (ignoring trailing slashes)
+ //
+ // +optional
+ // +kubebuilder:validation:XValidation:rule="self.size() > 0 ? isURL(self) : true",message="discoveryURL must be a valid URL"
+ // +kubebuilder:validation:XValidation:rule="self.size() > 0 ? (isURL(self) && url(self).getScheme() == 'https') : true",message="discoveryURL must be a valid https URL"
+ // +kubebuilder:validation:XValidation:rule="self.size() > 0 ? url(self).query == '' : true",message="discoveryURL must not contain query parameters"
+ // +kubebuilder:validation:XValidation:rule="self.size() > 0 ? url(self).user == '' : true",message="discoveryURL must not contain user info"
+ // +kubebuilder:validation:XValidation:rule="self.size() > 0 ? url(self).fragment == '' : true",message="discoveryURL must not contain a fragment"
+ // +kubebuilder:validation:MaxLength=2048
+ // +openshift:enable:FeatureGate=ExternalOIDCWithNewAuthConfigFields
+ DiscoveryURL string `json:"discoveryURL,omitempty"`
+
+ // audienceMatchPolicy specifies how token audiences are matched.
+ // If omitted, the system applies a default policy.
+ // Valid values are:
+ // - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ //
+ // +optional
+ // +openshift:enable:FeatureGate=ExternalOIDCWithNewAuthConfigFields
+ AudienceMatchPolicy AudienceMatchPolicy `json:"audienceMatchPolicy,omitempty"`
}
+// AudienceMatchPolicyType is a set of valid values for Issuer.AudienceMatchPolicy.
+//
+// +kubebuilder:validation:Enum=MatchAny;""
+type AudienceMatchPolicy string
+
+// Valid types for AudienceMatchPolicyType
+const (
+ AudienceMatchPolicyMatchAny AudienceMatchPolicy = "MatchAny"
+)
+
type TokenClaimMappings struct {
// username is a name of the claim that should be used to construct
// usernames for the cluster identity.
@@ -565,27 +616,44 @@ type PrefixedClaimMapping struct {
Prefix string `json:"prefix"`
}
+// TokenValidationRuleType defines the type of token validation rule.
+//
+// +kubebuilder:validation:Enum=RequiredClaim;Expression
type TokenValidationRuleType string
const (
- TokenValidationRuleTypeRequiredClaim = "RequiredClaim"
+ TokenValidationRuleRequiredClaim = "RequiredClaim"
+ TokenValidationRuleExpression = "Expression"
)
+// TokenClaimValidationRule represents a validation rule based on token claims.
+// If type is RequiredClaim, requiredClaim must be set.
+// If type is Expression, expressionRule must be set.
+//
+// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'RequiredClaim' ? has(self.requiredClaim) : !has(self.requiredClaim)",message="requiredClaim must be set when type is 'RequiredClaim', and forbidden otherwise"
+// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Expression' ? has(self.expressionRule) : !has(self.expressionRule)",message="expressionRule must be set when type is 'Expression', and forbidden otherwise"
+
type TokenClaimValidationRule struct {
// type sets the type of the validation rule
//
- // +kubebuilder:validation:Enum={"RequiredClaim"}
// +kubebuilder:default="RequiredClaim"
Type TokenValidationRuleType `json:"type"`
- // requiredClaim allows configuring a required claim name and its expected
- // value
+ // requiredClaim allows configuring a required claim name and its expected value.
+ // RequiredClaim is used when type is RequiredClaim.
+ // +optional
RequiredClaim *TokenRequiredClaim `json:"requiredClaim"`
+
+ // expressionRule contains the configuration for the "Expression" type.
+ // Must be set if type == "Expression".
+ //
+ // +optional
+ // +openshift:enable:FeatureGate=ExternalOIDCWithNewAuthConfigFields
+ ExpressionRule *TokenExpressionRule `json:"expressionRule,omitempty"`
}
type TokenRequiredClaim struct {
- // claim is a name of a required claim. Only claims with string values are
- // supported.
+ // claim is a name of a required claim. Only claims with string values are supported.
//
// +kubebuilder:validation:MinLength=1
// +required
@@ -597,3 +665,45 @@ type TokenRequiredClaim struct {
// +required
RequiredValue string `json:"requiredValue"`
}
+
+type TokenExpressionRule struct {
+ // Expression is a CEL expression evaluated against token claims.
+ // The expression must be a non-empty string and no longer than 4096 characters.
+ // This field is required.
+ //
+ // +kubebuilder:validation:MinLength=1
+ // +kubebuilder:validation:MaxLength=4096
+ // +required
+ Expression string `json:"expression"`
+
+ // Message allows configuring the human-readable message that is returned
+ // from the Kubernetes API server when a token fails validation based on
+ // the CEL expression defined in 'expression'. This field is optional.
+ //
+ // +optional
+ // +kubebuilder:validation:MinLength=1
+ // +kubebuilder:validation:MaxLength=256
+ Message string `json:"message,omitempty"`
+}
+
+// TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+// Each rule contains a CEL expression that is evaluated against the token’s claims.
+// If the expression evaluates to false, the token is rejected.
+// See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+// At least one rule must evaluate to true for the token to be considered valid.
+type TokenUserValidationRule struct {
+ // Expression is a CEL expression that must evaluate
+ // to true for the token to be accepted. The expression is evaluated against the token's
+ // user information (e.g., username, groups). This field must be non-empty and may not
+ // exceed 4096 characters.
+ //
+ // +required
+ // +kubebuilder:validation:MinLength=1
+ // +kubebuilder:validation:MaxLength=4096
+ Expression string `json:"expression,omitempty"`
+ // Message is an optional, human-readable message returned by the API server when
+ // this validation rule fails. It can help clarify why a token was rejected.
+ //
+ // +optional
+ Message string `json:"message,omitempty"`
+}
diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml
index db8b07e8dd2..42da6638cf4 100644
--- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml
index ea5c3252280..c2a90d9c9f6 100644
--- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml
@@ -168,13 +168,12 @@ spec:
properties:
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -191,8 +190,18 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml
index 6a4daafeccd..6aca805ccb7 100644
--- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml
index 0fcf1d3f2c4..6d6b226a896 100644
--- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml
index 880ca79d928..0341b036b2e 100644
--- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
index 9ffcd225a62..0a437c01d5d 100644
--- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
index e258aa25da6..86d7bbc7847 100644
--- a/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
+++ b/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/config/v1/zz_generated.deepcopy.go b/config/v1/zz_generated.deepcopy.go
index 38aa2f6f331..fac7da13a12 100644
--- a/config/v1/zz_generated.deepcopy.go
+++ b/config/v1/zz_generated.deepcopy.go
@@ -4355,6 +4355,11 @@ func (in *OIDCProvider) DeepCopyInto(out *OIDCProvider) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
+ if in.UserValidationRules != nil {
+ in, out := &in.UserValidationRules, &out.UserValidationRules
+ *out = make([]TokenUserValidationRule, len(*in))
+ copy(*out, *in)
+ }
return
}
@@ -5790,6 +5795,11 @@ func (in *TokenClaimValidationRule) DeepCopyInto(out *TokenClaimValidationRule)
*out = new(TokenRequiredClaim)
**out = **in
}
+ if in.ExpressionRule != nil {
+ in, out := &in.ExpressionRule, &out.ExpressionRule
+ *out = new(TokenExpressionRule)
+ **out = **in
+ }
return
}
@@ -5824,6 +5834,22 @@ func (in *TokenConfig) DeepCopy() *TokenConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TokenExpressionRule) DeepCopyInto(out *TokenExpressionRule) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenExpressionRule.
+func (in *TokenExpressionRule) DeepCopy() *TokenExpressionRule {
+ if in == nil {
+ return nil
+ }
+ out := new(TokenExpressionRule)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TokenIssuer) DeepCopyInto(out *TokenIssuer) {
*out = *in
@@ -5862,6 +5888,22 @@ func (in *TokenRequiredClaim) DeepCopy() *TokenRequiredClaim {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TokenUserValidationRule) DeepCopyInto(out *TokenUserValidationRule) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenUserValidationRule.
+func (in *TokenUserValidationRule) DeepCopy() *TokenUserValidationRule {
+ if in == nil {
+ return nil
+ }
+ out := new(TokenUserValidationRule)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Update) DeepCopyInto(out *Update) {
*out = *in
diff --git a/config/v1/zz_generated.featuregated-crd-manifests.yaml b/config/v1/zz_generated.featuregated-crd-manifests.yaml
index d8768ad0c31..0de81ae4043 100644
--- a/config/v1/zz_generated.featuregated-crd-manifests.yaml
+++ b/config/v1/zz_generated.featuregated-crd-manifests.yaml
@@ -30,6 +30,7 @@ authentications.config.openshift.io:
Category: ""
FeatureGates:
- ExternalOIDC
+ - ExternalOIDCWithNewAuthConfigFields
- ExternalOIDCWithUIDAndExtraClaimMappings
FilenameOperatorName: config-operator
FilenameOperatorOrdering: "01"
diff --git a/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDC.yaml b/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDC.yaml
index 91de3ce5a85..d263c4d4265 100644
--- a/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDC.yaml
+++ b/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDC.yaml
@@ -169,13 +169,12 @@ spec:
properties:
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -192,8 +191,18 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
diff --git a/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDCWithNewAuthConfigFields.yaml b/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDCWithNewAuthConfigFields.yaml
new file mode 100644
index 00000000000..f9052e7991b
--- /dev/null
+++ b/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDCWithNewAuthConfigFields.yaml
@@ -0,0 +1,532 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ api-approved.openshift.io: https://github.com/openshift/api/pull/470
+ api.openshift.io/filename-cvo-runlevel: "0000_10"
+ api.openshift.io/filename-operator: config-operator
+ api.openshift.io/filename-ordering: "01"
+ feature-gate.release.openshift.io/ExternalOIDCWithNewAuthConfigFields: "true"
+ release.openshift.io/bootstrap-required: "true"
+ name: authentications.config.openshift.io
+spec:
+ group: config.openshift.io
+ names:
+ kind: Authentication
+ listKind: AuthenticationList
+ plural: authentications
+ singular: authentication
+ scope: Cluster
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: |-
+ Authentication specifies cluster-wide settings for authentication (like OAuth and
+ webhook token authenticators). The canonical name of an instance is `cluster`.
+
+ Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
+ properties:
+ apiVersion:
+ description: |-
+ APIVersion defines the versioned schema of this representation of an object.
+ Servers should convert recognized schemas to the latest internal value, and
+ may reject unrecognized values.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+ type: string
+ kind:
+ description: |-
+ Kind is a string value representing the REST resource this object represents.
+ Servers may infer this from the endpoint the client submits requests to.
+ Cannot be updated.
+ In CamelCase.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: spec holds user settable values for configuration
+ properties:
+ oauthMetadata:
+ description: |-
+ oauthMetadata contains the discovery endpoint data for OAuth 2.0
+ Authorization Server Metadata for an external OAuth server.
+ This discovery document can be viewed from its served location:
+ oc get --raw '/.well-known/oauth-authorization-server'
+ For further details, see the IETF Draft:
+ https://tools.ietf.org/html/draft-ietf-oauth-discovery-04#section-2
+ If oauthMetadata.name is non-empty, this value has precedence
+ over any metadata reference stored in status.
+ The key "oauthMetadata" is used to locate the data.
+ If specified and the config map or expected key is not found, no metadata is served.
+ If the specified metadata is not valid, no metadata is served.
+ The namespace for this config map is openshift-config.
+ properties:
+ name:
+ description: name is the metadata.name of the referenced config
+ map
+ type: string
+ required:
+ - name
+ type: object
+ oidcProviders:
+ description: |-
+ oidcProviders are OIDC identity providers that can issue tokens
+ for this cluster
+ Can only be set if "Type" is set to "OIDC".
+
+ At most one provider can be configured.
+ items:
+ properties:
+ claimMappings:
+ description: |-
+ claimMappings describes rules on how to transform information from an
+ ID token into a cluster identity
+ properties:
+ groups:
+ description: |-
+ groups is a name of the claim that should be used to construct
+ groups for the cluster identity.
+ The referenced claim must use array of strings values.
+ properties:
+ claim:
+ description: claim is a JWT token claim to be used in
+ the mapping
+ type: string
+ prefix:
+ description: |-
+ prefix is a string to prefix the value from the token in the result of the
+ claim mapping.
+
+ By default, no prefixing occurs.
+
+ Example: if `prefix` is set to "myoidc:"" and the `claim` in JWT contains
+ an array of strings "a", "b" and "c", the mapping will result in an
+ array of string "myoidc:a", "myoidc:b" and "myoidc:c".
+ type: string
+ required:
+ - claim
+ type: object
+ username:
+ description: |-
+ username is a name of the claim that should be used to construct
+ usernames for the cluster identity.
+
+ Default value: "sub"
+ properties:
+ claim:
+ description: claim is a JWT token claim to be used in
+ the mapping
+ type: string
+ prefix:
+ properties:
+ prefixString:
+ minLength: 1
+ type: string
+ required:
+ - prefixString
+ type: object
+ prefixPolicy:
+ description: |-
+ prefixPolicy specifies how a prefix should apply.
+
+ By default, claims other than `email` will be prefixed with the issuer URL to
+ prevent naming clashes with other plugins.
+
+ Set to "NoPrefix" to disable prefixing.
+
+ Example:
+ (1) `prefix` is set to "myoidc:" and `claim` is set to "username".
+ If the JWT claim `username` contains value `userA`, the resulting
+ mapped value will be "myoidc:userA".
+ (2) `prefix` is set to "myoidc:" and `claim` is set to "email". If the
+ JWT `email` claim contains value "userA@myoidc.tld", the resulting
+ mapped value will be "myoidc:userA@myoidc.tld".
+ (3) `prefix` is unset, `issuerURL` is set to `https://myoidc.tld`,
+ the JWT claims include "username":"userA" and "email":"userA@myoidc.tld",
+ and `claim` is set to:
+ (a) "username": the mapped value will be "https://myoidc.tld#userA"
+ (b) "email": the mapped value will be "userA@myoidc.tld"
+ enum:
+ - ""
+ - NoPrefix
+ - Prefix
+ type: string
+ required:
+ - claim
+ type: object
+ x-kubernetes-validations:
+ - message: prefix must be set if prefixPolicy is 'Prefix',
+ but must remain unset otherwise
+ rule: 'has(self.prefixPolicy) && self.prefixPolicy ==
+ ''Prefix'' ? (has(self.prefix) && size(self.prefix.prefixString)
+ > 0) : !has(self.prefix)'
+ type: object
+ claimValidationRules:
+ description: claimValidationRules are rules that are applied
+ to validate token claims to authenticate users.
+ items:
+ properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
+ requiredClaim:
+ description: |-
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
+ properties:
+ claim:
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
+ minLength: 1
+ type: string
+ requiredValue:
+ description: requiredValue is the required value for
+ the claim.
+ minLength: 1
+ type: string
+ required:
+ - claim
+ - requiredValue
+ type: object
+ type:
+ default: RequiredClaim
+ description: type sets the type of the validation rule
+ enum:
+ - RequiredClaim
+ - Expression
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
+ type: array
+ x-kubernetes-list-type: atomic
+ issuer:
+ description: issuer describes atributes of the OIDC token issuer
+ properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
+ audiences:
+ description: |-
+ audiences is an array of audiences that the token was issued for.
+ Valid tokens must include at least one of these values in their
+ "aud" claim.
+ Must be set to exactly one value.
+ items:
+ minLength: 1
+ type: string
+ maxItems: 10
+ minItems: 1
+ type: array
+ x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
+ issuerCertificateAuthority:
+ description: |-
+ CertificateAuthority is a reference to a config map in the
+ configuration namespace. The .data of the configMap must contain
+ the "ca-bundle.crt" key.
+ If unset, system trust is used instead.
+ properties:
+ name:
+ description: name is the metadata.name of the referenced
+ config map
+ type: string
+ required:
+ - name
+ type: object
+ issuerURL:
+ description: |-
+ URL is the serving URL of the token issuer.
+ Must use the https:// scheme.
+ pattern: ^https:\/\/[^\s]
+ type: string
+ required:
+ - audiences
+ - issuerURL
+ type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
+ name:
+ description: name of the OIDC provider
+ minLength: 1
+ type: string
+ oidcClients:
+ description: |-
+ oidcClients contains configuration for the platform's clients that
+ need to request tokens from the issuer
+ items:
+ properties:
+ clientID:
+ description: clientID is the identifier of the OIDC client
+ from the OIDC provider
+ minLength: 1
+ type: string
+ clientSecret:
+ description: |-
+ clientSecret refers to a secret in the `openshift-config` namespace that
+ contains the client secret in the `clientSecret` key of the `.data` field
+ properties:
+ name:
+ description: name is the metadata.name of the referenced
+ secret
+ type: string
+ required:
+ - name
+ type: object
+ componentName:
+ description: |-
+ componentName is the name of the component that is supposed to consume this
+ client configuration
+ maxLength: 256
+ minLength: 1
+ type: string
+ componentNamespace:
+ description: |-
+ componentNamespace is the namespace of the component that is supposed to consume this
+ client configuration
+ maxLength: 63
+ minLength: 1
+ type: string
+ extraScopes:
+ description: extraScopes is an optional set of scopes
+ to request tokens with.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ required:
+ - clientID
+ - componentName
+ - componentNamespace
+ type: object
+ maxItems: 20
+ type: array
+ x-kubernetes-list-map-keys:
+ - componentNamespace
+ - componentName
+ x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - issuer
+ - name
+ type: object
+ maxItems: 1
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ serviceAccountIssuer:
+ description: |-
+ serviceAccountIssuer is the identifier of the bound service account token
+ issuer.
+ The default is https://kubernetes.default.svc
+ WARNING: Updating this field will not result in immediate invalidation of all bound tokens with the
+ previous issuer value. Instead, the tokens issued by previous service account issuer will continue to
+ be trusted for a time period chosen by the platform (currently set to 24h).
+ This time period is subject to change over time.
+ This allows internal components to transition to use new service account issuer without service distruption.
+ type: string
+ type:
+ description: |-
+ type identifies the cluster managed, user facing authentication mode in use.
+ Specifically, it manages the component that responds to login attempts.
+ The default is IntegratedOAuth.
+ type: string
+ webhookTokenAuthenticator:
+ description: |-
+ webhookTokenAuthenticator configures a remote token reviewer.
+ These remote authentication webhooks can be used to verify bearer tokens
+ via the tokenreviews.authentication.k8s.io REST API. This is required to
+ honor bearer tokens that are provisioned by an external authentication service.
+
+ Can only be set if "Type" is set to "None".
+ properties:
+ kubeConfig:
+ description: |-
+ kubeConfig references a secret that contains kube config file data which
+ describes how to access the remote webhook service.
+ The namespace for the referenced secret is openshift-config.
+
+ For further details, see:
+
+ https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication
+
+ The key "kubeConfig" is used to locate the data.
+ If the secret or expected key is not found, the webhook is not honored.
+ If the specified kube config data is not valid, the webhook is not honored.
+ properties:
+ name:
+ description: name is the metadata.name of the referenced secret
+ type: string
+ required:
+ - name
+ type: object
+ required:
+ - kubeConfig
+ type: object
+ webhookTokenAuthenticators:
+ description: webhookTokenAuthenticators is DEPRECATED, setting it
+ has no effect.
+ items:
+ description: |-
+ deprecatedWebhookTokenAuthenticator holds the necessary configuration options for a remote token authenticator.
+ It's the same as WebhookTokenAuthenticator but it's missing the 'required' validation on KubeConfig field.
+ properties:
+ kubeConfig:
+ description: |-
+ kubeConfig contains kube config file data which describes how to access the remote webhook service.
+ For further details, see:
+ https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication
+ The key "kubeConfig" is used to locate the data.
+ If the secret or expected key is not found, the webhook is not honored.
+ If the specified kube config data is not valid, the webhook is not honored.
+ The namespace for this secret is determined by the point of use.
+ properties:
+ name:
+ description: name is the metadata.name of the referenced
+ secret
+ type: string
+ required:
+ - name
+ type: object
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ status:
+ description: status holds observed values from the cluster. They may not
+ be overridden.
+ properties:
+ integratedOAuthMetadata:
+ description: |-
+ integratedOAuthMetadata contains the discovery endpoint data for OAuth 2.0
+ Authorization Server Metadata for the in-cluster integrated OAuth server.
+ This discovery document can be viewed from its served location:
+ oc get --raw '/.well-known/oauth-authorization-server'
+ For further details, see the IETF Draft:
+ https://tools.ietf.org/html/draft-ietf-oauth-discovery-04#section-2
+ This contains the observed value based on cluster state.
+ An explicitly set value in spec.oauthMetadata has precedence over this field.
+ This field has no meaning if authentication spec.type is not set to IntegratedOAuth.
+ The key "oauthMetadata" is used to locate the data.
+ If the config map or expected key is not found, no metadata is served.
+ If the specified metadata is not valid, no metadata is served.
+ The namespace for this config map is openshift-config-managed.
+ properties:
+ name:
+ description: name is the metadata.name of the referenced config
+ map
+ type: string
+ required:
+ - name
+ type: object
+ type: object
+ required:
+ - spec
+ type: object
+ x-kubernetes-validations:
+ - message: all oidcClients in the oidcProviders must match their componentName
+ and componentNamespace to either a previously configured oidcClient or
+ they must exist in the status.oidcClients
+ rule: '!has(self.spec.oidcProviders) || self.spec.oidcProviders.all(p, !has(p.oidcClients)
+ || p.oidcClients.all(specC, self.status.oidcClients.exists(statusC, statusC.componentNamespace
+ == specC.componentNamespace && statusC.componentName == specC.componentName)
+ || (has(oldSelf.spec.oidcProviders) && oldSelf.spec.oidcProviders.exists(oldP,
+ oldP.name == p.name && has(oldP.oidcClients) && oldP.oidcClients.exists(oldC,
+ oldC.componentNamespace == specC.componentNamespace && oldC.componentName
+ == specC.componentName)))))'
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
index 6bfe1cbc865..38d4415ca18 100644
--- a/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
+++ b/config/v1/zz_generated.featuregated-crd-manifests/authentications.config.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
@@ -320,13 +320,12 @@ spec:
properties:
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -343,8 +342,18 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
diff --git a/config/v1/zz_generated.swagger_doc_generated.go b/config/v1/zz_generated.swagger_doc_generated.go
index 5f99eedd722..46fb4f6bfab 100644
--- a/config/v1/zz_generated.swagger_doc_generated.go
+++ b/config/v1/zz_generated.swagger_doc_generated.go
@@ -490,18 +490,30 @@ func (TokenClaimOrExpressionMapping) SwaggerDoc() map[string]string {
}
var map_TokenClaimValidationRule = map[string]string{
- "type": "type sets the type of the validation rule",
- "requiredClaim": "requiredClaim allows configuring a required claim name and its expected value",
+ "type": "type sets the type of the validation rule",
+ "requiredClaim": "requiredClaim allows configuring a required claim name and its expected value. RequiredClaim is used when type is RequiredClaim.",
+ "expressionRule": "expressionRule contains the configuration for the \"Expression\" type. Must be set if type == \"Expression\".",
}
func (TokenClaimValidationRule) SwaggerDoc() map[string]string {
return map_TokenClaimValidationRule
}
+var map_TokenExpressionRule = map[string]string{
+ "expression": "Expression is a CEL expression evaluated against token claims. The expression must be a non-empty string and no longer than 4096 characters. This field is required.",
+ "message": "Message allows configuring the human-readable message that is returned from the Kubernetes API server when a token fails validation based on the CEL expression defined in 'expression'. This field is optional.",
+}
+
+func (TokenExpressionRule) SwaggerDoc() map[string]string {
+ return map_TokenExpressionRule
+}
+
var map_TokenIssuer = map[string]string{
"issuerURL": "URL is the serving URL of the token issuer. Must use the https:// scheme.",
"audiences": "audiences is an array of audiences that the token was issued for. Valid tokens must include at least one of these values in their \"aud\" claim. Must be set to exactly one value.",
"issuerCertificateAuthority": "CertificateAuthority is a reference to a config map in the configuration namespace. The .data of the configMap must contain the \"ca-bundle.crt\" key. If unset, system trust is used instead.",
+ "discoveryURL": "discoveryURL is an optional field that, if specified, overrides the default discovery endpoint used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url` as \"{url}/.well-known/openid-configuration\".\n\nThe discoveryURL must:\n - Be a valid absolute URL.\n - Use the HTTPS scheme.\n - Not contain query parameters, user info, or fragments.\n - Be different from the value of `url` (ignoring trailing slashes)",
+ "audienceMatchPolicy": "audienceMatchPolicy specifies how token audiences are matched. If omitted, the system applies a default policy. Valid values are: - \"MatchAny\": The token is accepted if any of its audiences match any of the configured audiences.",
}
func (TokenIssuer) SwaggerDoc() map[string]string {
@@ -517,6 +529,16 @@ func (TokenRequiredClaim) SwaggerDoc() map[string]string {
return map_TokenRequiredClaim
}
+var map_TokenUserValidationRule = map[string]string{
+ "": "TokenUserValidationRule provides a CEL-based rule used to validate a token subject. Each rule contains a CEL expression that is evaluated against the token’s claims. If the expression evaluates to false, the token is rejected. See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax. At least one rule must evaluate to true for the token to be considered valid.",
+ "expression": "Expression is a CEL expression that must evaluate to true for the token to be accepted. The expression is evaluated against the token's user information (e.g., username, groups). This field must be non-empty and may not exceed 4096 characters.",
+ "message": "Message is an optional, human-readable message returned by the API server when this validation rule fails. It can help clarify why a token was rejected.",
+}
+
+func (TokenUserValidationRule) SwaggerDoc() map[string]string {
+ return map_TokenUserValidationRule
+}
+
var map_UsernameClaimMapping = map[string]string{
"prefixPolicy": "prefixPolicy specifies how a prefix should apply.\n\nBy default, claims other than `email` will be prefixed with the issuer URL to prevent naming clashes with other plugins.\n\nSet to \"NoPrefix\" to disable prefixing.\n\nExample:\n (1) `prefix` is set to \"myoidc:\" and `claim` is set to \"username\".\n If the JWT claim `username` contains value `userA`, the resulting\n mapped value will be \"myoidc:userA\".\n (2) `prefix` is set to \"myoidc:\" and `claim` is set to \"email\". If the\n JWT `email` claim contains value \"userA@myoidc.tld\", the resulting\n mapped value will be \"myoidc:userA@myoidc.tld\".\n (3) `prefix` is unset, `issuerURL` is set to `https://myoidc.tld`,\n the JWT claims include \"username\":\"userA\" and \"email\":\"userA@myoidc.tld\",\n and `claim` is set to:\n (a) \"username\": the mapped value will be \"https://myoidc.tld#userA\"\n (b) \"email\": the mapped value will be \"userA@myoidc.tld\"",
}
diff --git a/features.md b/features.md
index 049482cad9c..955cc84d773 100644
--- a/features.md
+++ b/features.md
@@ -25,6 +25,7 @@
| DynamicResourceAllocation| | | Enabled | Enabled | Enabled | Enabled |
| EtcdBackendQuota| | | Enabled | Enabled | Enabled | Enabled |
| Example| | | Enabled | Enabled | Enabled | Enabled |
+| ExternalOIDCWithNewAuthConfigFields| | | Enabled | Enabled | Enabled | Enabled |
| ExternalOIDCWithUIDAndExtraClaimMappings| | | Enabled | Enabled | Enabled | Enabled |
| GCPClusterHostedDNS| | | Enabled | Enabled | Enabled | Enabled |
| GCPCustomAPIEndpoints| | | Enabled | Enabled | Enabled | Enabled |
diff --git a/features/features.go b/features/features.go
index c2b9d1aee28..e1e65eb4836 100644
--- a/features/features.go
+++ b/features/features.go
@@ -483,13 +483,22 @@ var (
mustRegister()
FeatureGateExternalOIDCWithAdditionalClaimMappings = newFeatureGate("ExternalOIDCWithUIDAndExtraClaimMappings").
- reportProblemsToJiraComponent("authentication").
- contactPerson("bpalmer").
- productScope(ocpSpecific).
- enhancementPR("https://github.com/openshift/enhancements/pull/1777").
- enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
- enableForClusterProfile(Hypershift, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
- mustRegister()
+ reportProblemsToJiraComponent("authentication").
+ contactPerson("bpalmer").
+ productScope(ocpSpecific).
+ enhancementPR("https://github.com/openshift/enhancements/pull/1777").
+ enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
+ enableForClusterProfile(Hypershift, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
+ mustRegister()
+
+ FeatureGateExternalOIDCWithNewAuthConfigFields = newFeatureGate("ExternalOIDCWithNewAuthConfigFields").
+ reportProblemsToJiraComponent("authentication").
+ contactPerson("saldawam").
+ productScope(ocpSpecific).
+ enhancementPR("https://github.com/openshift/enhancements/pull/1763").
+ enableIn(configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
+ enableForClusterProfile(Hypershift, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
+ mustRegister()
FeatureGateExample = newFeatureGate("Example").
reportProblemsToJiraComponent("cluster-config").
@@ -540,12 +549,12 @@ var (
mustRegister()
FeatureGateNewOLMOwnSingleNamespace = newFeatureGate("NewOLMOwnSingleNamespace").
- reportProblemsToJiraComponent("olm").
- contactPerson("nschieder").
- productScope(ocpSpecific).
- enhancementPR("https://github.com/openshift/enhancements/pull/1774").
- enableForClusterProfile(SelfManaged, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
- mustRegister()
+ reportProblemsToJiraComponent("olm").
+ contactPerson("nschieder").
+ productScope(ocpSpecific).
+ enhancementPR("https://github.com/openshift/enhancements/pull/1774").
+ enableForClusterProfile(SelfManaged, configv1.DevPreviewNoUpgrade, configv1.TechPreviewNoUpgrade).
+ mustRegister()
FeatureGateInsightsOnDemandDataGather = newFeatureGate("InsightsOnDemandDataGather").
reportProblemsToJiraComponent("insights").
diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go
index c7e2a20809b..6c4e012605e 100644
--- a/openapi/generated_openapi/zz_generated.openapi.go
+++ b/openapi/generated_openapi/zz_generated.openapi.go
@@ -386,8 +386,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"github.com/openshift/api/config/v1.TokenClaimOrExpressionMapping": schema_openshift_api_config_v1_TokenClaimOrExpressionMapping(ref),
"github.com/openshift/api/config/v1.TokenClaimValidationRule": schema_openshift_api_config_v1_TokenClaimValidationRule(ref),
"github.com/openshift/api/config/v1.TokenConfig": schema_openshift_api_config_v1_TokenConfig(ref),
+ "github.com/openshift/api/config/v1.TokenExpressionRule": schema_openshift_api_config_v1_TokenExpressionRule(ref),
"github.com/openshift/api/config/v1.TokenIssuer": schema_openshift_api_config_v1_TokenIssuer(ref),
"github.com/openshift/api/config/v1.TokenRequiredClaim": schema_openshift_api_config_v1_TokenRequiredClaim(ref),
+ "github.com/openshift/api/config/v1.TokenUserValidationRule": schema_openshift_api_config_v1_TokenUserValidationRule(ref),
"github.com/openshift/api/config/v1.Update": schema_openshift_api_config_v1_Update(ref),
"github.com/openshift/api/config/v1.UpdateHistory": schema_openshift_api_config_v1_UpdateHistory(ref),
"github.com/openshift/api/config/v1.UsernameClaimMapping": schema_openshift_api_config_v1_UsernameClaimMapping(ref),
@@ -16724,12 +16726,30 @@ func schema_openshift_api_config_v1_OIDCProvider(ref common.ReferenceCallback) c
},
},
},
+ "userValidationRules": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "atomic",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: map[string]interface{}{},
+ Ref: ref("github.com/openshift/api/config/v1.TokenUserValidationRule"),
+ },
+ },
+ },
+ },
+ },
},
Required: []string{"name", "issuer", "oidcClients", "claimMappings"},
},
},
Dependencies: []string{
- "github.com/openshift/api/config/v1.OIDCClientConfig", "github.com/openshift/api/config/v1.TokenClaimMappings", "github.com/openshift/api/config/v1.TokenClaimValidationRule", "github.com/openshift/api/config/v1.TokenIssuer"},
+ "github.com/openshift/api/config/v1.OIDCClientConfig", "github.com/openshift/api/config/v1.TokenClaimMappings", "github.com/openshift/api/config/v1.TokenClaimValidationRule", "github.com/openshift/api/config/v1.TokenIssuer", "github.com/openshift/api/config/v1.TokenUserValidationRule"},
}
}
@@ -19470,16 +19490,22 @@ func schema_openshift_api_config_v1_TokenClaimValidationRule(ref common.Referenc
},
"requiredClaim": {
SchemaProps: spec.SchemaProps{
- Description: "requiredClaim allows configuring a required claim name and its expected value",
+ Description: "requiredClaim allows configuring a required claim name and its expected value. RequiredClaim is used when type is RequiredClaim.",
Ref: ref("github.com/openshift/api/config/v1.TokenRequiredClaim"),
},
},
+ "expressionRule": {
+ SchemaProps: spec.SchemaProps{
+ Description: "expressionRule contains the configuration for the \"Expression\" type. Must be set if type == \"Expression\".",
+ Ref: ref("github.com/openshift/api/config/v1.TokenExpressionRule"),
+ },
+ },
},
- Required: []string{"type", "requiredClaim"},
+ Required: []string{"type"},
},
},
Dependencies: []string{
- "github.com/openshift/api/config/v1.TokenRequiredClaim"},
+ "github.com/openshift/api/config/v1.TokenExpressionRule", "github.com/openshift/api/config/v1.TokenRequiredClaim"},
}
}
@@ -19518,6 +19544,34 @@ func schema_openshift_api_config_v1_TokenConfig(ref common.ReferenceCallback) co
}
}
+func schema_openshift_api_config_v1_TokenExpressionRule(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Type: []string{"object"},
+ Properties: map[string]spec.Schema{
+ "expression": {
+ SchemaProps: spec.SchemaProps{
+ Description: "Expression is a CEL expression evaluated against token claims. The expression must be a non-empty string and no longer than 4096 characters. This field is required.",
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "message": {
+ SchemaProps: spec.SchemaProps{
+ Description: "Message allows configuring the human-readable message that is returned from the Kubernetes API server when a token fails validation based on the CEL expression defined in 'expression'. This field is optional.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ Required: []string{"expression"},
+ },
+ },
+ }
+}
+
func schema_openshift_api_config_v1_TokenIssuer(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
@@ -19559,6 +19613,20 @@ func schema_openshift_api_config_v1_TokenIssuer(ref common.ReferenceCallback) co
Ref: ref("github.com/openshift/api/config/v1.ConfigMapNameReference"),
},
},
+ "discoveryURL": {
+ SchemaProps: spec.SchemaProps{
+ Description: "discoveryURL is an optional field that, if specified, overrides the default discovery endpoint used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url` as \"{url}/.well-known/openid-configuration\".\n\nThe discoveryURL must:\n - Be a valid absolute URL.\n - Use the HTTPS scheme.\n - Not contain query parameters, user info, or fragments.\n - Be different from the value of `url` (ignoring trailing slashes)",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "audienceMatchPolicy": {
+ SchemaProps: spec.SchemaProps{
+ Description: "audienceMatchPolicy specifies how token audiences are matched. If omitted, the system applies a default policy. Valid values are: - \"MatchAny\": The token is accepted if any of its audiences match any of the configured audiences.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
},
Required: []string{"issuerURL", "audiences", "issuerCertificateAuthority"},
},
@@ -19597,6 +19665,34 @@ func schema_openshift_api_config_v1_TokenRequiredClaim(ref common.ReferenceCallb
}
}
+func schema_openshift_api_config_v1_TokenUserValidationRule(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "TokenUserValidationRule provides a CEL-based rule used to validate a token subject. Each rule contains a CEL expression that is evaluated against the token’s claims. If the expression evaluates to false, the token is rejected. See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax. At least one rule must evaluate to true for the token to be considered valid.",
+ Type: []string{"object"},
+ Properties: map[string]spec.Schema{
+ "expression": {
+ SchemaProps: spec.SchemaProps{
+ Description: "Expression is a CEL expression that must evaluate to true for the token to be accepted. The expression is evaluated against the token's user information (e.g., username, groups). This field must be non-empty and may not exceed 4096 characters.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "message": {
+ SchemaProps: spec.SchemaProps{
+ Description: "Message is an optional, human-readable message returned by the API server when this validation rule fails. It can help clarify why a token was rejected.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ Required: []string{"expression"},
+ },
+ },
+ }
+}
+
func schema_openshift_api_config_v1_Update(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
diff --git a/openapi/openapi.json b/openapi/openapi.json
index 6369a9bc821..2bdecc054d1 100644
--- a/openapi/openapi.json
+++ b/openapi/openapi.json
@@ -8948,6 +8948,14 @@
"componentName"
],
"x-kubernetes-list-type": "map"
+ },
+ "userValidationRules": {
+ "type": "array",
+ "items": {
+ "default": {},
+ "$ref": "#/definitions/com.github.openshift.api.config.v1.TokenUserValidationRule"
+ },
+ "x-kubernetes-list-type": "atomic"
}
}
},
@@ -10536,12 +10544,15 @@
"com.github.openshift.api.config.v1.TokenClaimValidationRule": {
"type": "object",
"required": [
- "type",
- "requiredClaim"
+ "type"
],
"properties": {
+ "expressionRule": {
+ "description": "expressionRule contains the configuration for the \"Expression\" type. Must be set if type == \"Expression\".",
+ "$ref": "#/definitions/com.github.openshift.api.config.v1.TokenExpressionRule"
+ },
"requiredClaim": {
- "description": "requiredClaim allows configuring a required claim name and its expected value",
+ "description": "requiredClaim allows configuring a required claim name and its expected value. RequiredClaim is used when type is RequiredClaim.",
"$ref": "#/definitions/com.github.openshift.api.config.v1.TokenRequiredClaim"
},
"type": {
@@ -10571,6 +10582,23 @@
}
}
},
+ "com.github.openshift.api.config.v1.TokenExpressionRule": {
+ "type": "object",
+ "required": [
+ "expression"
+ ],
+ "properties": {
+ "expression": {
+ "description": "Expression is a CEL expression evaluated against token claims. The expression must be a non-empty string and no longer than 4096 characters. This field is required.",
+ "type": "string",
+ "default": ""
+ },
+ "message": {
+ "description": "Message allows configuring the human-readable message that is returned from the Kubernetes API server when a token fails validation based on the CEL expression defined in 'expression'. This field is optional.",
+ "type": "string"
+ }
+ }
+ },
"com.github.openshift.api.config.v1.TokenIssuer": {
"type": "object",
"required": [
@@ -10579,6 +10607,10 @@
"issuerCertificateAuthority"
],
"properties": {
+ "audienceMatchPolicy": {
+ "description": "audienceMatchPolicy specifies how token audiences are matched. If omitted, the system applies a default policy. Valid values are: - \"MatchAny\": The token is accepted if any of its audiences match any of the configured audiences.",
+ "type": "string"
+ },
"audiences": {
"description": "audiences is an array of audiences that the token was issued for. Valid tokens must include at least one of these values in their \"aud\" claim. Must be set to exactly one value.",
"type": "array",
@@ -10588,6 +10620,10 @@
},
"x-kubernetes-list-type": "set"
},
+ "discoveryURL": {
+ "description": "discoveryURL is an optional field that, if specified, overrides the default discovery endpoint used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url` as \"{url}/.well-known/openid-configuration\".\n\nThe discoveryURL must:\n - Be a valid absolute URL.\n - Use the HTTPS scheme.\n - Not contain query parameters, user info, or fragments.\n - Be different from the value of `url` (ignoring trailing slashes)",
+ "type": "string"
+ },
"issuerCertificateAuthority": {
"description": "CertificateAuthority is a reference to a config map in the configuration namespace. The .data of the configMap must contain the \"ca-bundle.crt\" key. If unset, system trust is used instead.",
"default": {},
@@ -10619,6 +10655,23 @@
}
}
},
+ "com.github.openshift.api.config.v1.TokenUserValidationRule": {
+ "description": "TokenUserValidationRule provides a CEL-based rule used to validate a token subject. Each rule contains a CEL expression that is evaluated against the token’s claims. If the expression evaluates to false, the token is rejected. See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax. At least one rule must evaluate to true for the token to be considered valid.",
+ "type": "object",
+ "required": [
+ "expression"
+ ],
+ "properties": {
+ "expression": {
+ "description": "Expression is a CEL expression that must evaluate to true for the token to be accepted. The expression is evaluated against the token's user information (e.g., username, groups). This field must be non-empty and may not exceed 4096 characters.",
+ "type": "string"
+ },
+ "message": {
+ "description": "Message is an optional, human-readable message returned by the API server when this validation rule fails. It can help clarify why a token was rejected.",
+ "type": "string"
+ }
+ }
+ },
"com.github.openshift.api.config.v1.Update": {
"description": "Update represents an administrator update request.",
"type": "object",
diff --git a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml
index db8b07e8dd2..42da6638cf4 100644
--- a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml
+++ b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-CustomNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml
index ea5c3252280..c2a90d9c9f6 100644
--- a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml
+++ b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-Default.crd.yaml
@@ -168,13 +168,12 @@ spec:
properties:
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -191,8 +190,18 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
diff --git a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml
index 6a4daafeccd..6aca805ccb7 100644
--- a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml
+++ b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-DevPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml
index 0fcf1d3f2c4..6d6b226a896 100644
--- a/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml
+++ b/payload-manifests/crds/0000_10_config-operator_01_authentications-Hypershift-TechPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml
index 880ca79d928..0341b036b2e 100644
--- a/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml
+++ b/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-CustomNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
index 9ffcd225a62..0a437c01d5d 100644
--- a/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
+++ b/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml b/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
index e258aa25da6..86d7bbc7847 100644
--- a/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
+++ b/payload-manifests/crds/0000_10_config-operator_01_authentications-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
@@ -317,15 +317,38 @@ spec:
to validate token claims to authenticate users.
items:
properties:
+ expressionRule:
+ description: |-
+ expressionRule contains the configuration for the "Expression" type.
+ Must be set if type == "Expression".
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression evaluated against token claims.
+ The expression must be a non-empty string and no longer than 4096 characters.
+ This field is required.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message allows configuring the human-readable message that is returned
+ from the Kubernetes API server when a token fails validation based on
+ the CEL expression defined in 'expression'. This field is optional.
+ maxLength: 256
+ minLength: 1
+ type: string
+ required:
+ - expression
+ type: object
requiredClaim:
description: |-
- requiredClaim allows configuring a required claim name and its expected
- value
+ requiredClaim allows configuring a required claim name and its expected value.
+ RequiredClaim is used when type is RequiredClaim.
properties:
claim:
- description: |-
- claim is a name of a required claim. Only claims with string values are
- supported.
+ description: claim is a name of a required claim.
+ Only claims with string values are supported.
minLength: 1
type: string
requiredValue:
@@ -342,13 +365,33 @@ spec:
description: type sets the type of the validation rule
enum:
- RequiredClaim
+ - Expression
type: string
type: object
+ x-kubernetes-validations:
+ - message: requiredClaim must be set when type is 'RequiredClaim',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''RequiredClaim''
+ ? has(self.requiredClaim) : !has(self.requiredClaim)'
+ - message: expressionRule must be set when type is 'Expression',
+ and forbidden otherwise
+ rule: 'has(self.type) && self.type == ''Expression'' ? has(self.expressionRule)
+ : !has(self.expressionRule)'
type: array
x-kubernetes-list-type: atomic
issuer:
description: issuer describes atributes of the OIDC token issuer
properties:
+ audienceMatchPolicy:
+ description: |-
+ audienceMatchPolicy specifies how token audiences are matched.
+ If omitted, the system applies a default policy.
+ Valid values are:
+ - "MatchAny": The token is accepted if any of its audiences match any of the configured audiences.
+ enum:
+ - MatchAny
+ - ""
+ type: string
audiences:
description: |-
audiences is an array of audiences that the token was issued for.
@@ -362,6 +405,32 @@ spec:
minItems: 1
type: array
x-kubernetes-list-type: set
+ discoveryURL:
+ description: |-
+ discoveryURL is an optional field that, if specified, overrides the default discovery endpoint
+ used to retrieve OIDC configuration metadata. By default, the discovery URL is derived from `url`
+ as "{url}/.well-known/openid-configuration".
+
+ The discoveryURL must:
+ - Be a valid absolute URL.
+ - Use the HTTPS scheme.
+ - Not contain query parameters, user info, or fragments.
+ - Be different from the value of `url` (ignoring trailing slashes)
+ maxLength: 2048
+ type: string
+ x-kubernetes-validations:
+ - message: discoveryURL must be a valid URL
+ rule: 'self.size() > 0 ? isURL(self) : true'
+ - message: discoveryURL must be a valid https URL
+ rule: 'self.size() > 0 ? (isURL(self) && url(self).getScheme()
+ == ''https'') : true'
+ - message: discoveryURL must not contain query parameters
+ rule: 'self.size() > 0 ? url(self).query == '''' : true'
+ - message: discoveryURL must not contain user info
+ rule: 'self.size() > 0 ? url(self).user == '''' : true'
+ - message: discoveryURL must not contain a fragment
+ rule: 'self.size() > 0 ? url(self).fragment == '''' :
+ true'
issuerCertificateAuthority:
description: |-
CertificateAuthority is a reference to a config map in the
@@ -386,6 +455,11 @@ spec:
- audiences
- issuerURL
type: object
+ x-kubernetes-validations:
+ - message: discoveryURL must be different from issuerURL
+ rule: 'self.discoveryURL.size() > 0 ? (self.issuerURL.size()
+ == 0 || self.discoveryURL.find(''^.+[^/]'') != self.issuerURL.find(''^.+[^/]''))
+ : true'
name:
description: name of the OIDC provider
minLength: 1
@@ -445,6 +519,34 @@ spec:
- componentNamespace
- componentName
x-kubernetes-list-type: map
+ userValidationRules:
+ items:
+ description: |-
+ TokenUserValidationRule provides a CEL-based rule used to validate a token subject.
+ Each rule contains a CEL expression that is evaluated against the token’s claims.
+ If the expression evaluates to false, the token is rejected.
+ See https://kubernetes.io/docs/reference/using-api/cel/ for CEL syntax.
+ At least one rule must evaluate to true for the token to be considered valid.
+ properties:
+ expression:
+ description: |-
+ Expression is a CEL expression that must evaluate
+ to true for the token to be accepted. The expression is evaluated against the token's
+ user information (e.g., username, groups). This field must be non-empty and may not
+ exceed 4096 characters.
+ maxLength: 4096
+ minLength: 1
+ type: string
+ message:
+ description: |-
+ Message is an optional, human-readable message returned by the API server when
+ this validation rule fails. It can help clarify why a token was rejected.
+ type: string
+ required:
+ - expression
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
required:
- issuer
- name
diff --git a/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml b/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml
index 13ccf75834c..a67e36d0ee6 100644
--- a/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml
+++ b/payload-manifests/featuregates/featureGate-Hypershift-Default.yaml
@@ -58,6 +58,9 @@
{
"name": "Example2"
},
+ {
+ "name": "ExternalOIDCWithNewAuthConfigFields"
+ },
{
"name": "ExternalOIDCWithUIDAndExtraClaimMappings"
},
diff --git a/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml
index 4d843f294cc..12352a42930 100644
--- a/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-Hypershift-DevPreviewNoUpgrade.yaml
@@ -122,6 +122,9 @@
{
"name": "ExternalOIDC"
},
+ {
+ "name": "ExternalOIDCWithNewAuthConfigFields"
+ },
{
"name": "ExternalOIDCWithUIDAndExtraClaimMappings"
},
diff --git a/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml
index a6f5efc856b..9626c2cfcdf 100644
--- a/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-Hypershift-TechPreviewNoUpgrade.yaml
@@ -131,6 +131,9 @@
{
"name": "ExternalOIDC"
},
+ {
+ "name": "ExternalOIDCWithNewAuthConfigFields"
+ },
{
"name": "ExternalOIDCWithUIDAndExtraClaimMappings"
},
diff --git a/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml b/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml
index df9e93be7a7..a3c1f4ccc2f 100644
--- a/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml
+++ b/payload-manifests/featuregates/featureGate-SelfManagedHA-Default.yaml
@@ -61,6 +61,9 @@
{
"name": "ExternalOIDC"
},
+ {
+ "name": "ExternalOIDCWithNewAuthConfigFields"
+ },
{
"name": "ExternalOIDCWithUIDAndExtraClaimMappings"
},
diff --git a/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml
index d929fa6096b..28876b7cb62 100644
--- a/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-SelfManagedHA-DevPreviewNoUpgrade.yaml
@@ -110,6 +110,9 @@
{
"name": "ExternalOIDC"
},
+ {
+ "name": "ExternalOIDCWithNewAuthConfigFields"
+ },
{
"name": "ExternalOIDCWithUIDAndExtraClaimMappings"
},
diff --git a/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml b/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml
index 98bbb0ea13b..8a10a55d4c6 100644
--- a/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml
+++ b/payload-manifests/featuregates/featureGate-SelfManagedHA-TechPreviewNoUpgrade.yaml
@@ -119,6 +119,9 @@
{
"name": "ExternalOIDC"
},
+ {
+ "name": "ExternalOIDCWithNewAuthConfigFields"
+ },
{
"name": "ExternalOIDCWithUIDAndExtraClaimMappings"
},