diff --git a/examples/kuadrant/color_policy.go b/examples/color_policy/color_policy.go similarity index 99% rename from examples/kuadrant/color_policy.go rename to examples/color_policy/color_policy.go index fed1152..05c1d9a 100644 --- a/examples/kuadrant/color_policy.go +++ b/examples/color_policy/color_policy.go @@ -1,4 +1,4 @@ -package kuadrant +package color_policy import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/examples/kuadrant/color_policy_test.go b/examples/color_policy/color_policy_test.go similarity index 99% rename from examples/kuadrant/color_policy_test.go rename to examples/color_policy/color_policy_test.go index bccedc9..f412c1f 100644 --- a/examples/kuadrant/color_policy_test.go +++ b/examples/color_policy/color_policy_test.go @@ -1,6 +1,6 @@ //go:build unit -package kuadrant +package color_policy import ( "testing" diff --git a/examples/kuadrant/integration_test.go b/examples/color_policy/integration_test.go similarity index 99% rename from examples/kuadrant/integration_test.go rename to examples/color_policy/integration_test.go index 41e9311..8d87b77 100644 --- a/examples/kuadrant/integration_test.go +++ b/examples/color_policy/integration_test.go @@ -1,6 +1,6 @@ //go:build integration -package kuadrant +package color_policy import ( "encoding/json" diff --git a/examples/kuadrant/merge_strategies.go b/examples/color_policy/merge_strategies.go similarity index 99% rename from examples/kuadrant/merge_strategies.go rename to examples/color_policy/merge_strategies.go index 2baf9fa..c1ce95b 100644 --- a/examples/kuadrant/merge_strategies.go +++ b/examples/color_policy/merge_strategies.go @@ -1,4 +1,4 @@ -package kuadrant +package color_policy import ( "github.com/samber/lo" diff --git a/examples/kuadrant/.gitignore b/examples/kuadrant/.gitignore new file mode 100644 index 0000000..1346f20 --- /dev/null +++ b/examples/kuadrant/.gitignore @@ -0,0 +1,2 @@ +bin +topology.dot diff --git a/examples/kuadrant/Makefile b/examples/kuadrant/Makefile new file mode 100644 index 0000000..5a6d4b1 --- /dev/null +++ b/examples/kuadrant/Makefile @@ -0,0 +1,69 @@ +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +PROJECT_PATH := $(patsubst %/,%,$(dir $(MKFILE_PATH))) + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-30s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +.PHONY: project-path +project-path: ## Print the project path. + @echo $(PROJECT_PATH) + +##@ Tools + +# go-install-tool will 'go install' any package $2 and install it to $1. +PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) +define go-install-tool +@[ -f $(1) ] || { \ +set -e ;\ +TMP_DIR=$$(mktemp -d) ;\ +cd $$TMP_DIR ;\ +go mod init tmp ;\ +echo "Downloading $(2)" ;\ +GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\ +rm -rf $$TMP_DIR ;\ +} +endef + +CONTROLLER_GEN = $(PROJECT_PATH)/bin/controller-gen +$(CONTROLLER_GEN): + $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.15.0) + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. + +##@ Development + +.PHONY: generate +generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. + $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + +.PHONY: manifests +manifests: controller-gen ## Generate CustomResourceDefinition objects. + $(CONTROLLER_GEN) crd paths="./apis/v1alpha2;./apis/v1beta3" output:crd:artifacts:config=config/crds + +.PHONY: install +install: manifests ## Install CRDs into a cluster. + kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml + kubectl apply -f config/crds + +.PHONY: run +run: generate ## Run the controller. + go run *.go diff --git a/examples/kuadrant/README.md b/examples/kuadrant/README.md new file mode 100644 index 0000000..cd53e72 --- /dev/null +++ b/examples/kuadrant/README.md @@ -0,0 +1,355 @@ +# Kuadrant Controller + +Practical example of using the [Policy Machinery](https://github.com/kuadrant/policy-machinery) to implment a custom controller. + +
+ +The examples defines 4 kinds of policies: +- **DNSPolicy:** can target Gateways and Listeners +- **TLSPolicy:** can target Gateways and Listeners +- **AuthPolicy:** can target Gateways, Listeners, HTTPRoutes, and HTTPRouteRules; support for Defaults & Overrides and 2 merge strategies (`atomic` or `merge`) +- **RateLimitPolicy:** can target Gateways, Listeners, HTTPRoutes, and HTTPRouteRules; support for Defaults & Overrides and 2 merge strategies (`atomic` or `merge`) + +The controller watches for events related to these resources, plus Gateways and HTTPRoutes: It keeps an in-memory Gateway API topology up to date. + +A callback to a reconcile function computes the effective policies for every path between Gateways and Listeners (DNSPolicy and TLSPolicy) and between Gateways and HTTPRouteRules (AuthPolicy and RateLimitPolicy), applying the proper merge strategy specified in the policies. + +## Demo + +### Requirements + +- [kubectl](https://kubernetes.io/docs/reference/kubectl/introduction/) +- [Kind](https://kind.sigs.k8s.io/) + +### Setup + +Create the cluster: + +```sh +kind create cluster +``` + +Install the CRDs: + +```sh +make install +``` + +Run the operator (holds the shell): + +```sh +make run +``` + +### Create the resources + +> **Note:** After each step below, check out the state of the topology (`topology.dot`) and the operator logs for the new effective policies in place. + +1. Create a Gateway: + +```sh +kubectl apply -f -<= 8; h <= 17 } +EOF +``` + +5. Create a HTTPRoute-wide AuthPolicy to enforce API key authentication and affiliation to the 'admin' group: + +```sh +kubectl apply -f - <= 8; h <= 17 } +EOF +``` + +9. Change the `business-hours` AuthPolicy to the 'merge' strategy: + +```sh +kubectl apply -f - <= 8; h <= 17 } + strategy: merge +EOF +``` + +10. Create a HTTPRoute-wide RateLimitPolicy: + +```sh +kubectl apply -f - < 0 && p.Spec.Proper().Limits == nil { + p.Spec.Proper().Limits = make(map[string]Limit) + } + + for ruleId := range rules { + rule := rules[ruleId] + p.Spec.Proper().Limits[ruleId] = rule.(Limit) + } +} + +// +kubebuilder:validation:XValidation:rule="!(has(self.defaults) && has(self.limits))",message="Implicit and explicit defaults are mutually exclusive" +// +kubebuilder:validation:XValidation:rule="!(has(self.defaults) && has(self.overrides))",message="Overrides and explicit defaults are mutually exclusive" +// +kubebuilder:validation:XValidation:rule="!(has(self.overrides) && has(self.limits))",message="Overrides and implicit defaults are mutually exclusive" +type RateLimitPolicySpec struct { + // Reference to the object to which this policy applies. + // +kubebuilder:validation:XValidation:rule="self.group == 'gateway.networking.k8s.io'",message="Invalid targetRef.group. The only supported value is 'gateway.networking.k8s.io'" + // +kubebuilder:validation:XValidation:rule="self.kind == 'HTTPRoute' || self.kind == 'Gateway'",message="Invalid targetRef.kind. The only supported values are 'HTTPRoute' and 'Gateway'" + TargetRef gwapiv1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRef"` + + // Rules to apply as defaults. Can be overridden by more specific policiy rules lower in the hierarchy and by less specific policy overrides. + // Use one of: defaults, overrides, or bare set of policy rules (implicit defaults). + // +optional + Defaults *MergeableRateLimitPolicySpec `json:"defaults,omitempty"` + + // Rules to apply as overrides. Override all policy rules lower in the hierarchy. Can be overriden by less specific policy overrides. + // Use one of: defaults, overrides, or bare set of policy rules (implicit defaults). + // +optional + Overrides *MergeableRateLimitPolicySpec `json:"overrides,omitempty"` + + // Bare set of policy rules (implicit defaults). + // Use one of: defaults, overrides, or bare set of policy rules (implicit defaults). + RateLimitPolicySpecProper `json:""` +} + +// UnmarshalJSON unmarshals the RateLimitPolicySpec from JSON byte array. +// This should not be needed, but runtime.DefaultUnstructuredConverter.FromUnstructured does not work well with embedded structs. +func (s *RateLimitPolicySpec) UnmarshalJSON(j []byte) error { + targetRef := struct { + gwapiv1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRef"` + }{} + if err := json.Unmarshal(j, &targetRef); err != nil { + return err + } + s.TargetRef = targetRef.LocalPolicyTargetReferenceWithSectionName + + defaults := &struct { + *MergeableRateLimitPolicySpec `json:"defaults,omitempty"` + }{} + if err := json.Unmarshal(j, defaults); err != nil { + return err + } + s.Defaults = defaults.MergeableRateLimitPolicySpec + + overrides := &struct { + *MergeableRateLimitPolicySpec `json:"overrides,omitempty"` + }{} + if err := json.Unmarshal(j, overrides); err != nil { + return err + } + s.Overrides = overrides.MergeableRateLimitPolicySpec + + proper := struct { + RateLimitPolicySpecProper `json:""` + }{} + if err := json.Unmarshal(j, &proper); err != nil { + return err + } + s.RateLimitPolicySpecProper = proper.RateLimitPolicySpecProper + + return nil +} + +func (s *RateLimitPolicySpec) Proper() *RateLimitPolicySpecProper { + if s.Defaults != nil { + return &s.Defaults.RateLimitPolicySpecProper + } + + if s.Overrides != nil { + return &s.Overrides.RateLimitPolicySpecProper + } + + return &s.RateLimitPolicySpecProper +} + +type MergeableRateLimitPolicySpec struct { + // Strategy defines the merge strategy to apply when merging this policy with other policies. + // +kubebuilder:validation:Enum=atomic;merge + // +kubebuilder:default=atomic + Strategy string `json:"strategy,omitempty"` + + RateLimitPolicySpecProper `json:""` +} + +// RateLimitPolicySpecProper contains common shared fields for defaults and overrides +type RateLimitPolicySpecProper struct { + // Limits holds the struct of limits indexed by a unique name + // +optional + // +kubebuilder:validation:MaxProperties=14 + Limits map[string]Limit `json:"limits,omitempty"` +} + +// Limit represents a complete rate limit configuration +type Limit struct { + // When holds the list of conditions for the policy to be enforced. + // Called also "soft" conditions as route selectors must also match + // +optional + When []WhenCondition `json:"when,omitempty"` + + // Counters defines additional rate limit counters based on context qualifiers and well known selectors + // TODO Document properly "Well-known selector" https://github.com/Kuadrant/architecture/blob/main/rfcs/0001-rlp-v2.md#well-known-selectors + // +optional + Counters []ContextSelector `json:"counters,omitempty"` + + // Rates holds the list of limit rates + // +optional + Rates []Rate `json:"rates,omitempty"` +} + +// +kubebuilder:validation:Enum:=second;minute;hour;day +type TimeUnit string + +// Rate defines the actual rate limit that will be used when there is a match +type Rate struct { + // Limit defines the max value allowed for a given period of time + Limit int `json:"limit"` + + // Duration defines the time period for which the Limit specified above applies. + Duration int `json:"duration"` + + // Duration defines the time uni + // Possible values are: "second", "minute", "hour", "day" + Unit TimeUnit `json:"unit"` +} + +// 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"` +} + +// 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 + +// +kubebuilder:validation:Enum:=eq;neq;startswith;endswith;incl;excl;matches +type WhenConditionOperator string + +type RateLimitPolicyStatus struct { + // ObservedGeneration reflects the generation of the most recently observed spec. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Represents the observations of a foo's current state. + // Known .status.conditions.type are: "Available" + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"` +} + +func (s *RateLimitPolicyStatus) GetConditions() []metav1.Condition { + return s.Conditions +} + +//+kubebuilder:object:root=true + +// RateLimitPolicyList contains a list of RateLimitPolicy +type RateLimitPolicyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []RateLimitPolicy `json:"items"` +} diff --git a/examples/kuadrant/apis/v1beta3/zz_generated.deepcopy.go b/examples/kuadrant/apis/v1beta3/zz_generated.deepcopy.go new file mode 100644 index 0000000..89c10aa --- /dev/null +++ b/examples/kuadrant/apis/v1beta3/zz_generated.deepcopy.go @@ -0,0 +1,448 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta3 + +import ( + "github.com/kuadrant/authorino/api/v1beta2" + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthPolicy) DeepCopyInto(out *AuthPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthPolicy. +func (in *AuthPolicy) DeepCopy() *AuthPolicy { + if in == nil { + return nil + } + out := new(AuthPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AuthPolicy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthPolicyList) DeepCopyInto(out *AuthPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AuthPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthPolicyList. +func (in *AuthPolicyList) DeepCopy() *AuthPolicyList { + if in == nil { + return nil + } + out := new(AuthPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AuthPolicyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthPolicySpec) DeepCopyInto(out *AuthPolicySpec) { + *out = *in + in.TargetRef.DeepCopyInto(&out.TargetRef) + if in.Defaults != nil { + in, out := &in.Defaults, &out.Defaults + *out = new(MergeableAuthPolicySpec) + (*in).DeepCopyInto(*out) + } + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = new(MergeableAuthPolicySpec) + (*in).DeepCopyInto(*out) + } + in.AuthPolicySpecProper.DeepCopyInto(&out.AuthPolicySpecProper) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthPolicySpec. +func (in *AuthPolicySpec) DeepCopy() *AuthPolicySpec { + if in == nil { + return nil + } + out := new(AuthPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthPolicySpecProper) DeepCopyInto(out *AuthPolicySpecProper) { + *out = *in + if in.NamedPatterns != nil { + in, out := &in.NamedPatterns, &out.NamedPatterns + *out = make(map[string]v1beta2.PatternExpressions, len(*in)) + for key, val := range *in { + var outVal []v1beta2.PatternExpression + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make(v1beta2.PatternExpressions, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1beta2.PatternExpressionOrRef, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AuthScheme != nil { + in, out := &in.AuthScheme, &out.AuthScheme + *out = new(AuthSchemeSpec) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthPolicySpecProper. +func (in *AuthPolicySpecProper) DeepCopy() *AuthPolicySpecProper { + if in == nil { + return nil + } + out := new(AuthPolicySpecProper) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthPolicyStatus) DeepCopyInto(out *AuthPolicyStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthPolicyStatus. +func (in *AuthPolicyStatus) DeepCopy() *AuthPolicyStatus { + if in == nil { + return nil + } + out := new(AuthPolicyStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthSchemeSpec) DeepCopyInto(out *AuthSchemeSpec) { + *out = *in + if in.Authentication != nil { + in, out := &in.Authentication, &out.Authentication + *out = make(map[string]v1beta2.AuthenticationSpec, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make(map[string]v1beta2.MetadataSpec, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Authorization != nil { + in, out := &in.Authorization, &out.Authorization + *out = make(map[string]v1beta2.AuthorizationSpec, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Response != nil { + in, out := &in.Response, &out.Response + *out = new(v1beta2.ResponseSpec) + (*in).DeepCopyInto(*out) + } + if in.Callbacks != nil { + in, out := &in.Callbacks, &out.Callbacks + *out = make(map[string]v1beta2.CallbackSpec, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthSchemeSpec. +func (in *AuthSchemeSpec) DeepCopy() *AuthSchemeSpec { + if in == nil { + return nil + } + out := new(AuthSchemeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Limit) DeepCopyInto(out *Limit) { + *out = *in + if in.When != nil { + in, out := &in.When, &out.When + *out = make([]WhenCondition, len(*in)) + copy(*out, *in) + } + if in.Counters != nil { + in, out := &in.Counters, &out.Counters + *out = make([]ContextSelector, len(*in)) + copy(*out, *in) + } + if in.Rates != nil { + in, out := &in.Rates, &out.Rates + *out = make([]Rate, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Limit. +func (in *Limit) DeepCopy() *Limit { + if in == nil { + return nil + } + out := new(Limit) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MergeableAuthPolicySpec) DeepCopyInto(out *MergeableAuthPolicySpec) { + *out = *in + in.AuthPolicySpecProper.DeepCopyInto(&out.AuthPolicySpecProper) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MergeableAuthPolicySpec. +func (in *MergeableAuthPolicySpec) DeepCopy() *MergeableAuthPolicySpec { + if in == nil { + return nil + } + out := new(MergeableAuthPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MergeableRateLimitPolicySpec) DeepCopyInto(out *MergeableRateLimitPolicySpec) { + *out = *in + in.RateLimitPolicySpecProper.DeepCopyInto(&out.RateLimitPolicySpecProper) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MergeableRateLimitPolicySpec. +func (in *MergeableRateLimitPolicySpec) DeepCopy() *MergeableRateLimitPolicySpec { + if in == nil { + return nil + } + out := new(MergeableRateLimitPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Rate) DeepCopyInto(out *Rate) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rate. +func (in *Rate) DeepCopy() *Rate { + if in == nil { + return nil + } + out := new(Rate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RateLimitPolicy) DeepCopyInto(out *RateLimitPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitPolicy. +func (in *RateLimitPolicy) DeepCopy() *RateLimitPolicy { + if in == nil { + return nil + } + out := new(RateLimitPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RateLimitPolicy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RateLimitPolicyList) DeepCopyInto(out *RateLimitPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]RateLimitPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitPolicyList. +func (in *RateLimitPolicyList) DeepCopy() *RateLimitPolicyList { + if in == nil { + return nil + } + out := new(RateLimitPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RateLimitPolicyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RateLimitPolicySpec) DeepCopyInto(out *RateLimitPolicySpec) { + *out = *in + in.TargetRef.DeepCopyInto(&out.TargetRef) + if in.Defaults != nil { + in, out := &in.Defaults, &out.Defaults + *out = new(MergeableRateLimitPolicySpec) + (*in).DeepCopyInto(*out) + } + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = new(MergeableRateLimitPolicySpec) + (*in).DeepCopyInto(*out) + } + in.RateLimitPolicySpecProper.DeepCopyInto(&out.RateLimitPolicySpecProper) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitPolicySpec. +func (in *RateLimitPolicySpec) DeepCopy() *RateLimitPolicySpec { + if in == nil { + return nil + } + out := new(RateLimitPolicySpec) + in.DeepCopyInto(out) + return out +} + +// 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.Limits != nil { + in, out := &in.Limits, &out.Limits + *out = make(map[string]Limit, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitPolicySpecProper. +func (in *RateLimitPolicySpecProper) DeepCopy() *RateLimitPolicySpecProper { + if in == nil { + return nil + } + out := new(RateLimitPolicySpecProper) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RateLimitPolicyStatus) DeepCopyInto(out *RateLimitPolicyStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitPolicyStatus. +func (in *RateLimitPolicyStatus) DeepCopy() *RateLimitPolicyStatus { + if in == nil { + return nil + } + out := new(RateLimitPolicyStatus) + in.DeepCopyInto(out) + 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 +} diff --git a/examples/kuadrant/config/crds/kuadrant.io_authpolicies.yaml b/examples/kuadrant/config/crds/kuadrant.io_authpolicies.yaml new file mode 100644 index 0000000..02d5bed --- /dev/null +++ b/examples/kuadrant/config/crds/kuadrant.io_authpolicies.yaml @@ -0,0 +1,6812 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + gateway.networking.k8s.io/policy: inherited + name: authpolicies.kuadrant.io +spec: + group: kuadrant.io + names: + kind: AuthPolicy + listKind: AuthPolicyList + plural: authpolicies + singular: authpolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: AuthPolicy Accepted + jsonPath: .status.conditions[?(@.type=="Accepted")].status + name: Accepted + priority: 2 + type: string + - description: AuthPolicy Enforced + jsonPath: .status.conditions[?(@.type=="Enforced")].status + name: Enforced + priority: 2 + type: string + - description: Kind of the object to which the policy aaplies + jsonPath: .spec.targetRef.kind + name: TargetKind + priority: 2 + type: string + - description: Name of the object to which the policy applies + jsonPath: .spec.targetRef.name + name: TargetName + priority: 2 + type: string + - description: 'Name of the section within the object to which the policy applies ' + jsonPath: .spec.targetRef.sectionName + name: TargetSection + priority: 2 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta3 + schema: + openAPIV3Schema: + description: AuthPolicy enables authentication and authorization for service + workloads in a Gateway API network + 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: + properties: + defaults: + description: |- + Rules to apply as defaults. Can be overridden by more specific policiy rules lower in the hierarchy and by less specific policy overrides. + Use one of: defaults, overrides, or bare set of policy rules (implicit defaults). + properties: + patterns: + additionalProperties: + items: + properties: + 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 + 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 + type: object + type: array + description: Named sets of patterns that can be referred in `when` + conditions and in pattern-matching authorization policy rules. + type: object + rules: + description: |- + The auth rules of the policy. + See Authorino's AuthConfig CRD for more details. + properties: + authentication: + additionalProperties: + properties: + anonymous: + description: Anonymous access. + type: object + apiKey: + description: Authentication based on API keys stored + in Kubernetes secrets. + properties: + allNamespaces: + default: false + description: |- + Whether Authorino should look for API key secrets in all namespaces or only in the same namespace as the AuthConfig. + Enabling this option in namespaced Authorino instances has no effect. + type: boolean + selector: + description: Label selector used by Authorino to + match secrets from the cluster storing valid credentials + to authenticate to this service + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - selector + type: object + cache: + description: |- + Caching options for the resolved object returned when applying this config. + Omit it to avoid caching objects for this config. + properties: + key: + description: |- + Key used to store the entry in the cache. + The resolved key must be unique within the scope of this particular config. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + ttl: + default: 60 + description: Duration (in seconds) of the external + data in the cache before pulled again from the + source. + type: integer + required: + - key + type: object + credentials: + description: |- + Defines where credentials are required to be passed in the request for authentication based on this config. + If omitted, it defaults to credentials passed in the HTTP Authorization header and the "Bearer" prefix prepended to the secret credential value. + properties: + authorizationHeader: + properties: + prefix: + type: string + type: object + cookie: + properties: + name: + type: string + required: + - name + type: object + customHeader: + properties: + name: + type: string + required: + - name + type: object + queryString: + properties: + name: + type: string + required: + - name + type: object + type: object + defaults: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: |- + Set default property values (claims) for the resolved identity object, that are set before appending the object to + the authorization JSON. If the property is already present in the resolved identity object, the default value is ignored. + It requires the resolved identity object to always be a JSON object. + Do not use this option with identity objects of other JSON types (array, string, etc). + type: object + jwt: + description: Authentication based on JWT tokens. + properties: + issuerUrl: + description: |- + URL of the issuer of the JWT. + If `jwksUrl` is omitted, Authorino will append the path to the OpenID Connect Well-Known Discovery endpoint + (i.e. "/.well-known/openid-configuration") to this URL, to discover the OIDC configuration where to obtain + the "jkws_uri" claim from. + The value must coincide with the value of the "iss" (issuer) claim of the discovered OpenID Connect configuration. + type: string + ttl: + description: |- + Decides how long to wait before refreshing the JWKS (in seconds). + If omitted, Authorino will never refresh the JWKS. + type: integer + type: object + kubernetesTokenReview: + description: Authentication by Kubernetes token review. + properties: + audiences: + description: |- + The list of audiences (scopes) that must be claimed in a Kubernetes authentication token supplied in the request, and reviewed by Authorino. + If omitted, Authorino will review tokens expecting the host name of the requested protected service amongst the audiences. + items: + type: string + type: array + type: object + metrics: + default: false + description: Whether this config should generate individual + observability metrics + type: boolean + oauth2Introspection: + description: Authentication by OAuth2 token introspection. + properties: + credentialsRef: + description: Reference to a Kubernetes secret in + the same namespace, that stores client credentials + to the OAuth2 server. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + type: object + x-kubernetes-map-type: atomic + endpoint: + description: The full URL of the token introspection + endpoint. + type: string + tokenTypeHint: + description: |- + The token type hint for the token introspection. + If omitted, it defaults to "access_token". + type: string + required: + - credentialsRef + - endpoint + type: object + overrides: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: |- + Overrides the resolved identity object by setting the additional properties (claims) specified in this config, + before appending the object to the authorization JSON. + It requires the resolved identity object to always be a JSON object. + Do not use this option with identity objects of other JSON types (array, string, etc). + type: object + plain: + description: |- + Identity object extracted from the context. + Use this method when authentication is performed beforehand by a proxy and the resulting object passed to Authorino as JSON in the auth request. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + required: + - selector + type: object + priority: + default: 0 + description: |- + Priority group of the config. + All configs in the same priority group are evaluated concurrently; consecutive priority groups are evaluated sequentially. + type: integer + when: + description: |- + Conditions for Authorino to enforce this config. + If omitted, the config will be enforced for all requests. + If present, all conditions must match for the config to be enforced; otherwise, the config will be skipped. + items: + 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 + 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 + type: object + type: array + x509: + description: |- + Authentication based on client X.509 certificates. + The certificates presented by the clients must be signed by a trusted CA whose certificates are stored in Kubernetes secrets. + properties: + allNamespaces: + default: false + description: |- + Whether Authorino should look for TLS secrets in all namespaces or only in the same namespace as the AuthConfig. + Enabling this option in namespaced Authorino instances has no effect. + type: boolean + selector: + description: |- + Label selector used by Authorino to match secrets from the cluster storing trusted CA certificates to validate + clients trying to authenticate to this service + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + required: + - selector + type: object + type: object + description: |- + Authentication configs. + At least one config MUST evaluate to a valid identity object for the auth request to be successful. + maxProperties: 10 + type: object + authorization: + additionalProperties: + properties: + cache: + description: |- + Caching options for the resolved object returned when applying this config. + Omit it to avoid caching objects for this config. + properties: + key: + description: |- + Key used to store the entry in the cache. + The resolved key must be unique within the scope of this particular config. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + ttl: + default: 60 + description: Duration (in seconds) of the external + data in the cache before pulled again from the + source. + type: integer + required: + - key + type: object + kubernetesSubjectAccessReview: + description: Authorization by Kubernetes SubjectAccessReview + properties: + groups: + description: Groups the user must be a member of + or, if `user` is omitted, the groups to check + for authorization in the Kubernetes RBAC. + items: + type: string + type: array + resourceAttributes: + description: |- + Use resourceAttributes to check permissions on Kubernetes resources. + If omitted, it performs a non-resource SubjectAccessReview, with verb and path inferred from the request. + properties: + group: + description: |- + API group of the resource. + Use '*' for all API groups. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + name: + description: |- + Resource name + Omit it to check for authorization on all resources of the specified kind. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + namespace: + description: Namespace where the user must have + permissions on the resource. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + resource: + description: |- + Resource kind + Use '*' for all resource kinds. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + subresource: + description: Subresource kind + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + verb: + description: |- + Verb to check for authorization on the resource. + Use '*' for all verbs. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + user: + description: |- + User to check for authorization in the Kubernetes RBAC. + Omit it to check for group authorization only. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + metrics: + default: false + description: Whether this config should generate individual + observability metrics + type: boolean + opa: + description: Open Policy Agent (OPA) Rego policy. + properties: + allValues: + default: false + description: |- + Returns the value of all Rego rules in the virtual document. Values can be read in subsequent evaluators/phases of the Auth Pipeline. + Otherwise, only the default `allow` rule will be exposed. + Returning all Rego rules can affect performance of OPA policies during reconciliation (policy precompile) and at runtime. + type: boolean + externalPolicy: + description: |- + Settings for fetching the OPA policy from an external registry. + Use it alternatively to 'rego'. + For the configurations of the HTTP request, the following options are not implemented: 'method', 'body', 'bodyParameters', + 'contentType', 'headers', 'oauth2'. Use it only with: 'url', 'sharedSecret', 'credentials'. + properties: + body: + description: |- + Raw body of the HTTP request. + Supersedes 'bodyParameters'; use either one or the other. + Use it with method=POST; for GET requests, set parameters as query string in the 'endpoint' (placeholders can be used). + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + bodyParameters: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: |- + Custom parameters to encode in the body of the HTTP request. + Superseded by 'body'; use either one or the other. + Use it with method=POST; for GET requests, set parameters as query string in the 'endpoint' (placeholders can be used). + type: object + contentType: + default: application/x-www-form-urlencoded + description: |- + Content-Type of the request body. Shapes how 'bodyParameters' are encoded. + Use it with method=POST; for GET requests, Content-Type is automatically set to 'text/plain'. + enum: + - application/x-www-form-urlencoded + - application/json + type: string + credentials: + description: |- + Defines where client credentials will be passed in the request to the service. + If omitted, it defaults to client credentials passed in the HTTP Authorization header and the "Bearer" prefix expected prepended to the secret value. + properties: + authorizationHeader: + properties: + prefix: + type: string + type: object + cookie: + properties: + name: + type: string + required: + - name + type: object + customHeader: + properties: + name: + type: string + required: + - name + type: object + queryString: + properties: + name: + type: string + required: + - name + type: object + type: object + headers: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: Custom headers in the HTTP request. + type: object + method: + default: GET + description: |- + HTTP verb used in the request to the service. Accepted values: GET (default), POST. + When the request method is POST, the authorization JSON is passed in the body of the request. + enum: + - GET + - POST + - PUT + - PATCH + - DELETE + - HEAD + - OPTIONS + - CONNECT + - TRACE + type: string + oauth2: + description: Authentication with the HTTP service + by OAuth2 Client Credentials grant. + properties: + cache: + default: true + description: |- + Caches and reuses the token until expired. + Set it to false to force fetch the token at every authorization request regardless of expiration. + type: boolean + clientId: + description: OAuth2 Client ID. + type: string + clientSecretRef: + description: Reference to a Kuberentes Secret + key that stores that OAuth2 Client Secret. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: The name of the secret + in the Authorino's namespace to select + from. + type: string + required: + - key + - name + type: object + extraParams: + additionalProperties: + type: string + description: Optional extra parameters for + the requests to the token URL. + type: object + scopes: + description: Optional scopes for the client + credentials grant, if supported by he + OAuth2 server. + items: + type: string + type: array + tokenUrl: + description: Token endpoint URL of the OAuth2 + resource server. + type: string + required: + - clientId + - clientSecretRef + - tokenUrl + type: object + sharedSecretRef: + description: |- + Reference to a Secret key whose value will be passed by Authorino in the request. + The HTTP service can use the shared secret to authenticate the origin of the request. + Ignored if used together with oauth2. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: The name of the secret in the + Authorino's namespace to select from. + type: string + required: + - key + - name + type: object + ttl: + description: Duration (in seconds) of the external + data in the cache before pulled again from + the source. + type: integer + url: + description: |- + Endpoint URL of the HTTP service. + The value can include variable placeholders in the format "{selector}", where "selector" is any pattern supported + by https://pkg.go.dev/github.com/tidwall/gjson and selects value from the authorization JSON. + E.g. https://ext-auth-server.io/metadata?p={request.path} + type: string + required: + - url + type: object + rego: + description: |- + Authorization policy as a Rego language document. + The Rego document must include the "allow" condition, set by Authorino to "false" by default (i.e. requests are unauthorized unless changed). + The Rego document must NOT include the "package" declaration in line 1. + type: string + type: object + patternMatching: + description: Pattern-matching authorization rules. + properties: + patterns: + items: + 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 + 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 + type: object + type: array + required: + - patterns + type: object + priority: + default: 0 + description: |- + Priority group of the config. + All configs in the same priority group are evaluated concurrently; consecutive priority groups are evaluated sequentially. + type: integer + spicedb: + description: Authorization decision delegated to external + Authzed/SpiceDB server. + properties: + endpoint: + description: Hostname and port number to the GRPC + interface of the SpiceDB server (e.g. spicedb:50051). + type: string + insecure: + description: Insecure HTTP connection (i.e. disables + TLS verification) + type: boolean + permission: + description: The name of the permission (or relation) + on which to execute the check. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + resource: + description: The resource on which to check the + permission or relation. + properties: + kind: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + name: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + sharedSecretRef: + description: Reference to a Secret key whose value + will be used by Authorino to authenticate with + the Authzed service. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: The name of the secret in the Authorino's + namespace to select from. + type: string + required: + - key + - name + type: object + subject: + description: The subject that will be checked for + the permission or relation. + properties: + kind: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + name: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + required: + - endpoint + type: object + when: + description: |- + Conditions for Authorino to enforce this config. + If omitted, the config will be enforced for all requests. + If present, all conditions must match for the config to be enforced; otherwise, the config will be skipped. + items: + 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 + 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 + type: object + type: array + type: object + description: |- + Authorization policies. + All policies MUST evaluate to "allowed = true" for the auth request be successful. + maxProperties: 10 + type: object + callbacks: + additionalProperties: + properties: + cache: + description: |- + Caching options for the resolved object returned when applying this config. + Omit it to avoid caching objects for this config. + properties: + key: + description: |- + Key used to store the entry in the cache. + The resolved key must be unique within the scope of this particular config. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + ttl: + default: 60 + description: Duration (in seconds) of the external + data in the cache before pulled again from the + source. + type: integer + required: + - key + type: object + http: + description: Settings of the external HTTP request + properties: + body: + description: |- + Raw body of the HTTP request. + Supersedes 'bodyParameters'; use either one or the other. + Use it with method=POST; for GET requests, set parameters as query string in the 'endpoint' (placeholders can be used). + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + bodyParameters: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: |- + Custom parameters to encode in the body of the HTTP request. + Superseded by 'body'; use either one or the other. + Use it with method=POST; for GET requests, set parameters as query string in the 'endpoint' (placeholders can be used). + type: object + contentType: + default: application/x-www-form-urlencoded + description: |- + Content-Type of the request body. Shapes how 'bodyParameters' are encoded. + Use it with method=POST; for GET requests, Content-Type is automatically set to 'text/plain'. + enum: + - application/x-www-form-urlencoded + - application/json + type: string + credentials: + description: |- + Defines where client credentials will be passed in the request to the service. + If omitted, it defaults to client credentials passed in the HTTP Authorization header and the "Bearer" prefix expected prepended to the secret value. + properties: + authorizationHeader: + properties: + prefix: + type: string + type: object + cookie: + properties: + name: + type: string + required: + - name + type: object + customHeader: + properties: + name: + type: string + required: + - name + type: object + queryString: + properties: + name: + type: string + required: + - name + type: object + type: object + headers: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: Custom headers in the HTTP request. + type: object + method: + default: GET + description: |- + HTTP verb used in the request to the service. Accepted values: GET (default), POST. + When the request method is POST, the authorization JSON is passed in the body of the request. + enum: + - GET + - POST + - PUT + - PATCH + - DELETE + - HEAD + - OPTIONS + - CONNECT + - TRACE + type: string + oauth2: + description: Authentication with the HTTP service + by OAuth2 Client Credentials grant. + properties: + cache: + default: true + description: |- + Caches and reuses the token until expired. + Set it to false to force fetch the token at every authorization request regardless of expiration. + type: boolean + clientId: + description: OAuth2 Client ID. + type: string + clientSecretRef: + description: Reference to a Kuberentes Secret + key that stores that OAuth2 Client Secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: The name of the secret in the + Authorino's namespace to select from. + type: string + required: + - key + - name + type: object + extraParams: + additionalProperties: + type: string + description: Optional extra parameters for the + requests to the token URL. + type: object + scopes: + description: Optional scopes for the client + credentials grant, if supported by he OAuth2 + server. + items: + type: string + type: array + tokenUrl: + description: Token endpoint URL of the OAuth2 + resource server. + type: string + required: + - clientId + - clientSecretRef + - tokenUrl + type: object + sharedSecretRef: + description: |- + Reference to a Secret key whose value will be passed by Authorino in the request. + The HTTP service can use the shared secret to authenticate the origin of the request. + Ignored if used together with oauth2. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: The name of the secret in the Authorino's + namespace to select from. + type: string + required: + - key + - name + type: object + url: + description: |- + Endpoint URL of the HTTP service. + The value can include variable placeholders in the format "{selector}", where "selector" is any pattern supported + by https://pkg.go.dev/github.com/tidwall/gjson and selects value from the authorization JSON. + E.g. https://ext-auth-server.io/metadata?p={request.path} + type: string + required: + - url + type: object + metrics: + default: false + description: Whether this config should generate individual + observability metrics + type: boolean + priority: + default: 0 + description: |- + Priority group of the config. + All configs in the same priority group are evaluated concurrently; consecutive priority groups are evaluated sequentially. + type: integer + when: + description: |- + Conditions for Authorino to enforce this config. + If omitted, the config will be enforced for all requests. + If present, all conditions must match for the config to be enforced; otherwise, the config will be skipped. + items: + 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 + 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 + type: object + type: array + required: + - http + type: object + description: |- + Callback functions. + Authorino sends callbacks at the end of the auth pipeline to the endpoints specified in this config. + maxProperties: 10 + type: object + metadata: + additionalProperties: + properties: + cache: + description: |- + Caching options for the resolved object returned when applying this config. + Omit it to avoid caching objects for this config. + properties: + key: + description: |- + Key used to store the entry in the cache. + The resolved key must be unique within the scope of this particular config. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + ttl: + default: 60 + description: Duration (in seconds) of the external + data in the cache before pulled again from the + source. + type: integer + required: + - key + type: object + http: + description: External source of auth metadata via HTTP + request + properties: + body: + description: |- + Raw body of the HTTP request. + Supersedes 'bodyParameters'; use either one or the other. + Use it with method=POST; for GET requests, set parameters as query string in the 'endpoint' (placeholders can be used). + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + bodyParameters: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: |- + Custom parameters to encode in the body of the HTTP request. + Superseded by 'body'; use either one or the other. + Use it with method=POST; for GET requests, set parameters as query string in the 'endpoint' (placeholders can be used). + type: object + contentType: + default: application/x-www-form-urlencoded + description: |- + Content-Type of the request body. Shapes how 'bodyParameters' are encoded. + Use it with method=POST; for GET requests, Content-Type is automatically set to 'text/plain'. + enum: + - application/x-www-form-urlencoded + - application/json + type: string + credentials: + description: |- + Defines where client credentials will be passed in the request to the service. + If omitted, it defaults to client credentials passed in the HTTP Authorization header and the "Bearer" prefix expected prepended to the secret value. + properties: + authorizationHeader: + properties: + prefix: + type: string + type: object + cookie: + properties: + name: + type: string + required: + - name + type: object + customHeader: + properties: + name: + type: string + required: + - name + type: object + queryString: + properties: + name: + type: string + required: + - name + type: object + type: object + headers: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: Custom headers in the HTTP request. + type: object + method: + default: GET + description: |- + HTTP verb used in the request to the service. Accepted values: GET (default), POST. + When the request method is POST, the authorization JSON is passed in the body of the request. + enum: + - GET + - POST + - PUT + - PATCH + - DELETE + - HEAD + - OPTIONS + - CONNECT + - TRACE + type: string + oauth2: + description: Authentication with the HTTP service + by OAuth2 Client Credentials grant. + properties: + cache: + default: true + description: |- + Caches and reuses the token until expired. + Set it to false to force fetch the token at every authorization request regardless of expiration. + type: boolean + clientId: + description: OAuth2 Client ID. + type: string + clientSecretRef: + description: Reference to a Kuberentes Secret + key that stores that OAuth2 Client Secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: The name of the secret in the + Authorino's namespace to select from. + type: string + required: + - key + - name + type: object + extraParams: + additionalProperties: + type: string + description: Optional extra parameters for the + requests to the token URL. + type: object + scopes: + description: Optional scopes for the client + credentials grant, if supported by he OAuth2 + server. + items: + type: string + type: array + tokenUrl: + description: Token endpoint URL of the OAuth2 + resource server. + type: string + required: + - clientId + - clientSecretRef + - tokenUrl + type: object + sharedSecretRef: + description: |- + Reference to a Secret key whose value will be passed by Authorino in the request. + The HTTP service can use the shared secret to authenticate the origin of the request. + Ignored if used together with oauth2. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: The name of the secret in the Authorino's + namespace to select from. + type: string + required: + - key + - name + type: object + url: + description: |- + Endpoint URL of the HTTP service. + The value can include variable placeholders in the format "{selector}", where "selector" is any pattern supported + by https://pkg.go.dev/github.com/tidwall/gjson and selects value from the authorization JSON. + E.g. https://ext-auth-server.io/metadata?p={request.path} + type: string + required: + - url + type: object + metrics: + default: false + description: Whether this config should generate individual + observability metrics + type: boolean + priority: + default: 0 + description: |- + Priority group of the config. + All configs in the same priority group are evaluated concurrently; consecutive priority groups are evaluated sequentially. + type: integer + uma: + description: User-Managed Access (UMA) source of resource + data. + properties: + credentialsRef: + description: Reference to a Kubernetes secret in + the same namespace, that stores client credentials + to the resource registration API of the UMA server. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + type: object + x-kubernetes-map-type: atomic + endpoint: + description: |- + The endpoint of the UMA server. + The value must coincide with the "issuer" claim of the UMA config discovered from the well-known uma configuration endpoint. + type: string + required: + - credentialsRef + - endpoint + type: object + userInfo: + description: OpendID Connect UserInfo linked to an OIDC + authentication config specified in this same AuthConfig. + properties: + identitySource: + description: The name of an OIDC-enabled JWT authentication + config whose OpenID Connect configuration discovered + includes the OIDC "userinfo_endpoint" claim. + type: string + required: + - identitySource + type: object + when: + description: |- + Conditions for Authorino to enforce this config. + If omitted, the config will be enforced for all requests. + If present, all conditions must match for the config to be enforced; otherwise, the config will be skipped. + items: + 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 + 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 + type: object + type: array + type: object + description: |- + Metadata sources. + Authorino fetches auth metadata as JSON from sources specified in this config. + maxProperties: 10 + type: object + response: + description: |- + Response items. + Authorino builds custom responses to the client of the auth request. + properties: + success: + description: |- + Response items to be included in the auth response when the request is authenticated and authorized. + For integration of Authorino via proxy, the proxy must use these settings to propagate dynamic metadata and/or inject data in the request. + properties: + dynamicMetadata: + additionalProperties: + description: Settings of the success custom response + item. + properties: + cache: + description: |- + Caching options for the resolved object returned when applying this config. + Omit it to avoid caching objects for this config. + properties: + key: + description: |- + Key used to store the entry in the cache. + The resolved key must be unique within the scope of this particular config. + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + ttl: + default: 60 + description: Duration (in seconds) of the + external data in the cache before pulled + again from the source. + type: integer + required: + - key + type: object + json: + description: |- + JSON object + Specify it as the list of properties of the object, whose values can combine static values and values selected from the authorization JSON. + properties: + properties: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + required: + - properties + type: object + key: + description: |- + The key used to add the custom response item (name of the HTTP header or root property of the Dynamic Metadata object). + If omitted, it will be set to the name of the response config. + type: string + metrics: + default: false + description: Whether this config should generate + individual observability metrics + type: boolean + plain: + description: Plain text content + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + priority: + default: 0 + description: |- + Priority group of the config. + All configs in the same priority group are evaluated concurrently; consecutive priority groups are evaluated sequentially. + type: integer + when: + description: |- + Conditions for Authorino to enforce this config. + If omitted, the config will be enforced for all requests. + If present, all conditions must match for the config to be enforced; otherwise, the config will be skipped. + items: + 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 + 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 + type: object + type: array + wristband: + description: Authorino Festival Wristband token + properties: + customClaims: + additionalProperties: + properties: + selector: + description: |- + Simple path selector to fetch content from the authorization JSON (e.g. 'request.method') or a string template with variables that resolve to patterns (e.g. "Hello, {auth.identity.name}!"). + Any pattern supported by https://pkg.go.dev/github.com/tidwall/gjson can be used. + The following Authorino custom modifiers are supported: @extract:{sep:" ",pos:0}, @replace{old:"",new:""}, @case:upper|lower, @base64:encode|decode and @strip. + type: string + value: + description: Static value + x-kubernetes-preserve-unknown-fields: true + type: object + description: Any claims to be added to the + wristband token apart from the standard + JWT claims (iss, iat, exp) added by default. + type: object + issuer: + description: 'The endpoint to the Authorino + service that issues the wristband (format: + ://:/, where + = /://:/, where + = /://:/, where + = /://:/, where + = /://:/, where + = /://:/, where + = / The path portion of the URL + maxLength: 253 + minLength: 1 + type: string + type: array + rates: + description: Rates holds the list of limit rates + items: + description: Rate defines the actual rate limit that will + be used when there is a match + properties: + duration: + description: Duration defines the time period for + which the Limit specified above applies. + type: integer + limit: + description: Limit defines the max value allowed for + a given period of time + type: integer + unit: + description: |- + Duration defines the time uni + Possible values are: "second", "minute", "hour", "day" + enum: + - second + - minute + - hour + - day + type: string + required: + - duration + - limit + - unit + type: object + type: array + when: + description: |- + When holds the list of conditions for the policy to be enforced. + Called also "soft" conditions as route selectors must also match + items: + description: |- + 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 + properties: + operator: + description: |- + The binary operator to be applied to the content fetched from the selector + Possible values are: "eq" (equal to), "neq" (not equal to) + enum: + - eq + - neq + - startswith + - endswith + - incl + - excl + - matches + type: string + selector: + description: |- + 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 + maxLength: 253 + minLength: 1 + type: string + value: + description: The value of reference for the comparison. + type: string + required: + - operator + - selector + - value + type: object + type: array + type: object + description: Limits holds the struct of limits indexed by a unique + name + maxProperties: 14 + type: object + strategy: + default: atomic + description: Strategy defines the merge strategy to apply when + merging this policy with other policies. + enum: + - atomic + - merge + type: string + type: object + limits: + additionalProperties: + description: Limit represents a complete rate limit configuration + properties: + counters: + description: |- + Counters defines additional rate limit counters based on context qualifiers and well known selectors + TODO Document properly "Well-known selector" https://github.com/Kuadrant/architecture/blob/main/rfcs/0001-rlp-v2.md#well-known-selectors + items: + description: |- + 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 + maxLength: 253 + minLength: 1 + type: string + type: array + rates: + description: Rates holds the list of limit rates + items: + description: Rate defines the actual rate limit that will + be used when there is a match + properties: + duration: + description: Duration defines the time period for which + the Limit specified above applies. + type: integer + limit: + description: Limit defines the max value allowed for a + given period of time + type: integer + unit: + description: |- + Duration defines the time uni + Possible values are: "second", "minute", "hour", "day" + enum: + - second + - minute + - hour + - day + type: string + required: + - duration + - limit + - unit + type: object + type: array + when: + description: |- + When holds the list of conditions for the policy to be enforced. + Called also "soft" conditions as route selectors must also match + items: + description: |- + 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 + properties: + operator: + description: |- + The binary operator to be applied to the content fetched from the selector + Possible values are: "eq" (equal to), "neq" (not equal to) + enum: + - eq + - neq + - startswith + - endswith + - incl + - excl + - matches + type: string + selector: + description: |- + 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 + maxLength: 253 + minLength: 1 + type: string + value: + description: The value of reference for the comparison. + type: string + required: + - operator + - selector + - value + type: object + type: array + type: object + description: Limits holds the struct of limits indexed by a unique + name + maxProperties: 14 + type: object + overrides: + description: |- + Rules to apply as overrides. Override all policy rules lower in the hierarchy. Can be overriden by less specific policy overrides. + Use one of: defaults, overrides, or bare set of policy rules (implicit defaults). + properties: + limits: + additionalProperties: + description: Limit represents a complete rate limit configuration + properties: + counters: + description: |- + Counters defines additional rate limit counters based on context qualifiers and well known selectors + TODO Document properly "Well-known selector" https://github.com/Kuadrant/architecture/blob/main/rfcs/0001-rlp-v2.md#well-known-selectors + items: + description: |- + 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 + maxLength: 253 + minLength: 1 + type: string + type: array + rates: + description: Rates holds the list of limit rates + items: + description: Rate defines the actual rate limit that will + be used when there is a match + properties: + duration: + description: Duration defines the time period for + which the Limit specified above applies. + type: integer + limit: + description: Limit defines the max value allowed for + a given period of time + type: integer + unit: + description: |- + Duration defines the time uni + Possible values are: "second", "minute", "hour", "day" + enum: + - second + - minute + - hour + - day + type: string + required: + - duration + - limit + - unit + type: object + type: array + when: + description: |- + When holds the list of conditions for the policy to be enforced. + Called also "soft" conditions as route selectors must also match + items: + description: |- + 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 + properties: + operator: + description: |- + The binary operator to be applied to the content fetched from the selector + Possible values are: "eq" (equal to), "neq" (not equal to) + enum: + - eq + - neq + - startswith + - endswith + - incl + - excl + - matches + type: string + selector: + description: |- + 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 + maxLength: 253 + minLength: 1 + type: string + value: + description: The value of reference for the comparison. + type: string + required: + - operator + - selector + - value + type: object + type: array + type: object + description: Limits holds the struct of limits indexed by a unique + name + maxProperties: 14 + type: object + strategy: + default: atomic + description: Strategy defines the merge strategy to apply when + merging this policy with other policies. + enum: + - atomic + - merge + type: string + type: object + targetRef: + description: Reference to the object to which this policy applies. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + sectionName: + description: |- + SectionName is the name of a section within the target resource. When + unspecified, this targetRef targets the entire resource. In the following + resources, SectionName is interpreted as the following: + + + * Gateway: Listener name + * HTTPRoute: HTTPRouteRule name + * Service: Port name + + + If a SectionName is specified, but does not exist on the targeted object, + the Policy must fail to attach, and the policy implementation should record + a `ResolvedRefs` or similar Condition in the Policy's status. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - group + - kind + - name + type: object + x-kubernetes-validations: + - message: Invalid targetRef.group. The only supported value is 'gateway.networking.k8s.io' + rule: self.group == 'gateway.networking.k8s.io' + - message: Invalid targetRef.kind. The only supported values are 'HTTPRoute' + and 'Gateway' + rule: self.kind == 'HTTPRoute' || self.kind == 'Gateway' + required: + - targetRef + type: object + x-kubernetes-validations: + - message: Implicit and explicit defaults are mutually exclusive + rule: '!(has(self.defaults) && has(self.limits))' + - message: Overrides and explicit defaults are mutually exclusive + rule: '!(has(self.defaults) && has(self.overrides))' + - message: Overrides and implicit defaults are mutually exclusive + rule: '!(has(self.overrides) && has(self.limits))' + status: + properties: + conditions: + description: |- + Represents the observations of a foo's current state. + Known .status.conditions.type are: "Available" + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + description: ObservedGeneration reflects the generation of the most + recently observed spec. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/examples/kuadrant/config/crds/kuadrant.io_tlspolicies.yaml b/examples/kuadrant/config/crds/kuadrant.io_tlspolicies.yaml new file mode 100644 index 0000000..d5b56a3 --- /dev/null +++ b/examples/kuadrant/config/crds/kuadrant.io_tlspolicies.yaml @@ -0,0 +1,394 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + gateway.networking.k8s.io/policy: inherited + name: tlspolicies.kuadrant.io +spec: + group: kuadrant.io + names: + kind: TLSPolicy + listKind: TLSPolicyList + plural: tlspolicies + singular: tlspolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: TLSPolicy Accepted + jsonPath: .status.conditions[?(@.type=="Accepted")].status + name: Accepted + priority: 2 + type: string + - description: TLSPolicy Enforced + jsonPath: .status.conditions[?(@.type=="Enforced")].status + name: Enforced + priority: 2 + type: string + - description: Kind of the object to which the policy aaplies + jsonPath: .spec.targetRef.kind + name: TargetKind + priority: 2 + type: string + - description: Name of the object to which the policy applies + jsonPath: .spec.targetRef.name + name: TargetName + priority: 2 + type: string + - description: 'Name of the section within the object to which the policy applies ' + jsonPath: .spec.targetRef.sectionName + name: TargetSection + priority: 2 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: TLSPolicy enables automatic TLS configuration for Gateway API + objects. + 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: TLSPolicySpec defines the desired state of TLSPolicy + properties: + commonName: + description: |- + CommonName is a common name to be used on the Certificate. + The CommonName should have a length of 64 characters or fewer to avoid + generating invalid CSRs. + This value is ignored by TLS clients when any subject alt name is set. + This is x509 behaviour: https://tools.ietf.org/html/rfc6125#section-6.4.4 + type: string + duration: + description: |- + The requested 'duration' (i.e. lifetime) of the Certificate. This option + may be ignored/overridden by some issuer types. If unset this defaults to + 90 days. Certificate will be renewed either 2/3 through its duration or + `renewBefore` period before its expiry, whichever is later. Minimum + accepted duration is 1 hour. Value must be in units accepted by Go + time.ParseDuration https://golang.org/pkg/time/#ParseDuration + type: string + issuerRef: + description: |- + IssuerRef is a reference to the issuer for this certificate. + If the `kind` field is not set, or set to `Issuer`, an Issuer resource + with the given name in the same namespace as the Certificate will be used. + If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the + provided name will be used. + The `name` field in this stanza is required at all times. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + privateKey: + description: Options to control private keys used for the Certificate. + properties: + algorithm: + description: |- + Algorithm is the private key algorithm of the corresponding private key + for this certificate. + + + If provided, allowed values are either `RSA`, `ECDSA` or `Ed25519`. + If `algorithm` is specified and `size` is not provided, + key size of 2048 will be used for `RSA` key algorithm and + key size of 256 will be used for `ECDSA` key algorithm. + key size is ignored when using the `Ed25519` key algorithm. + enum: + - RSA + - ECDSA + - Ed25519 + type: string + encoding: + description: |- + The private key cryptography standards (PKCS) encoding for this + certificate's private key to be encoded in. + + + If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 + and PKCS#8, respectively. + Defaults to `PKCS1` if not specified. + enum: + - PKCS1 + - PKCS8 + type: string + rotationPolicy: + description: |- + RotationPolicy controls how private keys should be regenerated when a + re-issuance is being processed. + + + If set to `Never`, a private key will only be generated if one does not + already exist in the target `spec.secretName`. If one does exists but it + does not have the correct algorithm or size, a warning will be raised + to await user intervention. + If set to `Always`, a private key matching the specified requirements + will be generated whenever a re-issuance occurs. + Default is `Never` for backward compatibility. + enum: + - Never + - Always + type: string + size: + description: |- + Size is the key bit size of the corresponding private key for this certificate. + + + If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, + and will default to `2048` if not specified. + If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, + and will default to `256` if not specified. + If `algorithm` is set to `Ed25519`, Size is ignored. + No other values are allowed. + type: integer + type: object + renewBefore: + description: |- + How long before the currently issued certificate's expiry + cert-manager should renew the certificate. The default is 2/3 of the + issued certificate's duration. Minimum accepted value is 5 minutes. + Value must be in units accepted by Go time.ParseDuration + https://golang.org/pkg/time/#ParseDuration + type: string + revisionHistoryLimit: + description: |- + RevisionHistoryLimit is the maximum number of CertificateRequest revisions + that are maintained in the Certificate's history. Each revision represents + a single `CertificateRequest` created by this Certificate, either when it + was created, renewed, or Spec was changed. Revisions will be removed by + oldest first if the number of revisions exceeds this number. If set, + revisionHistoryLimit must be a value of `1` or greater. If unset (`nil`), + revisions will not be garbage collected. Default value is `nil`. + format: int32 + type: integer + targetRef: + description: Reference to the object to which this policy applies. + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + sectionName: + description: |- + SectionName is the name of a section within the target resource. When + unspecified, this targetRef targets the entire resource. In the following + resources, SectionName is interpreted as the following: + + + * Gateway: Listener name + * HTTPRoute: HTTPRouteRule name + * Service: Port name + + + If a SectionName is specified, but does not exist on the targeted object, + the Policy must fail to attach, and the policy implementation should record + a `ResolvedRefs` or similar Condition in the Policy's status. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - group + - kind + - name + type: object + x-kubernetes-validations: + - message: Invalid targetRef.group. The only supported value is 'gateway.networking.k8s.io' + rule: self.group == 'gateway.networking.k8s.io' + - message: Invalid targetRef.kind. The only supported values are 'Gateway' + rule: self.kind == 'Gateway' + usages: + description: |- + Usages is the set of x509 usages that are requested for the certificate. + Defaults to `digital signature` and `key encipherment` if not specified. + items: + description: |- + KeyUsage specifies valid usage contexts for keys. + See: + https://tools.ietf.org/html/rfc5280#section-4.2.1.3 + https://tools.ietf.org/html/rfc5280#section-4.2.1.12 + + + Valid KeyUsage values are as follows: + "signing", + "digital signature", + "content commitment", + "key encipherment", + "key agreement", + "data encipherment", + "cert sign", + "crl sign", + "encipher only", + "decipher only", + "any", + "server auth", + "client auth", + "code signing", + "email protection", + "s/mime", + "ipsec end system", + "ipsec tunnel", + "ipsec user", + "timestamping", + "ocsp signing", + "microsoft sgc", + "netscape sgc" + enum: + - signing + - digital signature + - content commitment + - key encipherment + - key agreement + - data encipherment + - cert sign + - crl sign + - encipher only + - decipher only + - any + - server auth + - client auth + - code signing + - email protection + - s/mime + - ipsec end system + - ipsec tunnel + - ipsec user + - timestamping + - ocsp signing + - microsoft sgc + - netscape sgc + type: string + type: array + required: + - issuerRef + - targetRef + type: object + status: + properties: + conditions: + description: |- + Represents the observations of a foo's current state. + Known .status.conditions.type are: "Available" + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + description: ObservedGeneration reflects the generation of the most + recently observed spec. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/examples/kuadrant/hack/boilerplate.go.txt b/examples/kuadrant/hack/boilerplate.go.txt new file mode 100644 index 0000000..06a460e --- /dev/null +++ b/examples/kuadrant/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ diff --git a/examples/kuadrant/main.go b/examples/kuadrant/main.go new file mode 100644 index 0000000..82c5f1a --- /dev/null +++ b/examples/kuadrant/main.go @@ -0,0 +1,163 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "os" + "sort" + "strings" + + "github.com/google/go-cmp/cmp" + "github.com/samber/lo" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/tools/clientcmd" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + "github.com/kuadrant/policy-machinery/controller" + "github.com/kuadrant/policy-machinery/machinery" + + kuadrantapis "github.com/kuadrant/policy-machinery/examples/kuadrant/apis" + kuadrantv1alpha2 "github.com/kuadrant/policy-machinery/examples/kuadrant/apis/v1alpha2" + kuadrantv1beta3 "github.com/kuadrant/policy-machinery/examples/kuadrant/apis/v1beta3" +) + +const topologyFile = "topology.dot" + +var _ controller.RuntimeObject = &gwapiv1.Gateway{} +var _ controller.RuntimeObject = &gwapiv1.HTTPRoute{} +var _ controller.RuntimeObject = &kuadrantv1alpha2.DNSPolicy{} +var _ controller.RuntimeObject = &kuadrantv1beta3.AuthPolicy{} +var _ controller.RuntimeObject = &kuadrantv1beta3.RateLimitPolicy{} + +func main() { + // load kubeconfig + kubeconfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}) + config, err := kubeconfig.ClientConfig() + if err != nil { + log.Fatalf("Error loading kubeconfig: %v", err) + } + + // create the client + client, err := dynamic.NewForConfig(config) + if err != nil { + log.Fatalf("Error creating client: %v", err) + } + + controller := controller.NewController( + controller.WithClient(client), + controller.WithInformer("gateway", controller.For[*gwapiv1.Gateway](gwapiv1.SchemeGroupVersion.WithResource("gateways"), metav1.NamespaceAll)), + controller.WithInformer("httproute", controller.For[*gwapiv1.HTTPRoute](gwapiv1.SchemeGroupVersion.WithResource("httproutes"), metav1.NamespaceAll)), + controller.WithInformer("dnspolicy", controller.For[*kuadrantv1alpha2.DNSPolicy](kuadrantv1alpha2.SchemeGroupVersion.WithResource("dnspolicies"), metav1.NamespaceAll)), + controller.WithInformer("tlspolicy", controller.For[*kuadrantv1alpha2.TLSPolicy](kuadrantv1alpha2.SchemeGroupVersion.WithResource("tlspolicies"), metav1.NamespaceAll)), + controller.WithInformer("authpolicy", controller.For[*kuadrantv1beta3.AuthPolicy](kuadrantv1beta3.SchemeGroupVersion.WithResource("authpolicies"), metav1.NamespaceAll)), + controller.WithInformer("ratelimitpolicy", controller.For[*kuadrantv1beta3.RateLimitPolicy](kuadrantv1beta3.SchemeGroupVersion.WithResource("ratelimitpolicies"), metav1.NamespaceAll)), + controller.WithPolicyKinds( + schema.GroupKind{Group: kuadrantv1alpha2.SchemeGroupVersion.Group, Kind: "DNSPolicy"}, + schema.GroupKind{Group: kuadrantv1alpha2.SchemeGroupVersion.Group, Kind: "TLSPolicy"}, + schema.GroupKind{Group: kuadrantv1beta3.SchemeGroupVersion.Group, Kind: "AuthPolicy"}, + schema.GroupKind{Group: kuadrantv1beta3.SchemeGroupVersion.Group, Kind: "RateLimitPolicy"}, + ), + controller.WithCallback(reconcile), + ) + + controller.Start() +} + +func reconcile(eventType controller.EventType, oldObj, newObj controller.RuntimeObject, topology *machinery.Topology) { + // print the event + obj := oldObj + if obj == nil { + obj = newObj + } + log.Printf("%s %sd: %s/%s\n", obj.GetObjectKind().GroupVersionKind().Kind, eventType.String(), obj.GetNamespace(), obj.GetName()) + if eventType == controller.UpdateEvent { + log.Println(cmp.Diff(oldObj, newObj)) + } + + // update the topology file + saveTopologyToFile(topology) + + // reconcile policies + gateways := topology.Targetables(func(o machinery.Object) bool { + _, ok := o.(*machinery.Gateway) + return ok + }) + + listeners := topology.Targetables(func(o machinery.Object) bool { + _, ok := o.(*machinery.Listener) + return ok + }) + + httpRouteRules := topology.Targetables(func(o machinery.Object) bool { + _, ok := o.(*machinery.HTTPRouteRule) + return ok + }) + + for _, gateway := range gateways { + // reconcile Gateway -> Listener policies + for _, listener := range listeners { + paths := topology.Paths(gateway, listener) + for i := range paths { + effectivePolicyForPath[*kuadrantv1alpha2.DNSPolicy](paths[i]) + effectivePolicyForPath[*kuadrantv1alpha2.TLSPolicy](paths[i]) + } + } + + // reconcile Gateway -> HTTPRouteRule policies + for _, httpRouteRule := range httpRouteRules { + paths := topology.Paths(gateway, httpRouteRule) + for i := range paths { + effectivePolicyForPath[*kuadrantv1beta3.AuthPolicy](paths[i]) + effectivePolicyForPath[*kuadrantv1beta3.RateLimitPolicy](paths[i]) + } + } + } +} + +func saveTopologyToFile(topology *machinery.Topology) { + file, err := os.Create(topologyFile) + if err != nil { + log.Fatal(err) + } + defer file.Close() + _, err = file.Write(topology.ToDot().Bytes()) + if err != nil { + log.Fatal(err) + } +} + +func effectivePolicyForPath[T machinery.Policy](path []machinery.Targetable) *T { + // gather all policies in the path sorted from the least specific to the most specific + policies := lo.FlatMap(path, func(targetable machinery.Targetable, _ int) []machinery.Policy { + policies := lo.FilterMap(targetable.Policies(), func(p machinery.Policy, _ int) (kuadrantapis.MergeablePolicy, bool) { + _, ok := p.(T) + mergeablePolicy, mergeable := p.(kuadrantapis.MergeablePolicy) + return mergeablePolicy, mergeable && ok + }) + sort.Sort(kuadrantapis.PolicyByCreationTimestamp(policies)) + return lo.Map(policies, func(p kuadrantapis.MergeablePolicy, _ int) machinery.Policy { return p }) + }) + + pathStr := strings.Join(lo.Map(path, func(t machinery.Targetable, _ int) string { + return fmt.Sprintf("%s::%s/%s", t.GroupVersionKind().Kind, t.GetNamespace(), t.GetName()) + }), " → ") + + if len(policies) == 0 { + log.Printf("No %T for path %s\n", new(T), pathStr) + return nil + } + + // map reduces the policies from most specific to least specific, merging them into one effective policy + effectivePolicy := lo.ReduceRight(policies, func(effectivePolicy machinery.Policy, policy machinery.Policy, _ int) machinery.Policy { + return effectivePolicy.Merge(policy) + }, policies[len(policies)-1]) + + jsonEffectivePolicy, _ := json.MarshalIndent(effectivePolicy, "", " ") + log.Printf("Effective %T for path %s:\n%s\n", new(T), pathStr, jsonEffectivePolicy) + + concreteEffectivePolicy, _ := effectivePolicy.(T) + return &concreteEffectivePolicy +} diff --git a/go.mod b/go.mod index ce0e4e4..c0e86ad 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,11 @@ module github.com/kuadrant/policy-machinery go 1.22.2 require ( + github.com/cert-manager/cert-manager v1.15.1 github.com/evanphx/json-patch v5.9.0+incompatible github.com/goccy/go-graphviz v0.1.3 + github.com/google/go-cmp v0.6.0 + github.com/kuadrant/authorino v0.17.2 github.com/samber/lo v1.39.0 k8s.io/api v0.30.2 k8s.io/apimachinery v0.30.2 @@ -14,19 +17,40 @@ require ( ) require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.12.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fogleman/gg v1.3.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.1 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.46.0 // indirect + github.com/prometheus/procfs v0.15.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/tidwall/gjson v1.14.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/image v0.14.0 // indirect golang.org/x/net v0.26.0 // indirect @@ -35,11 +59,15 @@ require ( golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.30.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f // indirect + sigs.k8s.io/controller-runtime v0.18.2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 719462e..52da611 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,11 @@ +dario.cat/mergo v0.3.5 h1:rybKppoxBoyv1JiXjzlqE4gdrhB0Xk/us0OW7yDEAl0= +dario.cat/mergo v0.3.5/go.mod h1:fvkCdyGtdx6UQvuEimZ9mB2dzc2AymrLoRgHC4lz6ec= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cert-manager/cert-manager v1.15.1 h1:HSG4k2GlJ2YgTLkZfQzrArNaQpM9+ehDDg550IxAD94= +github.com/cert-manager/cert-manager v1.15.1/go.mod h1:p98JoGv3J9JhdKU9ngsj2EhWGI6/GlU7kpjWu5lf2js= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/corona10/goimagehash v1.0.2 h1:pUfB0LnsJASMPGEZLj7tGY251vF+qLGqOgEP4rUs6kA= github.com/corona10/goimagehash v1.0.2/go.mod h1:/l9umBhvcHQXVtQO1V6Gp1yD20STawkhRnnX0D1bvVI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -8,22 +16,33 @@ github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapw github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/goccy/go-graphviz v0.1.3 h1:Pkt8y4FBnBNI9tfSobpoN5qy1qMNqRXPQYvLhaSUasY= github.com/goccy/go-graphviz v0.1.3/go.mod h1:pMYpbAqJT10V8dzV1JN/g/wUlG/0imKPzn3ZsrchGCI= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -34,6 +53,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -46,6 +67,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kuadrant/authorino v0.17.2 h1:UgWH4NY/n36IhoaU+ELUkoujaly1/9sx5mHY5vUrPOc= +github.com/kuadrant/authorino v0.17.2/go.mod h1:al71fN0FX6c9Orrhk9GR4CtjtC+CD/lUHJCs7drlRNM= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -57,11 +80,23 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= +github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= +github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek= +github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= @@ -72,8 +107,20 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w= +github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -111,10 +158,14 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -127,8 +178,12 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= +k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= +k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= @@ -139,6 +194,8 @@ k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGc k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q= +sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM= sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=