Skip to content

Commit

Permalink
AuthPolicy Atomic Overrides (#525)
Browse files Browse the repository at this point in the history
* Initial types added

rebase commit

* Fix typo

* Reconcile atomic overrides for AuthPolicy

* Update docs

* fix bundles and imports for PR checks

* Add AuthPolicy controller intergation tests

* Add CEL to limit adding the of overrides on AuthPolicies attached to HTTPRoutes

* refactor based on PR comments
  • Loading branch information
Boomatang authored Apr 19, 2024
1 parent 6ba870a commit e3b119e
Show file tree
Hide file tree
Showing 10 changed files with 9,027 additions and 36 deletions.
36 changes: 30 additions & 6 deletions api/v1beta2/authpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ type AuthSchemeSpec struct {
// Authentication configs.
// At least one config MUST evaluate to a valid identity object for the auth request to be successful.
// +optional
// +kubebuilder:validation:MaxProperties=14
// +kubebuilder:validation:MaxProperties=10
Authentication map[string]AuthenticationSpec `json:"authentication,omitempty"`

// Metadata sources.
// Authorino fetches auth metadata as JSON from sources specified in this config.
// +optional
// +kubebuilder:validation:MaxProperties=14
// +kubebuilder:validation:MaxProperties=10
Metadata map[string]MetadataSpec `json:"metadata,omitempty"`

// Authorization policies.
// All policies MUST evaluate to "allowed = true" for the auth request be successful.
// +optional
// +kubebuilder:validation:MaxProperties=14
// +kubebuilder:validation:MaxProperties=10
Authorization map[string]AuthorizationSpec `json:"authorization,omitempty"`

// Response items.
Expand All @@ -47,7 +47,7 @@ type AuthSchemeSpec struct {
// Callback functions.
// Authorino sends callbacks at the end of the auth pipeline to the endpoints specified in this config.
// +optional
// +kubebuilder:validation:MaxProperties=14
// +kubebuilder:validation:MaxProperties=10
Callbacks map[string]CallbackSpec `json:"callbacks,omitempty"`
}

Expand Down Expand Up @@ -104,13 +104,13 @@ type ResponseSpec struct {
type WrappedSuccessResponseSpec struct {
// Custom success response items wrapped as HTTP headers.
// For integration of Authorino via proxy, the proxy must use these settings to inject data in the request.
// +kubebuilder:validation:MaxProperties=14
// +kubebuilder:validation:MaxProperties=10
Headers map[string]HeaderSuccessResponseSpec `json:"headers,omitempty"`

// Custom success response items wrapped as HTTP headers.
// For integration of Authorino via proxy, the proxy must use these settings to propagate dynamic metadata.
// See https://www.envoyproxy.io/docs/envoy/latest/configuration/advanced/well_known_dynamic_metadata
// +kubebuilder:validation:MaxProperties=14
// +kubebuilder:validation:MaxProperties=10
DynamicMetadata map[string]SuccessResponseSpec `json:"dynamicMetadata,omitempty"`
}

Expand Down Expand Up @@ -144,8 +144,19 @@ type CallbackSpec struct {
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.defaults) || !has(self.defaults.rules) || !has(self.defaults.rules.response) || !has(self.defaults.rules.response.success) || !has(self.defaults.rules.response.success.headers) || !self.defaults.rules.response.success.headers.exists(x, has(self.defaults.rules.response.success.headers[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.defaults) || !has(self.defaults.rules) || !has(self.defaults.rules.response) || !has(self.defaults.rules.response.success) || !has(self.defaults.rules.response.success.dynamicMetadata) || !self.defaults.rules.response.success.dynamicMetadata.exists(x, has(self.defaults.rules.response.success.dynamicMetadata[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.defaults) || !has(self.defaults.rules) || !has(self.defaults.rules.callbacks) || !self.defaults.rules.callbacks.exists(x, has(self.defaults.rules.callbacks[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// RouteSelectors - explicit overrides validation
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.overrides) || !has(self.overrides.routeSelectors)",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.overrides) || !has(self.overrides.rules) || !has(self.overrides.rules.authentication) || !self.overrides.rules.authentication.exists(x, has(self.overrides.rules.authentication[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.overrides) || !has(self.overrides.rules) || !has(self.overrides.rules.metadata) || !self.overrides.rules.metadata.exists(x, has(self.overrides.rules.metadata[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.overrides) || !has(self.overrides.rules) || !has(self.overrides.rules.authorization) || !self.overrides.rules.authorization.exists(x, has(self.overrides.rules.authorization[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.overrides) || !has(self.overrides.rules) || !has(self.overrides.rules.response) || !has(self.overrides.rules.response.success) || !has(self.overrides.rules.response.success.headers) || !self.overrides.rules.response.success.headers.exists(x, has(self.overrides.rules.response.success.headers[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.overrides) || !has(self.overrides.rules) || !has(self.overrides.rules.response) || !has(self.overrides.rules.response.success) || !has(self.overrides.rules.response.success.dynamicMetadata) || !self.overrides.rules.response.success.dynamicMetadata.exists(x, has(self.overrides.rules.response.success.dynamicMetadata[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// +kubebuilder:validation:XValidation:rule="self.targetRef.kind != 'Gateway' || !has(self.overrides) || !has(self.overrides.rules) || !has(self.overrides.rules.callbacks) || !self.overrides.rules.callbacks.exists(x, has(self.overrides.rules.callbacks[x].routeSelectors))",message="route selectors not supported when targeting a Gateway"
// Mutual Exclusivity Validation
// +kubebuilder:validation:XValidation:rule="!(has(self.defaults) && (has(self.routeSelectors) || has(self.patterns) || has(self.when) || has(self.rules)))",message="Implicit and explicit defaults are mutually exclusive"
// +kubebuilder:validation:XValidation:rule="!(has(self.overrides) && (has(self.routeSelectors) || has(self.patterns) || has(self.when) || has(self.rules)))",message="Implicit defaults and explicit overrides are mutually exclusive"
// +kubebuilder:validation:XValidation:rule="!(has(self.overrides) && has(self.defaults))",message="Explicit overrides and explicit defaults are mutually exclusive"
// +kubebuilder:validation:XValidation:rule="!(has(self.overrides) && self.targetRef.kind == 'HTTPRoute')",message="Overrides are not allowed for policies targeting a HTTPRoute resource"
type AuthPolicySpec struct {
// TargetRef identifies an API object to apply policy to.
// +kubebuilder:validation:XValidation:rule="self.group == 'gateway.networking.k8s.io'",message="Invalid targetRef.group. The only supported value is 'gateway.networking.k8s.io'"
Expand All @@ -157,6 +168,11 @@ type AuthPolicySpec struct {
// +optional
Defaults *AuthPolicyCommonSpec `json:"defaults,omitempty"`

// Overrides define explicit override values for this policy.
// Overrides are mutually exclusive with explicit and implicit defaults defined by AuthPolicyCommonSpec.
// +optional
Overrides *AuthPolicyCommonSpec `json:"overrides,omitempty"`

// AuthPolicyCommonSpec defines implicit default values for this policy and for policies inheriting this policy.
// AuthPolicyCommonSpec is mutually exclusive with explicit defaults defined by Defaults.
AuthPolicyCommonSpec `json:""`
Expand Down Expand Up @@ -247,6 +263,10 @@ type AuthPolicy struct {
Status AuthPolicyStatus `json:"status,omitempty"`
}

func (ap *AuthPolicy) IsAtomicOverride() bool {
return ap.Spec.Overrides != nil
}

func (ap *AuthPolicy) TargetKey() client.ObjectKey {
ns := ap.Namespace
if ap.Spec.TargetRef.Namespace != nil {
Expand Down Expand Up @@ -335,6 +355,10 @@ func (ap *AuthPolicySpec) CommonSpec() *AuthPolicyCommonSpec {
return ap.Defaults
}

if ap.Overrides != nil {
return ap.Overrides
}

return &ap.AuthPolicyCommonSpec
}

Expand Down
5 changes: 5 additions & 0 deletions api/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ metadata:
capabilities: Basic Install
categories: Integration & Delivery
containerImage: quay.io/kuadrant/kuadrant-operator:latest
createdAt: "2024-03-25T09:38:12Z"
createdAt: "2024-04-15T13:13:02Z"
operators.operatorframework.io/builder: operator-sdk-v1.32.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
repository: https://github.com/Kuadrant/kuadrant-operator
Expand Down
Loading

0 comments on commit e3b119e

Please sign in to comment.