From eb610353bc3d8df655bf978e5e9b84c6a39c63e6 Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Thu, 7 Nov 2024 23:14:57 +0100 Subject: [PATCH] drop user-defined top-level conditions in the authpolicy if favour of cel predicates only (#988) Signed-off-by: Guilherme Cassolato --- api/v1beta3/authpolicy_types.go | 82 +-------- api/v1beta3/common_types.go | 66 +++++++ api/v1beta3/ratelimitpolicy_types.go | 74 +------- api/v1beta3/zz_generated.deepcopy.go | 69 +++----- ...adrant-operator.clusterserviceversion.yaml | 2 +- .../manifests/kuadrant.io_authpolicies.yaml | 150 +++------------- .../kuadrant.io_ratelimitpolicies.yaml | 15 +- .../templates/manifests.yaml | 165 ++++-------------- .../crd/bases/kuadrant.io_authpolicies.yaml | 150 +++------------- .../bases/kuadrant.io_ratelimitpolicies.yaml | 15 +- controllers/auth_workflow_helpers.go | 16 +- controllers/authconfigs_reconciler.go | 7 - pkg/wasm/types.go | 58 +----- pkg/wasm/types_test.go | 16 +- pkg/wasm/utils.go | 12 -- pkg/wasm/utils_test.go | 30 +--- .../authpolicy/authpolicy_controller_test.go | 22 +-- tests/istio/extension_reconciler_test.go | 10 +- 18 files changed, 239 insertions(+), 720 deletions(-) create mode 100644 api/v1beta3/common_types.go diff --git a/api/v1beta3/authpolicy_types.go b/api/v1beta3/authpolicy_types.go index 936dade12..5edba1cdc 100644 --- a/api/v1beta3/authpolicy_types.go +++ b/api/v1beta3/authpolicy_types.go @@ -24,7 +24,6 @@ import ( "github.com/google/go-cmp/cmp" authorinov1beta3 "github.com/kuadrant/authorino/api/v1beta3" "github.com/kuadrant/policy-machinery/machinery" - "github.com/samber/lo" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -42,43 +41,6 @@ const ( AuthPolicyDirectReferenceAnnotationName = "kuadrant.io/authpolicy" ) -const ( - EqualOperator WhenConditionOperator = "eq" - NotEqualOperator WhenConditionOperator = "neq" - StartsWithOperator WhenConditionOperator = "startsWith" - EndsWithOperator WhenConditionOperator = "endsWith" - IncludeOperator WhenConditionOperator = "incl" - ExcludeOperator WhenConditionOperator = "excl" - MatchesOperator WhenConditionOperator = "matches" -) - -// +kubebuilder:validation:Enum:=eq;neq;startswith;endswith;incl;excl;matches -type WhenConditionOperator string - -// ContextSelector defines one item from the well known attributes -// Attributes: https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/advanced/attributes -// Well-known selectors: https://github.com/Kuadrant/architecture/blob/main/rfcs/0001-rlp-v2.md#well-known-selectors -// They are named by a dot-separated path (e.g. request.path) -// Example: "request.path" -> The path portion of the URL -// +kubebuilder:validation:MinLength=1 -// +kubebuilder:validation:MaxLength=253 -type ContextSelector string - -// WhenCondition defines semantics for matching an HTTP request based on conditions -// https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec -type WhenCondition struct { - // Selector defines one item from the well known selectors - // TODO Document properly "Well-known selector" https://github.com/Kuadrant/architecture/blob/main/rfcs/0001-rlp-v2.md#well-known-selectors - Selector ContextSelector `json:"selector"` - - // The binary operator to be applied to the content fetched from the selector - // Possible values are: "eq" (equal to), "neq" (not equal to) - Operator WhenConditionOperator `json:"operator"` - - // The value of reference for the comparison. - Value string `json:"value"` -} - var ( AuthPolicyGroupKind = schema.GroupKind{Group: SchemeGroupVersion.Group, Kind: "AuthPolicy"} AuthPoliciesResource = SchemeGroupVersion.WithResource("authpolicies") @@ -170,9 +132,8 @@ func (p *AuthPolicy) Rules() map[string]kuadrantv1.MergeableRule { rules[fmt.Sprintf("patterns#%s", ruleID)] = kuadrantv1.NewMergeableRule(&rule, policyLocator) } - for ruleID := range spec.Conditions { - rule := spec.Conditions[ruleID] - rules[fmt.Sprintf("conditions#%d", ruleID)] = kuadrantv1.NewMergeableRule(&rule, policyLocator) + if whenPredicates := spec.MergeableWhenPredicates; len(whenPredicates.Predicates) > 0 { + rules["conditions#"] = kuadrantv1.NewMergeableRule(&whenPredicates, policyLocator) } if spec.AuthScheme == nil { @@ -226,7 +187,7 @@ func (p *AuthPolicy) Rules() map[string]kuadrantv1.MergeableRule { func (p *AuthPolicy) SetRules(rules map[string]kuadrantv1.MergeableRule) { // clear all rules of the policy before setting new ones p.Spec.Proper().NamedPatterns = nil - p.Spec.Proper().Conditions = nil + p.Spec.Proper().Predicates = nil p.Spec.Proper().AuthScheme = nil ensureNamedPatterns := func() { @@ -305,7 +266,7 @@ func (p *AuthPolicy) SetRules(rules map[string]kuadrantv1.MergeableRule) { ensureNamedPatterns() p.Spec.Proper().NamedPatterns[ruleID] = *rule.(*MergeablePatternExpressions) case "conditions": - p.Spec.Proper().Conditions = append(p.Spec.Proper().Conditions, *rule.(*MergeablePatternExpressionOrRef)) + p.Spec.Proper().MergeableWhenPredicates = *rule.(*MergeableWhenPredicates) case "authentication": ensureAuthentication() p.Spec.Proper().AuthScheme.Authentication[ruleID] = *rule.(*MergeableAuthenticationSpec) @@ -429,7 +390,7 @@ type AuthPolicySpecProper struct { // If omitted, the AuthPolicy will be enforced at all requests to the protected routes. // If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. // +optional - Conditions []MergeablePatternExpressionOrRef `json:"when,omitempty"` + MergeableWhenPredicates `json:""` // The auth rules of the policy. // See Authorino's AuthConfig CRD for more details. @@ -490,39 +451,6 @@ func (r *MergeablePatternExpressionOrRef) WithSource(source string) kuadrantv1.M r.Source = source return r } -func (r *MergeablePatternExpressionOrRef) ToWhenConditions(namedPatterns map[string]MergeablePatternExpressions) []WhenCondition { - if ref := r.PatternRef.Name; ref != "" { - if pattern, ok := namedPatterns[ref]; ok { - return lo.Map(pattern.PatternExpressions, func(p authorinov1beta3.PatternExpression, _ int) WhenCondition { - return WhenCondition{ - Selector: ContextSelector(p.Selector), - Operator: WhenConditionOperator(p.Operator), - Value: p.Value, - } - }) - } - } - - if allOf := r.All; len(allOf) > 0 { - return lo.Map(allOf, func(p authorinov1beta3.UnstructuredPatternExpressionOrRef, _ int) WhenCondition { - return WhenCondition{ - Selector: ContextSelector(p.Selector), - Operator: WhenConditionOperator(p.Operator), - Value: p.Value, - } - }) - } - - // FIXME: anyOf cannot be represented in the current schema of the wasm config - - return []WhenCondition{ - { - Selector: ContextSelector(r.Selector), - Operator: WhenConditionOperator(r.Operator), - Value: r.Value, - }, - } -} type MergeableAuthenticationSpec struct { authorinov1beta3.AuthenticationSpec `json:",inline"` diff --git a/api/v1beta3/common_types.go b/api/v1beta3/common_types.go new file mode 100644 index 000000000..f3fa523bf --- /dev/null +++ b/api/v1beta3/common_types.go @@ -0,0 +1,66 @@ +package v1beta3 + +import ( + "github.com/samber/lo" + + kuadrantv1 "github.com/kuadrant/kuadrant-operator/api/v1" +) + +func NewPredicate(predicate string) Predicate { + return Predicate{Predicate: predicate} +} + +// Predicate defines one CEL expression that must be evaluated to bool +type Predicate struct { + // +kubebuilder:validation:MinLength=1 + Predicate string `json:"predicate"` +} + +func NewWhenPredicates(predicates ...string) WhenPredicates { + whenPredicates := make(WhenPredicates, 0) + for _, predicate := range predicates { + whenPredicates = append(whenPredicates, NewPredicate(predicate)) + } + + return whenPredicates +} + +type WhenPredicates []Predicate + +func (w WhenPredicates) Extend(other WhenPredicates) WhenPredicates { + return append(w, other...) +} + +func (w WhenPredicates) Into() []string { + if w == nil { + return nil + } + + return lo.Map(w, func(p Predicate, _ int) string { return p.Predicate }) +} + +type MergeableWhenPredicates struct { + // Overall conditions for the policy to be enforced. + // If omitted, the policy will be enforced at all requests to the protected routes. + // If present, all conditions must match for the policy to be enforced. + // +optional + Predicates WhenPredicates `json:"when,omitempty"` + + // Source stores the locator of the policy where the limit is orignaly defined (internal use) + Source string `json:"-"` +} + +var _ kuadrantv1.MergeableRule = &MergeableWhenPredicates{} + +func (p *MergeableWhenPredicates) GetSpec() any { + return p.Predicates +} + +func (p *MergeableWhenPredicates) GetSource() string { + return p.Source +} + +func (p *MergeableWhenPredicates) WithSource(source string) kuadrantv1.MergeableRule { + p.Source = source + return p +} diff --git a/api/v1beta3/ratelimitpolicy_types.go b/api/v1beta3/ratelimitpolicy_types.go index e3bbc6d53..89792b22c 100644 --- a/api/v1beta3/ratelimitpolicy_types.go +++ b/api/v1beta3/ratelimitpolicy_types.go @@ -20,7 +20,6 @@ import ( "time" "github.com/kuadrant/policy-machinery/machinery" - "github.com/samber/lo" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -120,16 +119,14 @@ func (p *RateLimitPolicy) Empty() bool { func (p *RateLimitPolicy) Rules() map[string]kuadrantv1.MergeableRule { rules := make(map[string]kuadrantv1.MergeableRule) policyLocator := p.GetLocator() + spec := p.Spec.Proper() - if len(p.Spec.Proper().When) > 0 { - rules[RulesKeyTopLevelPredicates] = kuadrantv1.NewMergeableRule( - &WhenPredicatesMergeableRule{When: p.Spec.Proper().When, Source: policyLocator}, - policyLocator, - ) + if whenPredicates := spec.MergeableWhenPredicates; len(whenPredicates.Predicates) > 0 { + rules[RulesKeyTopLevelPredicates] = kuadrantv1.NewMergeableRule(&whenPredicates, policyLocator) } - for ruleID := range p.Spec.Proper().Limits { - limit := p.Spec.Proper().Limits[ruleID] + for ruleID := range spec.Limits { + limit := spec.Limits[ruleID] rules[ruleID] = kuadrantv1.NewMergeableRule(&limit, policyLocator) } @@ -139,7 +136,7 @@ func (p *RateLimitPolicy) Rules() map[string]kuadrantv1.MergeableRule { func (p *RateLimitPolicy) SetRules(rules map[string]kuadrantv1.MergeableRule) { // clear all rules of the policy before setting new ones p.Spec.Proper().Limits = nil - p.Spec.Proper().When = nil + p.Spec.Proper().Predicates = nil if len(rules) > 0 { p.Spec.Proper().Limits = make(map[string]Limit) @@ -147,7 +144,7 @@ func (p *RateLimitPolicy) SetRules(rules map[string]kuadrantv1.MergeableRule) { for ruleID := range rules { if ruleID == RulesKeyTopLevelPredicates { - p.Spec.Proper().When = rules[ruleID].(*WhenPredicatesMergeableRule).When + p.Spec.Proper().MergeableWhenPredicates = *rules[ruleID].(*MergeableWhenPredicates) } else { p.Spec.Proper().Limits[ruleID] = *rules[ruleID].(*Limit) } @@ -238,68 +235,13 @@ type MergeableRateLimitPolicySpec struct { type RateLimitPolicySpecProper struct { // When holds a list of "top-level" `Predicate`s // +optional - When WhenPredicates `json:"when,omitempty"` + MergeableWhenPredicates `json:""` // Limits holds the struct of limits indexed by a unique name // +optional Limits map[string]Limit `json:"limits,omitempty"` } -// Predicate defines one CEL expression that must be evaluated to bool -type Predicate struct { - // +kubebuilder:validation:MinLength=1 - Predicate string `json:"predicate"` -} - -func NewPredicate(predicate string) Predicate { - return Predicate{Predicate: predicate} -} - -type WhenPredicates []Predicate - -func NewWhenPredicates(predicates ...string) WhenPredicates { - whenPredicates := make(WhenPredicates, 0) - for _, predicate := range predicates { - whenPredicates = append(whenPredicates, NewPredicate(predicate)) - } - - return whenPredicates -} - -func (w WhenPredicates) Extend(other WhenPredicates) WhenPredicates { - return append(w, other...) -} - -func (w WhenPredicates) Into() []string { - if w == nil { - return nil - } - - return lo.Map(w, func(p Predicate, _ int) string { return p.Predicate }) -} - -type WhenPredicatesMergeableRule struct { - When WhenPredicates - - // Source stores the locator of the policy where the limit is orignaly defined (internal use) - Source string -} - -var _ kuadrantv1.MergeableRule = &WhenPredicatesMergeableRule{} - -func (w *WhenPredicatesMergeableRule) GetSpec() any { - return w.When -} - -func (w *WhenPredicatesMergeableRule) GetSource() string { - return w.Source -} - -func (w *WhenPredicatesMergeableRule) WithSource(source string) kuadrantv1.MergeableRule { - w.Source = source - return w -} - type Counter struct { Expression Expression `json:"expression"` } diff --git a/api/v1beta3/zz_generated.deepcopy.go b/api/v1beta3/zz_generated.deepcopy.go index a08cad998..1e1ded8b9 100644 --- a/api/v1beta3/zz_generated.deepcopy.go +++ b/api/v1beta3/zz_generated.deepcopy.go @@ -122,13 +122,7 @@ func (in *AuthPolicySpecProper) DeepCopyInto(out *AuthPolicySpecProper) { (*out)[key] = *val.DeepCopy() } } - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]MergeablePatternExpressionOrRef, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } + in.MergeableWhenPredicates.DeepCopyInto(&out.MergeableWhenPredicates) if in.AuthScheme != nil { in, out := &in.AuthScheme, &out.AuthScheme *out = new(AuthSchemeSpec) @@ -467,6 +461,26 @@ func (in *MergeableSuccessResponseSpec) DeepCopy() *MergeableSuccessResponseSpec return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MergeableWhenPredicates) DeepCopyInto(out *MergeableWhenPredicates) { + *out = *in + if in.Predicates != nil { + in, out := &in.Predicates, &out.Predicates + *out = make(WhenPredicates, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MergeableWhenPredicates. +func (in *MergeableWhenPredicates) DeepCopy() *MergeableWhenPredicates { + if in == nil { + return nil + } + out := new(MergeableWhenPredicates) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MergeableWrappedSuccessResponseSpec) DeepCopyInto(out *MergeableWrappedSuccessResponseSpec) { *out = *in @@ -615,11 +629,7 @@ func (in *RateLimitPolicySpec) DeepCopy() *RateLimitPolicySpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RateLimitPolicySpecProper) DeepCopyInto(out *RateLimitPolicySpecProper) { *out = *in - if in.When != nil { - in, out := &in.When, &out.When - *out = make(WhenPredicates, len(*in)) - copy(*out, *in) - } + in.MergeableWhenPredicates.DeepCopyInto(&out.MergeableWhenPredicates) if in.Limits != nil { in, out := &in.Limits, &out.Limits *out = make(map[string]Limit, len(*in)) @@ -661,21 +671,6 @@ func (in *RateLimitPolicyStatus) DeepCopy() *RateLimitPolicyStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WhenCondition) DeepCopyInto(out *WhenCondition) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WhenCondition. -func (in *WhenCondition) DeepCopy() *WhenCondition { - if in == nil { - return nil - } - out := new(WhenCondition) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in WhenPredicates) DeepCopyInto(out *WhenPredicates) { { @@ -694,23 +689,3 @@ func (in WhenPredicates) DeepCopy() WhenPredicates { in.DeepCopyInto(out) return *out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WhenPredicatesMergeableRule) DeepCopyInto(out *WhenPredicatesMergeableRule) { - *out = *in - if in.When != nil { - in, out := &in.When, &out.When - *out = make(WhenPredicates, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WhenPredicatesMergeableRule. -func (in *WhenPredicatesMergeableRule) DeepCopy() *WhenPredicatesMergeableRule { - if in == nil { - return nil - } - out := new(WhenPredicatesMergeableRule) - in.DeepCopyInto(out) - return out -} diff --git a/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml b/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml index 15117e122..62eb6adcf 100644 --- a/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml +++ b/bundle/manifests/kuadrant-operator.clusterserviceversion.yaml @@ -105,7 +105,7 @@ metadata: capabilities: Basic Install categories: Integration & Delivery containerImage: quay.io/kuadrant/kuadrant-operator:latest - createdAt: "2024-11-06T17:24:27Z" + createdAt: "2024-11-07T16:48:25Z" description: A Kubernetes Operator to manage the lifecycle of the Kuadrant system operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 diff --git a/bundle/manifests/kuadrant.io_authpolicies.yaml b/bundle/manifests/kuadrant.io_authpolicies.yaml index 41827641a..2c6bcf13e 100644 --- a/bundle/manifests/kuadrant.io_authpolicies.yaml +++ b/bundle/manifests/kuadrant.io_authpolicies.yaml @@ -2327,52 +2327,18 @@ spec: type: string when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must + be evaluated to bool properties: - all: - description: A list of pattern expressions to be evaluated - as a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated - as a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array type: object @@ -4632,52 +4598,18 @@ spec: type: string when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must + be evaluated to bool properties: - all: - description: A list of pattern expressions to be evaluated - as a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated - as a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array type: object @@ -6956,52 +6888,18 @@ spec: rule: self.kind == 'HTTPRoute' || self.kind == 'Gateway' when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must be evaluated + to bool properties: - all: - description: A list of pattern expressions to be evaluated as - a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated as - a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array required: diff --git a/bundle/manifests/kuadrant.io_ratelimitpolicies.yaml b/bundle/manifests/kuadrant.io_ratelimitpolicies.yaml index 4aae954cf..839ffa0ee 100644 --- a/bundle/manifests/kuadrant.io_ratelimitpolicies.yaml +++ b/bundle/manifests/kuadrant.io_ratelimitpolicies.yaml @@ -148,7 +148,10 @@ spec: - merge type: string when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool @@ -301,7 +304,10 @@ spec: - merge type: string when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool @@ -364,7 +370,10 @@ spec: and 'Gateway' rule: self.kind == 'HTTPRoute' || self.kind == 'Gateway' when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool diff --git a/charts/kuadrant-operator/templates/manifests.yaml b/charts/kuadrant-operator/templates/manifests.yaml index a0e7c4a44..f47c5cf6b 100644 --- a/charts/kuadrant-operator/templates/manifests.yaml +++ b/charts/kuadrant-operator/templates/manifests.yaml @@ -2327,52 +2327,18 @@ spec: type: string when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must + be evaluated to bool properties: - all: - description: A list of pattern expressions to be evaluated - as a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated - as a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array type: object @@ -4632,52 +4598,18 @@ spec: type: string when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must + be evaluated to bool properties: - all: - description: A list of pattern expressions to be evaluated - as a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated - as a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array type: object @@ -6956,52 +6888,18 @@ spec: rule: self.kind == 'HTTPRoute' || self.kind == 'Gateway' when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must be evaluated + to bool properties: - all: - description: A list of pattern expressions to be evaluated as - a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated as - a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array required: @@ -7960,7 +7858,10 @@ spec: - merge type: string when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool @@ -8113,7 +8014,10 @@ spec: - merge type: string when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool @@ -8176,7 +8080,10 @@ spec: and 'Gateway' rule: self.kind == 'HTTPRoute' || self.kind == 'Gateway' when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool diff --git a/config/crd/bases/kuadrant.io_authpolicies.yaml b/config/crd/bases/kuadrant.io_authpolicies.yaml index 235176e71..f0d67ff18 100644 --- a/config/crd/bases/kuadrant.io_authpolicies.yaml +++ b/config/crd/bases/kuadrant.io_authpolicies.yaml @@ -2326,52 +2326,18 @@ spec: type: string when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must + be evaluated to bool properties: - all: - description: A list of pattern expressions to be evaluated - as a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated - as a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array type: object @@ -4631,52 +4597,18 @@ spec: type: string when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must + be evaluated to bool properties: - all: - description: A list of pattern expressions to be evaluated - as a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated - as a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array type: object @@ -6955,52 +6887,18 @@ spec: rule: self.kind == 'HTTPRoute' || self.kind == 'Gateway' when: description: |- - Overall conditions for the AuthPolicy to be enforced. - If omitted, the AuthPolicy will be enforced at all requests to the protected routes. - If present, all conditions must match for the AuthPolicy to be enforced; otherwise, the authorization service skips the AuthPolicy and returns to the auth request with status OK. + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: + description: Predicate defines one CEL expression that must be evaluated + to bool properties: - all: - description: A list of pattern expressions to be evaluated as - a logical AND. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - any: - description: A list of pattern expressions to be evaluated as - a logical OR. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - operator: - description: |- - The binary operator to be applied to the content fetched from the authorization JSON, for comparison with "value". - Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - enum: - - eq - - neq - - incl - - excl - - matches - type: string - patternRef: - description: Reference to a named set of pattern expressions - type: string predicate: + minLength: 1 type: string - selector: - description: |- - Path selector to fetch content from the authorization JSON (e.g. 'request.method'). - Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. - Authorino custom JSON path modifiers are also supported. - type: string - value: - description: |- - The value of reference for the comparison with the content fetched from the authorization JSON. - If used with the "matches" operator, the value must compile to a valid Golang regex. - type: string + required: + - predicate type: object type: array required: diff --git a/config/crd/bases/kuadrant.io_ratelimitpolicies.yaml b/config/crd/bases/kuadrant.io_ratelimitpolicies.yaml index c6dc6e352..c63529cfa 100644 --- a/config/crd/bases/kuadrant.io_ratelimitpolicies.yaml +++ b/config/crd/bases/kuadrant.io_ratelimitpolicies.yaml @@ -147,7 +147,10 @@ spec: - merge type: string when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool @@ -300,7 +303,10 @@ spec: - merge type: string when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool @@ -363,7 +369,10 @@ spec: and 'Gateway' rule: self.kind == 'HTTPRoute' || self.kind == 'Gateway' when: - description: When holds a list of "top-level" `Predicate`s + description: |- + Overall conditions for the policy to be enforced. + If omitted, the policy will be enforced at all requests to the protected routes. + If present, all conditions must match for the policy to be enforced. items: description: Predicate defines one CEL expression that must be evaluated to bool diff --git a/controllers/auth_workflow_helpers.go b/controllers/auth_workflow_helpers.go index 3edb1303f..0e65cb74f 100644 --- a/controllers/auth_workflow_helpers.go +++ b/controllers/auth_workflow_helpers.go @@ -125,20 +125,8 @@ func buildWasmActionsForAuth(pathID string, effectivePolicy EffectiveAuthPolicy) } spec := effectivePolicy.Spec.Spec.Proper() - predicates := make([]string, 0) - whenConditions := make([]kuadrantv1beta3.WhenCondition, 0) - for _, condition := range spec.Conditions { - if condition.Predicate != "" { - predicates = append(predicates, condition.Predicate) - } else { - whenConditions = append(whenConditions, condition.ToWhenConditions(spec.NamedPatterns)...) - } - } - if len(predicates) > 0 { - action.Predicates = predicates - } - if conditions := wasm.ConditionsFromWhenConditions(whenConditions...); len(conditions) > 0 { - action.Conditions = conditions + if whenPredicates := spec.Predicates; len(whenPredicates) > 0 { + action.Predicates = whenPredicates.Into() } return []wasm.Action{action} diff --git a/controllers/authconfigs_reconciler.go b/controllers/authconfigs_reconciler.go index 7c72b4701..de6725210 100644 --- a/controllers/authconfigs_reconciler.go +++ b/controllers/authconfigs_reconciler.go @@ -179,13 +179,6 @@ func (r *AuthConfigsReconciler) buildDesiredAuthConfig(effectivePolicy Effective }) } - // top-level conditions - if conditions := spec.Conditions; conditions != nil { - authConfig.Spec.Conditions = lo.Map(spec.Conditions, func(v kuadrantv1beta3.MergeablePatternExpressionOrRef, _ int) authorinov1beta3.PatternExpressionOrRef { - return v.PatternExpressionOrRef - }) - } - // return early if authScheme is nil authScheme := spec.AuthScheme if authScheme == nil { diff --git a/pkg/wasm/types.go b/pkg/wasm/types.go index 1642773dc..c6316aa32 100644 --- a/pkg/wasm/types.go +++ b/pkg/wasm/types.go @@ -7,8 +7,6 @@ import ( _struct "google.golang.org/protobuf/types/known/structpb" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - - kuadrantv1beta3 "github.com/kuadrant/kuadrant-operator/api/v1beta3" ) type Config struct { @@ -133,36 +131,11 @@ func (r *RouteRuleConditions) EqualTo(other RouteRuleConditions) bool { return true } -type Condition struct { - // Selector of an attribute from the contextual properties provided by kuadrant - // during request and connection processing - Selector kuadrantv1beta3.ContextSelector `json:"selector"` - - // The binary operator to be applied to the content fetched from context, for comparison with "value". - // Possible values are: "eq" (equal to), "neq" (not equal to), "incl" (includes; for arrays), "excl" (excludes; for arrays), "matches" (regex) - // TODO build comprehensive list of operators - Operator PatternOperator `json:"operator"` - - // The value of reference for the comparison with the content fetched from the context. - Value string `json:"value"` -} - -func (p *Condition) EqualTo(other Condition) bool { - return p.Selector == other.Selector && - p.Operator == other.Operator && - p.Value == other.Value -} - -type PatternOperator kuadrantv1beta3.WhenConditionOperator - type Action struct { ServiceName string `json:"service"` Scope string `json:"scope"` - // Conditions that activate the action - Conditions []Condition `json:"conditions,omitempty"` - - // When holds a list of CEL `Predicate`s + // Predicates holds a list of CEL predicates // +optional Predicates []string `json:"predicates,omitempty"` @@ -174,18 +147,11 @@ type Action struct { func (a *Action) EqualTo(other Action) bool { if a.Scope != other.Scope || a.ServiceName != other.ServiceName || - len(a.Conditions) != len(other.Conditions) || len(a.Predicates) != len(other.Predicates) || len(a.Data) != len(other.Data) { return false } - for i := range a.Conditions { - if !a.Conditions[i].EqualTo(other.Conditions[i]) { - return false - } - } - for i := range a.Predicates { if a.Predicates[i] != other.Predicates[i] { return false @@ -209,7 +175,6 @@ func (d *DataType) UnmarshalJSON(data []byte) error { // Precisely one of "static", "selector" must be set. types := []interface{}{ &Static{}, - &Selector{}, &Expression{}, } @@ -232,8 +197,6 @@ func (d *DataType) MarshalJSON() ([]byte, error) { switch val := d.Value.(type) { case *Static: return json.Marshal(val) - case *Selector: - return json.Marshal(val) case *Expression: return json.Marshal(val) default: @@ -257,30 +220,11 @@ type Static struct { Static StaticSpec `json:"static"` } -type Selector struct { - Selector SelectorSpec `json:"selector"` -} - type StaticSpec struct { Value string `json:"value"` Key string `json:"key"` } -type SelectorSpec struct { - // Selector of an attribute from the contextual properties provided by kuadrant - // during request and connection processing - Selector kuadrantv1beta3.ContextSelector `json:"selector"` - - // If not set it defaults to `selector` field value as the descriptor key. - // +optional - Key *string `json:"key,omitempty"` - - // An optional value to use if the selector is not found in the context. - // If not set and the selector is not found in the context, then no descriptor is generated. - // +optional - Default *string `json:"default,omitempty"` -} - type ExpressionItem struct { // Key holds the expression key Key string `json:"key"` diff --git a/pkg/wasm/types_test.go b/pkg/wasm/types_test.go index 1e296adf3..314d4e27c 100644 --- a/pkg/wasm/types_test.go +++ b/pkg/wasm/types_test.go @@ -70,12 +70,8 @@ func TestConfigEqual(t *testing.T) { { ServiceName: "ratelimit-service", Scope: "default/other", - Conditions: []Condition{ - { - Selector: "source.address", - Operator: "neq", - Value: "127.0.0.1", - }, + Predicates: []string{ + "source.address != '127.0.0.1'", }, Data: []DataType{ { @@ -97,12 +93,8 @@ func TestConfigEqual(t *testing.T) { { Actions: []Action{ { - Conditions: []Condition{ - { - Operator: "neq", - Selector: "source.address", - Value: "127.0.0.1", - }, + Predicates: []string{ + "source.address != '127.0.0.1'", }, Data: []DataType{ { diff --git a/pkg/wasm/utils.go b/pkg/wasm/utils.go index c4b5030c2..06fd9d034 100644 --- a/pkg/wasm/utils.go +++ b/pkg/wasm/utils.go @@ -13,7 +13,6 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" - kuadrantv1beta3 "github.com/kuadrant/kuadrant-operator/api/v1beta3" "github.com/kuadrant/kuadrant-operator/pkg/common" kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi" ) @@ -113,17 +112,6 @@ func ConfigFromJSON(configJSON *apiextensionsv1.JSON) (*Config, error) { return config, nil } -// ConditionsFromWhenConditions builds a list of predicates from a list of (selector, operator, value) when conditions -func ConditionsFromWhenConditions(when ...kuadrantv1beta3.WhenCondition) []Condition { - return lo.Map(when, func(when kuadrantv1beta3.WhenCondition, _ int) Condition { - return Condition{ - Selector: when.Selector, - Operator: PatternOperator(when.Operator), - Value: when.Value, - } - }) -} - // PredicatesFromHTTPRouteMatch builds a list of conditions from a rule match func PredicatesFromHTTPRouteMatch(match gatewayapiv1.HTTPRouteMatch) []string { predicates := make([]string, 0) diff --git a/pkg/wasm/utils_test.go b/pkg/wasm/utils_test.go index 5b2cbd5b3..a6074996c 100644 --- a/pkg/wasm/utils_test.go +++ b/pkg/wasm/utils_test.go @@ -42,12 +42,8 @@ var ( { ServiceName: "ratelimit-service", Scope: "default/other", - Conditions: []Condition{ - { - Selector: "source.address", - Operator: "neq", - Value: "127.0.0.1", - }, + Predicates: []string{ + `source.address != "127.0.0.1"`, }, Data: []DataType{ { @@ -93,12 +89,8 @@ var ( { ServiceName: "ratelimit-service", Scope: "default/toystore", - Conditions: []Condition{ - { - Selector: "source.address", - Operator: "neq", - Value: "127.0.0.1", - }, + Predicates: []string{ + `source.address != "127.0.0.1"`, }, Data: []DataType{ { @@ -115,7 +107,7 @@ var ( }, }, } - testBasicConfigJSON = `{"services":{"auth-service":{"endpoint":"kuadrant-auth-service","type":"auth","failureMode":"deny"},"ratelimit-service":{"endpoint":"kuadrant-ratelimit-service","type":"ratelimit","failureMode":"allow"}},"actionSets":[{"name":"5755da0b3c275ba6b8f553890eb32b04768a703b60ab9a5d7f4e0948e23ef0ab","routeRuleConditions":{"hostnames":["other.example.com"],"predicates":["request.url_path.startsWith('/')"]},"actions":[{"service":"ratelimit-service","scope":"default/other","conditions":[{"operator":"neq","selector":"source.address","value":"127.0.0.1"}],"data":[{"static":{"key":"limit.global__f63bec56","value":"1"}}]}]},{"name":"21cb3adc608c09a360d62a03fd1afd7cc6f8720999a51d7916927fff26a34ef8","routeRuleConditions":{"hostnames":["*"],"predicates":["request.method == 'GET'","request.url_path.startsWith('/')"]},"actions":[{"service":"auth-service","scope":"e2db39952dd3bc72e152330a2eb15abbd9675c7ac6b54a1a292f07f25f09f138"},{"service":"ratelimit-service","scope":"default/toystore","data":[{"static":{"key":"limit.specific__69ea4d2d","value":"1"}}]},{"service":"ratelimit-service","scope":"default/toystore","conditions":[{"operator":"neq","selector":"source.address","value":"127.0.0.1"}],"data":[{"static":{"key":"limit.global__f63bec56","value":"1"}}]}]}]}` + testBasicConfigJSON = `{"services":{"auth-service":{"endpoint":"kuadrant-auth-service","type":"auth","failureMode":"deny"},"ratelimit-service":{"endpoint":"kuadrant-ratelimit-service","type":"ratelimit","failureMode":"allow"}},"actionSets":[{"name":"5755da0b3c275ba6b8f553890eb32b04768a703b60ab9a5d7f4e0948e23ef0ab","routeRuleConditions":{"hostnames":["other.example.com"],"predicates":["request.url_path.startsWith('/')"]},"actions":[{"service":"ratelimit-service","scope":"default/other","predicates":["source.address != \"127.0.0.1\""],"data":[{"static":{"key":"limit.global__f63bec56","value":"1"}}]}]},{"name":"21cb3adc608c09a360d62a03fd1afd7cc6f8720999a51d7916927fff26a34ef8","routeRuleConditions":{"hostnames":["*"],"predicates":["request.method == 'GET'","request.url_path.startsWith('/')"]},"actions":[{"service":"auth-service","scope":"e2db39952dd3bc72e152330a2eb15abbd9675c7ac6b54a1a292f07f25f09f138"},{"service":"ratelimit-service","scope":"default/toystore","data":[{"static":{"key":"limit.specific__69ea4d2d","value":"1"}}]},{"service":"ratelimit-service","scope":"default/toystore","predicates":["source.address != \"127.0.0.1\""],"data":[{"static":{"key":"limit.global__f63bec56","value":"1"}}]}]}]}` testBasicConfigYAML = ` services: auth-service: @@ -136,10 +128,8 @@ actionSets: actions: - service: ratelimit-service scope: default/other - conditions: - - operator: neq - selector: source.address - value: 127.0.0.1 + predicates: + - source.address != "127.0.0.1" data: - static: key: limit.global__f63bec56 @@ -162,10 +152,8 @@ actionSets: value: "1" - service: ratelimit-service scope: default/toystore - conditions: - - operator: neq - selector: source.address - value: 127.0.0.1 + predicates: + - source.address != "127.0.0.1" data: - static: key: limit.global__f63bec56 diff --git a/tests/common/authpolicy/authpolicy_controller_test.go b/tests/common/authpolicy/authpolicy_controller_test.go index 2be5f51bd..d8ca028ee 100644 --- a/tests/common/authpolicy/authpolicy_controller_test.go +++ b/tests/common/authpolicy/authpolicy_controller_test.go @@ -272,13 +272,9 @@ var _ = Describe("AuthPolicy controller", func() { }, }, } - policy.Spec.Proper().Conditions = []kuadrantv1beta3.MergeablePatternExpressionOrRef{ - { - PatternExpressionOrRef: authorinov1beta3.PatternExpressionOrRef{ - PatternRef: authorinov1beta3.PatternRef{ - Name: "internal-source", - }, - }, + policy.Spec.Proper().MergeableWhenPredicates = kuadrantv1beta3.MergeableWhenPredicates{ + Predicates: kuadrantv1beta3.WhenPredicates{ + {Predicate: `source.ip.matches("^192\.168\..*")`}, }, } policy.Spec.Proper().AuthScheme = &kuadrantv1beta3.AuthSchemeSpec{ @@ -484,7 +480,7 @@ var _ = Describe("AuthPolicy controller", func() { authConfig := &authorinov1beta3.AuthConfig{} Eventually(fetchReadyAuthConfig(ctx, httpRoute, 0, authConfig)).WithContext(ctx).Should(BeTrue()) authConfigSpecAsJSON, _ := json.Marshal(authConfig.Spec) - Expect(string(authConfigSpecAsJSON)).To(Equal(fmt.Sprintf(`{"hosts":["%s"],"patterns":{"authz-and-rl-required":[{"selector":"source.ip","operator":"neq","value":"192.168.0.10"}],"internal-source":[{"selector":"source.ip","operator":"matches","value":"192\\.168\\..*"}]},"when":[{"patternRef":"internal-source"}],"authentication":{"jwt":{"when":[{"selector":"filter_metadata.envoy\\.filters\\.http\\.jwt_authn|verified_jwt","operator":"neq"}],"credentials":{},"plain":{"selector":"filter_metadata.envoy\\.filters\\.http\\.jwt_authn|verified_jwt"}}},"metadata":{"user-groups":{"when":[{"selector":"auth.identity.admin","operator":"neq","value":"true"}],"http":{"url":"http://user-groups/username={auth.identity.username}","method":"GET","contentType":"application/x-www-form-urlencoded","credentials":{}}}},"authorization":{"admin-or-privileged":{"when":[{"patternRef":"authz-and-rl-required"}],"patternMatching":{"patterns":[{"any":[{"selector":"auth.identity.admin","operator":"eq","value":"true"},{"selector":"auth.metadata.user-groups","operator":"incl","value":"privileged"}]}]}}},"response":{"unauthenticated":{"message":{"value":"Missing verified JWT injected by the gateway"}},"unauthorized":{"message":{"value":"User must be admin or member of privileged group"}},"success":{"headers":{"x-username":{"when":[{"selector":"request.headers.x-propagate-username.@case:lower","operator":"matches","value":"1|yes|true"}],"plain":{"value":null,"selector":"auth.identity.username"}}},"dynamicMetadata":{"x-auth-data":{"when":[{"patternRef":"authz-and-rl-required"}],"json":{"properties":{"groups":{"value":null,"selector":"auth.metadata.user-groups"},"username":{"value":null,"selector":"auth.identity.username"}}}}}}},"callbacks":{"unauthorized-attempt":{"when":[{"patternRef":"authz-and-rl-required"},{"selector":"auth.authorization.admin-or-privileged","operator":"neq","value":"true"}],"http":{"url":"http://events/unauthorized","method":"POST","body":{"value":null,"selector":"\\{\"identity\":{auth.identity},\"request-id\":{request.id}\\}"},"contentType":"application/json","credentials":{}}}}}`, authConfig.GetName()))) + Expect(string(authConfigSpecAsJSON)).To(Equal(fmt.Sprintf(`{"hosts":["%s"],"patterns":{"authz-and-rl-required":[{"selector":"source.ip","operator":"neq","value":"192.168.0.10"}],"internal-source":[{"selector":"source.ip","operator":"matches","value":"192\\.168\\..*"}]},"authentication":{"jwt":{"when":[{"selector":"filter_metadata.envoy\\.filters\\.http\\.jwt_authn|verified_jwt","operator":"neq"}],"credentials":{},"plain":{"selector":"filter_metadata.envoy\\.filters\\.http\\.jwt_authn|verified_jwt"}}},"metadata":{"user-groups":{"when":[{"selector":"auth.identity.admin","operator":"neq","value":"true"}],"http":{"url":"http://user-groups/username={auth.identity.username}","method":"GET","contentType":"application/x-www-form-urlencoded","credentials":{}}}},"authorization":{"admin-or-privileged":{"when":[{"patternRef":"authz-and-rl-required"}],"patternMatching":{"patterns":[{"any":[{"selector":"auth.identity.admin","operator":"eq","value":"true"},{"selector":"auth.metadata.user-groups","operator":"incl","value":"privileged"}]}]}}},"response":{"unauthenticated":{"message":{"value":"Missing verified JWT injected by the gateway"}},"unauthorized":{"message":{"value":"User must be admin or member of privileged group"}},"success":{"headers":{"x-username":{"when":[{"selector":"request.headers.x-propagate-username.@case:lower","operator":"matches","value":"1|yes|true"}],"plain":{"value":null,"selector":"auth.identity.username"}}},"dynamicMetadata":{"x-auth-data":{"when":[{"patternRef":"authz-and-rl-required"}],"json":{"properties":{"groups":{"value":null,"selector":"auth.metadata.user-groups"},"username":{"value":null,"selector":"auth.identity.username"}}}}}}},"callbacks":{"unauthorized-attempt":{"when":[{"patternRef":"authz-and-rl-required"},{"selector":"auth.authorization.admin-or-privileged","operator":"neq","value":"true"}],"http":{"url":"http://events/unauthorized","method":"POST","body":{"value":null,"selector":"\\{\"identity\":{auth.identity},\"request-id\":{request.id}\\}"},"contentType":"application/json","credentials":{}}}}}`, authConfig.GetName()))) }, testTimeOut) It("Succeeds when AuthScheme is not defined", func(ctx SpecContext) { @@ -994,13 +990,9 @@ var _ = Describe("AuthPolicy CEL Validations", func() { It("Invalid when both implicit and explicit defaults are used - conditions", func(ctx SpecContext) { policy := policyFactory(func(policy *kuadrantv1beta3.AuthPolicy) { policy.Spec.Defaults = &kuadrantv1beta3.MergeableAuthPolicySpec{} - policy.Spec.Conditions = []kuadrantv1beta3.MergeablePatternExpressionOrRef{ - { - PatternExpressionOrRef: authorinov1beta3.PatternExpressionOrRef{ - PatternRef: authorinov1beta3.PatternRef{ - Name: "internal-source", - }, - }, + policy.Spec.MergeableWhenPredicates = kuadrantv1beta3.MergeableWhenPredicates{ + Predicates: kuadrantv1beta3.WhenPredicates{ + {Predicate: `source.ip.matches("^192\.168\..*")`}, }, } }) diff --git a/tests/istio/extension_reconciler_test.go b/tests/istio/extension_reconciler_test.go index a4ccc28a6..daf235e0e 100644 --- a/tests/istio/extension_reconciler_test.go +++ b/tests/istio/extension_reconciler_test.go @@ -245,10 +245,12 @@ var _ = Describe("Rate Limiting WasmPlugin controller", func() { }, }, RateLimitPolicySpecProper: kuadrantv1beta3.RateLimitPolicySpecProper{ - When: kuadrantv1beta3.NewWhenPredicates( - "source.remote_address != '192.168.1.1'", - "auth.identity.username != 'root'", - ), + MergeableWhenPredicates: kuadrantv1beta3.MergeableWhenPredicates{ + Predicates: kuadrantv1beta3.NewWhenPredicates( + "source.remote_address != '192.168.1.1'", + "auth.identity.username != 'root'", + ), + }, Limits: map[string]kuadrantv1beta3.Limit{ "users": { Rates: []kuadrantv1beta3.Rate{