diff --git a/api/v1alpha1/api.go b/api/v1alpha1/api.go index 8744c7bc..75cea19f 100644 --- a/api/v1alpha1/api.go +++ b/api/v1alpha1/api.go @@ -167,6 +167,12 @@ type LLMBackendSpec struct { // // +kubebuilder:validation:Required BackendRef egv1a1.BackendRef `json:"backendRef"` + + // BackendSecurityPolicyRef is the name of the BackendSecurityPolicy resources this backend + // is being attached to. + // + // +optional + BackendSecurityPolicyRef *gwapiv1.LocalObjectReference `json:"backendSecurityPolicyRef,omitempty"` } // LLMAPISchema defines the API schema of either LLMRoute (the input) or LLMBackend (the output). @@ -205,3 +211,113 @@ const ( // This can be used to describe the routing behavior in HTTPRoute referenced by LLMRoute. LLMModelHeaderKey = "x-envoy-ai-gateway-llm-model" ) + +// BackendSecurityPolicyType specifies the type of auth mechanism used to access a backend. +type BackendSecurityPolicyType string + +const ( + BackendSecurityPolicyTypeAPIKey BackendSecurityPolicyType = "APIKey" + BackendSecurityPolicyTypeAWSCredentials BackendSecurityPolicyType = "AWSCredentials" +) + +// +kubebuilder:object:root=true + +// BackendSecurityPolicy specifies configuration for authentication and authorization rules on the traffic +// exiting the gateway to the backend. +type BackendSecurityPolicy struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec BackendSecurityPolicySpec `json:"spec,omitempty"` +} + +// BackendSecurityPolicySpec specifies authentication rules on access the provider from the Gateway. +// Only one mechanism to access a backend(s) can be specified. +// +// Only one type of BackendSecurityPolicy can be defined. +// +kubebuilder:validation:MaxProperties=2 +type BackendSecurityPolicySpec struct { + // Type specifies the auth mechanism used to access the provider. Currently, only "APIKey", AND "AWSCredentials" are supported. + // + // +kubebuilder:validation:Enum=APIKey;AWSCredentials + Type BackendSecurityPolicyType `json:"type"` + + // APIKey is a mechanism to access a backend(s). The API key will be injected into the Authorization header. + // + // +optional + APIKey *BackendSecurityPolicyAPIKey `json:"apiKey,omitempty"` + + // AWSCredentials is a mechanism to access a backend(s). AWS specific logic will be applied. + // + // +optional + AWSCredentials *BackendSecurityPolicyAWSCredentials `json:"awsCredentials,omitempty"` +} + +// +kubebuilder:object:root=true + +// BackendSecurityPolicyList contains a list of BackendSecurityPolicy +type BackendSecurityPolicyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []BackendSecurityPolicy `json:"items"` +} + +// BackendSecurityPolicyAPIKey specifies the API key. +type BackendSecurityPolicyAPIKey struct { + // SecretRef is the reference to the secret containing the API key. + // ai-gateway must be given the permission to read this secret. + // The key of the secret should be "apiKey". + SecretRef *gwapiv1.SecretObjectReference `json:"secretRef"` +} + +// BackendSecurityPolicyAWSCredentials contains the supported authentication mechanisms to access aws +type BackendSecurityPolicyAWSCredentials struct { + // Region specifies the AWS region associated with the policy. + // + // +kubebuilder:validation:MinLength=1 + Region string `json:"region"` + + // CredentialsFile specifies the credentials file to use for the AWS provider. + // + // +optional + CredentialsFile *AWSCredentialsFile `json:"credentialsFile,omitempty"` + + // OIDCExchangeToken specifies the oidc configurations used to obtain an oidc token. The oidc token will be + // used to obtain temporary credentials to access AWS. + // + // +optional + OIDCExchangeToken *AWSOIDCExchangeToken `json:"oidcExchangeToken,omitempty"` +} + +// AWSCredentialsFile specifies the credentials file to use for the AWS provider. +// Envoy reads the secret file, and the profile to use is specified by the Profile field. +type AWSCredentialsFile struct { + // SecretRef is the reference to the credential file + SecretRef *gwapiv1.SecretObjectReference `json:"secretRef"` + + // Profile is the profile to use in the credentials file. + // + // +kubebuilder:default=default + Profile string `json:"profile,omitempty"` +} + +// AWSOIDCExchangeToken specifies credentials to obtain oidc token from a sso server. +// For AWS, the controller will query STS to obtain AWS AccessKeyId, SecretAccessKey, and SessionToken, +// and store them in a temporary credentials file. +type AWSOIDCExchangeToken struct { + // OIDC is used to obtain oidc tokens via an SSO server which will be used to exchange for temporary AWS credentials. + OIDC egv1a1.OIDC `json:"oidc"` + + // GrantType is the method application gets access token. + // + // +optional + GrantType string `json:"grantType,omitempty"` + + // Aud defines the audience that this ID Token is intended for. + // + // +optional + Aud string `json:"aud,omitempty"` + + // AwsRoleArn is the AWS IAM Role with the permission to use specific resources in AWS account + // which maps to the temporary AWS security credentials exchanged using the authentication token issued by OIDC provider. + AwsRoleArn string `json:"awsRoleArn"` +} diff --git a/api/v1alpha1/registry.go b/api/v1alpha1/registry.go index 7a64bc29..c2af79d1 100644 --- a/api/v1alpha1/registry.go +++ b/api/v1alpha1/registry.go @@ -8,6 +8,7 @@ import ( func init() { SchemeBuilder.Register(&LLMRoute{}, &LLMRouteList{}) SchemeBuilder.Register(&LLMBackend{}, &LLMBackendList{}) + SchemeBuilder.Register(&BackendSecurityPolicy{}, &BackendSecurityPolicyList{}) } const GroupName = "aigateway.envoyproxy.io" diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6d706e8b..6e1ec117 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -10,6 +10,170 @@ import ( "sigs.k8s.io/gateway-api/apis/v1alpha2" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSCredentialsFile) DeepCopyInto(out *AWSCredentialsFile) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(v1.SecretObjectReference) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSCredentialsFile. +func (in *AWSCredentialsFile) DeepCopy() *AWSCredentialsFile { + if in == nil { + return nil + } + out := new(AWSCredentialsFile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSOIDCExchangeToken) DeepCopyInto(out *AWSOIDCExchangeToken) { + *out = *in + in.OIDC.DeepCopyInto(&out.OIDC) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSOIDCExchangeToken. +func (in *AWSOIDCExchangeToken) DeepCopy() *AWSOIDCExchangeToken { + if in == nil { + return nil + } + out := new(AWSOIDCExchangeToken) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackendSecurityPolicy) DeepCopyInto(out *BackendSecurityPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendSecurityPolicy. +func (in *BackendSecurityPolicy) DeepCopy() *BackendSecurityPolicy { + if in == nil { + return nil + } + out := new(BackendSecurityPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackendSecurityPolicy) 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 *BackendSecurityPolicyAPIKey) DeepCopyInto(out *BackendSecurityPolicyAPIKey) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(v1.SecretObjectReference) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendSecurityPolicyAPIKey. +func (in *BackendSecurityPolicyAPIKey) DeepCopy() *BackendSecurityPolicyAPIKey { + if in == nil { + return nil + } + out := new(BackendSecurityPolicyAPIKey) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackendSecurityPolicyAWSCredentials) DeepCopyInto(out *BackendSecurityPolicyAWSCredentials) { + *out = *in + if in.CredentialsFile != nil { + in, out := &in.CredentialsFile, &out.CredentialsFile + *out = new(AWSCredentialsFile) + (*in).DeepCopyInto(*out) + } + if in.OIDCExchangeToken != nil { + in, out := &in.OIDCExchangeToken, &out.OIDCExchangeToken + *out = new(AWSOIDCExchangeToken) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendSecurityPolicyAWSCredentials. +func (in *BackendSecurityPolicyAWSCredentials) DeepCopy() *BackendSecurityPolicyAWSCredentials { + if in == nil { + return nil + } + out := new(BackendSecurityPolicyAWSCredentials) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackendSecurityPolicyList) DeepCopyInto(out *BackendSecurityPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BackendSecurityPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendSecurityPolicyList. +func (in *BackendSecurityPolicyList) DeepCopy() *BackendSecurityPolicyList { + if in == nil { + return nil + } + out := new(BackendSecurityPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackendSecurityPolicyList) 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 *BackendSecurityPolicySpec) DeepCopyInto(out *BackendSecurityPolicySpec) { + *out = *in + if in.APIKey != nil { + in, out := &in.APIKey, &out.APIKey + *out = new(BackendSecurityPolicyAPIKey) + (*in).DeepCopyInto(*out) + } + if in.AWSCredentials != nil { + in, out := &in.AWSCredentials, &out.AWSCredentials + *out = new(BackendSecurityPolicyAWSCredentials) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackendSecurityPolicySpec. +func (in *BackendSecurityPolicySpec) DeepCopy() *BackendSecurityPolicySpec { + if in == nil { + return nil + } + out := new(BackendSecurityPolicySpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LLMAPISchema) DeepCopyInto(out *LLMAPISchema) { *out = *in @@ -88,6 +252,11 @@ func (in *LLMBackendSpec) DeepCopyInto(out *LLMBackendSpec) { *out = *in out.APISchema = in.APISchema in.BackendRef.DeepCopyInto(&out.BackendRef) + if in.BackendSecurityPolicyRef != nil { + in, out := &in.BackendSecurityPolicyRef, &out.BackendSecurityPolicyRef + *out = new(v1.LocalObjectReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMBackendSpec. diff --git a/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_backendsecuritypolicies.yaml b/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_backendsecuritypolicies.yaml new file mode 100644 index 00000000..77e946c0 --- /dev/null +++ b/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_backendsecuritypolicies.yaml @@ -0,0 +1,1256 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.2 + name: backendsecuritypolicies.aigateway.envoyproxy.io +spec: + group: aigateway.envoyproxy.io + names: + kind: BackendSecurityPolicy + listKind: BackendSecurityPolicyList + plural: backendsecuritypolicies + singular: backendsecuritypolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + BackendSecurityPolicy specifies configuration for authentication and authorization rules on the traffic + exiting the gateway to the backend. + 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: |- + BackendSecurityPolicySpec specifies authentication rules on access the provider from the Gateway. + Only one mechanism to access a backend(s) can be specified. + + Only one type of BackendSecurityPolicy can be defined. + maxProperties: 2 + properties: + apiKey: + description: APIKey is a mechanism to access a backend(s). The API + key will be injected into the Authorization header. + properties: + secretRef: + description: |- + SecretRef is the reference to the secret containing the API key. + ai-gateway must be given the permission to read this secret. + The key of the secret should be "apiKey". + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example "Secret". + 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 referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - secretRef + type: object + awsCredentials: + description: AWSCredentials is a mechanism to access a backend(s). + AWS specific logic will be applied. + properties: + credentialsFile: + description: CredentialsFile specifies the credentials file to + use for the AWS provider. + properties: + profile: + default: default + description: Profile is the profile to use in the credentials + file. + type: string + secretRef: + description: SecretRef is the reference to the credential + file + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + 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 referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + required: + - secretRef + type: object + oidcExchangeToken: + description: |- + OIDCExchangeToken specifies the oidc configurations used to obtain an oidc token. The oidc token will be + used to obtain temporary credentials to access AWS. + properties: + aud: + description: Aud defines the audience that this ID Token is + intended for. + type: string + awsRoleArn: + description: |- + AwsRoleArn is the AWS IAM Role with the permission to use specific resources in AWS account + which maps to the temporary AWS security credentials exchanged using the authentication token issued by OIDC provider. + type: string + grantType: + description: GrantType is the method application gets access + token. + type: string + oidc: + description: OIDC is used to obtain oidc tokens via an SSO + server which will be used to exchange for temporary AWS + credentials. + properties: + clientID: + description: |- + The client ID to be used in the OIDC + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + minLength: 1 + type: string + clientSecret: + description: |- + The Kubernetes secret which contains the OIDC client secret to be used in the + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + + This is an Opaque secret. The client secret should be stored in the key + "client-secret". + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + 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 referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + cookieDomain: + description: |- + The optional domain to set the access and ID token cookies on. + If not set, the cookies will default to the host of the request, not including the subdomains. + If set, the cookies will be set on the specified domain and all subdomains. + This means that requests to any subdomain will not require reauthentication after users log in to the parent domain. + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9]))*$ + type: string + cookieNames: + description: |- + The optional cookie name overrides to be used for Bearer and IdToken cookies in the + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + If not specified, uses a randomly generated suffix + properties: + accessToken: + description: |- + The name of the cookie used to store the AccessToken in the + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + If not specified, defaults to "AccessToken-(randomly generated uid)" + type: string + idToken: + description: |- + The name of the cookie used to store the IdToken in the + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + If not specified, defaults to "IdToken-(randomly generated uid)" + type: string + type: object + defaultRefreshTokenTTL: + description: |- + DefaultRefreshTokenTTL is the default lifetime of the refresh token. + This field is only used when the exp (expiration time) claim is omitted in + the refresh token or the refresh token is not JWT. + + If not specified, defaults to 604800s (one week). + Note: this field is only applicable when the "refreshToken" field is set to true. + type: string + defaultTokenTTL: + description: |- + DefaultTokenTTL is the default lifetime of the id token and access token. + Please note that Envoy will always use the expiry time from the response + of the authorization server if it is provided. This field is only used when + the expiry time is not provided by the authorization. + + If not specified, defaults to 0. In this case, the "expires_in" field in + the authorization response must be set by the authorization server, or the + OAuth flow will fail. + type: string + forwardAccessToken: + description: |- + ForwardAccessToken indicates whether the Envoy should forward the access token + via the Authorization header Bearer scheme to the upstream. + If not specified, defaults to false. + type: boolean + logoutPath: + description: |- + The path to log a user out, clearing their credential cookies. + + If not specified, uses a default logout path "/logout" + type: string + provider: + description: The OIDC Provider configuration. + properties: + authorizationEndpoint: + description: |- + The OIDC Provider's [authorization endpoint](https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint). + If not provided, EG will try to discover it from the provider's [Well-Known Configuration Endpoint](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse). + type: string + backendRef: + description: |- + BackendRef references a Kubernetes object that represents the + backend server to which the authorization request will be sent. + + Deprecated: Use BackendRefs instead. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + 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 referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + backendRefs: + description: |- + BackendRefs references a Kubernetes object that represents the + backend server to which the authorization request will be sent. + items: + description: BackendRef defines how an ObjectReference + that is specific to BackendRef. + properties: + fallback: + description: |- + Fallback indicates whether the backend is designated as a fallback. + Multiple fallback backends can be configured. + It is highly recommended to configure active or passive health checks to ensure that failover can be detected + when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again. + The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when + the health of the active backends falls below 72%. + type: boolean + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + 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 referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == + ''Service'') ? has(self.port) : true' + maxItems: 16 + type: array + backendSettings: + description: |- + BackendSettings holds configuration for managing the connection + to the backend. + properties: + circuitBreaker: + description: |- + Circuit Breaker settings for the upstream connections and requests. + If not set, circuit breakers will be enabled with the default thresholds + properties: + maxConnections: + default: 1024 + description: The maximum number of connections + that Envoy will establish to the referenced + backend defined within a xRoute rule. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + maxParallelRequests: + default: 1024 + description: The maximum number of parallel + requests that Envoy will make to the referenced + backend defined within a xRoute rule. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + maxParallelRetries: + default: 1024 + description: The maximum number of parallel + retries that Envoy will make to the referenced + backend defined within a xRoute rule. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + maxPendingRequests: + default: 1024 + description: The maximum number of pending + requests that Envoy will queue to the referenced + backend defined within a xRoute rule. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + maxRequestsPerConnection: + description: |- + The maximum number of requests that Envoy will make over a single connection to the referenced backend defined within a xRoute rule. + Default: unlimited. + format: int64 + maximum: 4294967295 + minimum: 0 + type: integer + type: object + connection: + description: Connection includes backend connection + settings. + properties: + bufferLimit: + allOf: + - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + - pattern: ^[1-9]+[0-9]*([EPTGMK]i|[EPTGMk])?$ + anyOf: + - type: integer + - type: string + description: |- + BufferLimit Soft limit on size of the cluster’s connections read and write buffers. + BufferLimit applies to connection streaming (maybe non-streaming) channel between processes, it's in user space. + If unspecified, an implementation defined default is applied (32768 bytes). + For example, 20Mi, 1Gi, 256Ki etc. + Note: that when the suffix is not provided, the value is interpreted as bytes. + x-kubernetes-int-or-string: true + socketBufferLimit: + allOf: + - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + - pattern: ^[1-9]+[0-9]*([EPTGMK]i|[EPTGMk])?$ + anyOf: + - type: integer + - type: string + description: |- + SocketBufferLimit provides configuration for the maximum buffer size in bytes for each socket + to backend. + SocketBufferLimit applies to socket streaming channel between TCP/IP stacks, it's in kernel space. + For example, 20Mi, 1Gi, 256Ki etc. + Note that when the suffix is not provided, the value is interpreted as bytes. + x-kubernetes-int-or-string: true + type: object + dns: + description: DNS includes dns resolution settings. + properties: + dnsRefreshRate: + description: |- + DNSRefreshRate specifies the rate at which DNS records should be refreshed. + Defaults to 30 seconds. + type: string + respectDnsTtl: + description: |- + RespectDNSTTL indicates whether the DNS Time-To-Live (TTL) should be respected. + If the value is set to true, the DNS refresh rate will be set to the resource record’s TTL. + Defaults to true. + type: boolean + type: object + healthCheck: + description: HealthCheck allows gateway to perform + active health checking on backends. + properties: + active: + description: Active health check configuration + properties: + grpc: + description: |- + GRPC defines the configuration of the GRPC health checker. + It's optional, and can only be used if the specified type is GRPC. + properties: + service: + description: |- + Service to send in the health check request. + If this is not specified, then the health check request applies to the entire + server and not to a specific service. + type: string + type: object + healthyThreshold: + default: 1 + description: HealthyThreshold defines + the number of healthy health checks + required before a backend host is marked + healthy. + format: int32 + minimum: 1 + type: integer + http: + description: |- + HTTP defines the configuration of http health checker. + It's required while the health checker type is HTTP. + properties: + expectedResponse: + description: ExpectedResponse defines + a list of HTTP expected responses + to match. + properties: + binary: + description: Binary payload base64 + encoded. + format: byte + type: string + text: + description: Text payload in plain + text. + type: string + type: + allOf: + - enum: + - Text + - Binary + - enum: + - Text + - Binary + description: Type defines the + type of the payload. + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: If payload type is Text, + text field needs to be set. + rule: 'self.type == ''Text'' ? has(self.text) + : !has(self.text)' + - message: If payload type is Binary, + binary field needs to be set. + rule: 'self.type == ''Binary'' ? + has(self.binary) : !has(self.binary)' + expectedStatuses: + description: |- + ExpectedStatuses defines a list of HTTP response statuses considered healthy. + Defaults to 200 only + items: + description: HTTPStatus defines + the http status code. + exclusiveMaximum: true + maximum: 600 + minimum: 100 + type: integer + type: array + method: + description: |- + Method defines the HTTP method used for health checking. + Defaults to GET + type: string + path: + description: Path defines the HTTP + path that will be requested during + health checking. + maxLength: 1024 + minLength: 1 + type: string + required: + - path + type: object + interval: + default: 3s + description: Interval defines the time + between active health checks. + format: duration + type: string + tcp: + description: |- + TCP defines the configuration of tcp health checker. + It's required while the health checker type is TCP. + properties: + receive: + description: Receive defines the expected + response payload. + properties: + binary: + description: Binary payload base64 + encoded. + format: byte + type: string + text: + description: Text payload in plain + text. + type: string + type: + allOf: + - enum: + - Text + - Binary + - enum: + - Text + - Binary + description: Type defines the + type of the payload. + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: If payload type is Text, + text field needs to be set. + rule: 'self.type == ''Text'' ? has(self.text) + : !has(self.text)' + - message: If payload type is Binary, + binary field needs to be set. + rule: 'self.type == ''Binary'' ? + has(self.binary) : !has(self.binary)' + send: + description: Send defines the request + payload. + properties: + binary: + description: Binary payload base64 + encoded. + format: byte + type: string + text: + description: Text payload in plain + text. + type: string + type: + allOf: + - enum: + - Text + - Binary + - enum: + - Text + - Binary + description: Type defines the + type of the payload. + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: If payload type is Text, + text field needs to be set. + rule: 'self.type == ''Text'' ? has(self.text) + : !has(self.text)' + - message: If payload type is Binary, + binary field needs to be set. + rule: 'self.type == ''Binary'' ? + has(self.binary) : !has(self.binary)' + type: object + timeout: + default: 1s + description: Timeout defines the time + to wait for a health check response. + format: duration + type: string + type: + allOf: + - enum: + - HTTP + - TCP + - GRPC + - enum: + - HTTP + - TCP + - GRPC + description: Type defines the type of + health checker. + type: string + unhealthyThreshold: + default: 3 + description: UnhealthyThreshold defines + the number of unhealthy health checks + required before a backend host is marked + unhealthy. + format: int32 + minimum: 1 + type: integer + required: + - type + type: object + x-kubernetes-validations: + - message: If Health Checker type is HTTP, + http field needs to be set. + rule: 'self.type == ''HTTP'' ? has(self.http) + : !has(self.http)' + - message: If Health Checker type is TCP, + tcp field needs to be set. + rule: 'self.type == ''TCP'' ? has(self.tcp) + : !has(self.tcp)' + - message: The grpc field can only be set + if the Health Checker type is GRPC. + rule: 'has(self.grpc) ? self.type == ''GRPC'' + : true' + passive: + description: Passive passive check configuration + properties: + baseEjectionTime: + default: 30s + description: BaseEjectionTime defines + the base duration for which a host will + be ejected on consecutive failures. + format: duration + type: string + consecutive5XxErrors: + default: 5 + description: Consecutive5xxErrors sets + the number of consecutive 5xx errors + triggering ejection. + format: int32 + type: integer + consecutiveGatewayErrors: + default: 0 + description: ConsecutiveGatewayErrors + sets the number of consecutive gateway + errors triggering ejection. + format: int32 + type: integer + consecutiveLocalOriginFailures: + default: 5 + description: |- + ConsecutiveLocalOriginFailures sets the number of consecutive local origin failures triggering ejection. + Parameter takes effect only when split_external_local_origin_errors is set to true. + format: int32 + type: integer + interval: + default: 3s + description: Interval defines the time + between passive health checks. + format: duration + type: string + maxEjectionPercent: + default: 10 + description: MaxEjectionPercent sets the + maximum percentage of hosts in a cluster + that can be ejected. + format: int32 + type: integer + splitExternalLocalOriginErrors: + default: false + description: SplitExternalLocalOriginErrors + enables splitting of errors between + external and local origin. + type: boolean + type: object + type: object + http2: + description: HTTP2 provides HTTP/2 configuration + for backend connections. + properties: + initialConnectionWindowSize: + allOf: + - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + - pattern: ^[1-9]+[0-9]*([EPTGMK]i|[EPTGMk])?$ + anyOf: + - type: integer + - type: string + description: |- + InitialConnectionWindowSize sets the initial window size for HTTP/2 connections. + If not set, the default value is 1 MiB. + x-kubernetes-int-or-string: true + initialStreamWindowSize: + allOf: + - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + - pattern: ^[1-9]+[0-9]*([EPTGMK]i|[EPTGMk])?$ + anyOf: + - type: integer + - type: string + description: |- + InitialStreamWindowSize sets the initial window size for HTTP/2 streams. + If not set, the default value is 64 KiB(64*1024). + x-kubernetes-int-or-string: true + maxConcurrentStreams: + description: |- + MaxConcurrentStreams sets the maximum number of concurrent streams allowed per connection. + If not set, the default value is 100. + format: int32 + maximum: 2147483647 + minimum: 1 + type: integer + onInvalidMessage: + description: |- + OnInvalidMessage determines if Envoy will terminate the connection or just the offending stream in the event of HTTP messaging error + It's recommended for L2 Envoy deployments to set this value to TerminateStream. + https://www.envoyproxy.io/docs/envoy/latest/configuration/best_practices/level_two + Default: TerminateConnection + type: string + type: object + loadBalancer: + description: |- + LoadBalancer policy to apply when routing traffic from the gateway to + the backend endpoints. Defaults to `LeastRequest`. + properties: + consistentHash: + description: |- + ConsistentHash defines the configuration when the load balancer type is + set to ConsistentHash + properties: + cookie: + description: Cookie configures the cookie + hash policy when the consistent hash + type is set to Cookie. + properties: + attributes: + additionalProperties: + type: string + description: Additional Attributes + to set for the generated cookie. + type: object + name: + description: |- + Name of the cookie to hash. + If this cookie does not exist in the request, Envoy will generate a cookie and set + the TTL on the response back to the client based on Layer 4 + attributes of the backend endpoint, to ensure that these future requests + go to the same backend endpoint. Make sure to set the TTL field for this case. + type: string + ttl: + description: |- + TTL of the generated cookie if the cookie is not present. This value sets the + Max-Age attribute value. + type: string + required: + - name + type: object + header: + description: Header configures the header + hash policy when the consistent hash + type is set to Header. + properties: + name: + description: Name of the header to + hash. + type: string + required: + - name + type: object + tableSize: + default: 65537 + description: The table size for consistent + hashing, must be prime number limited + to 5000011. + format: int64 + maximum: 5000011 + minimum: 2 + type: integer + type: + description: |- + ConsistentHashType defines the type of input to hash on. Valid Type values are + "SourceIP", + "Header", + "Cookie". + enum: + - SourceIP + - Header + - Cookie + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: If consistent hash type is header, + the header field must be set. + rule: 'self.type == ''Header'' ? has(self.header) + : !has(self.header)' + - message: If consistent hash type is cookie, + the cookie field must be set. + rule: 'self.type == ''Cookie'' ? has(self.cookie) + : !has(self.cookie)' + slowStart: + description: |- + SlowStart defines the configuration related to the slow start load balancer policy. + If set, during slow start window, traffic sent to the newly added hosts will gradually increase. + Currently this is only supported for RoundRobin and LeastRequest load balancers + properties: + window: + description: |- + Window defines the duration of the warm up period for newly added host. + During slow start window, traffic sent to the newly added hosts will gradually increase. + Currently only supports linear growth of traffic. For additional details, + see https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#config-cluster-v3-cluster-slowstartconfig + type: string + required: + - window + type: object + type: + description: |- + Type decides the type of Load Balancer policy. + Valid LoadBalancerType values are + "ConsistentHash", + "LeastRequest", + "Random", + "RoundRobin". + enum: + - ConsistentHash + - LeastRequest + - Random + - RoundRobin + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: If LoadBalancer type is consistentHash, + consistentHash field needs to be set. + rule: 'self.type == ''ConsistentHash'' ? has(self.consistentHash) + : !has(self.consistentHash)' + - message: Currently SlowStart is only supported + for RoundRobin and LeastRequest load balancers. + rule: 'self.type in [''Random'', ''ConsistentHash''] + ? !has(self.slowStart) : true ' + proxyProtocol: + description: ProxyProtocol enables the Proxy Protocol + when communicating with the backend. + properties: + version: + description: |- + Version of ProxyProtol + Valid ProxyProtocolVersion values are + "V1" + "V2" + enum: + - V1 + - V2 + type: string + required: + - version + type: object + retry: + description: |- + Retry provides more advanced usage, allowing users to customize the number of retries, retry fallback strategy, and retry triggering conditions. + If not set, retry will be disabled. + properties: + numRetries: + default: 2 + description: NumRetries is the number of retries + to be attempted. Defaults to 2. + format: int32 + minimum: 0 + type: integer + perRetry: + description: PerRetry is the retry policy + to be applied per retry attempt. + properties: + backOff: + description: |- + Backoff is the backoff policy to be applied per retry attempt. gateway uses a fully jittered exponential + back-off algorithm for retries. For additional details, + see https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#config-http-filters-router-x-envoy-max-retries + properties: + baseInterval: + description: BaseInterval is the base + interval between retries. + format: duration + type: string + maxInterval: + description: |- + MaxInterval is the maximum interval between retries. This parameter is optional, but must be greater than or equal to the base_interval if set. + The default is 10 times the base_interval + format: duration + type: string + type: object + timeout: + description: Timeout is the timeout per + retry attempt. + format: duration + type: string + type: object + retryOn: + description: |- + RetryOn specifies the retry trigger condition. + + If not specified, the default is to retry on connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes(503). + properties: + httpStatusCodes: + description: |- + HttpStatusCodes specifies the http status codes to be retried. + The retriable-status-codes trigger must also be configured for these status codes to trigger a retry. + items: + description: HTTPStatus defines the + http status code. + exclusiveMaximum: true + maximum: 600 + minimum: 100 + type: integer + type: array + triggers: + description: Triggers specifies the retry + trigger condition(Http/Grpc). + items: + description: TriggerEnum specifies the + conditions that trigger retries. + enum: + - 5xx + - gateway-error + - reset + - connect-failure + - retriable-4xx + - refused-stream + - retriable-status-codes + - cancelled + - deadline-exceeded + - internal + - resource-exhausted + - unavailable + type: string + type: array + type: object + type: object + tcpKeepalive: + description: |- + TcpKeepalive settings associated with the upstream client connection. + Disabled by default. + properties: + idleTime: + description: |- + The duration a connection needs to be idle before keep-alive + probes start being sent. + The duration format is + Defaults to `7200s`. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + interval: + description: |- + The duration between keep-alive probes. + Defaults to `75s`. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + probes: + description: |- + The total number of unacknowledged probes to send before deciding + the connection is dead. + Defaults to 9. + format: int32 + type: integer + type: object + timeout: + description: Timeout settings for the backend + connections. + properties: + http: + description: Timeout settings for HTTP. + properties: + connectionIdleTimeout: + description: |- + The idle timeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection. + Default: 1 hour. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + maxConnectionDuration: + description: |- + The maximum duration of an HTTP connection. + Default: unlimited. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + requestTimeout: + description: RequestTimeout is the time + until which entire response is received + from the upstream. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + tcp: + description: Timeout settings for TCP. + properties: + connectTimeout: + description: |- + The timeout for network connection establishment, including TCP and TLS handshakes. + Default: 10 seconds. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string + type: object + type: object + type: object + issuer: + description: |- + The OIDC Provider's [issuer identifier](https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery). + Issuer MUST be a URI RFC 3986 [RFC3986] with a scheme component that MUST + be https, a host component, and optionally, port and path components and + no query or fragment components. + minLength: 1 + type: string + tokenEndpoint: + description: |- + The OIDC Provider's [token endpoint](https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint). + If not provided, EG will try to discover it from the provider's [Well-Known Configuration Endpoint](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse). + type: string + required: + - issuer + type: object + x-kubernetes-validations: + - message: BackendRefs must be used, backendRef is not + supported. + rule: '!has(self.backendRef)' + - message: Retry timeout is not supported. + rule: has(self.backendSettings)? (has(self.backendSettings.retry)?(has(self.backendSettings.retry.perRetry)? + !has(self.backendSettings.retry.perRetry.timeout):true):true):true + - message: HTTPStatusCodes is not supported. + rule: has(self.backendSettings)? (has(self.backendSettings.retry)?(has(self.backendSettings.retry.retryOn)? + !has(self.backendSettings.retry.retryOn.httpStatusCodes):true):true):true + redirectURL: + description: |- + The redirect URL to be used in the OIDC + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + If not specified, uses the default redirect URI "%REQ(x-forwarded-proto)%://%REQ(:authority)%/oauth2/callback" + type: string + refreshToken: + description: |- + RefreshToken indicates whether the Envoy should automatically refresh the + id token and access token when they expire. + When set to true, the Envoy will use the refresh token to get a new id token + and access token when they expire. + + If not specified, defaults to false. + type: boolean + resources: + description: |- + The OIDC resources to be used in the + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + items: + type: string + type: array + scopes: + description: |- + The OIDC scopes to be used in the + [Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). + The "openid" scope is always added to the list of scopes if not already + specified. + items: + type: string + type: array + required: + - clientID + - clientSecret + - provider + type: object + required: + - awsRoleArn + - oidc + type: object + region: + description: Region specifies the AWS region associated with the + policy. + minLength: 1 + type: string + required: + - region + type: object + type: + description: Type specifies the auth mechanism used to access the + provider. Currently, only "APIKey", AND "AWSCredentials" are supported. + enum: + - APIKey + - AWSCredentials + type: string + required: + - type + type: object + type: object + served: true + storage: true diff --git a/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackends.yaml b/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackends.yaml index a03922dd..71dc591f 100644 --- a/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackends.yaml +++ b/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackends.yaml @@ -131,6 +131,35 @@ spec: - message: Must have port for Service reference rule: '(size(self.group) == 0 && self.kind == ''Service'') ? has(self.port) : true' + backendSecurityPolicyRef: + description: |- + BackendSecurityPolicyRef is the name of the BackendSecurityPolicy resources this backend + is being attached to. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + 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 referent. For example "HTTPRoute" + or "Service". + 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 referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object outputSchema: description: |- APISchema specifies the API schema of the output format of requests from diff --git a/tests/cel-validation/main_test.go b/tests/cel-validation/main_test.go index 44bfcd0d..ee51aca3 100644 --- a/tests/cel-validation/main_test.go +++ b/tests/cel-validation/main_test.go @@ -37,6 +37,7 @@ func runTest(m *testing.M) int { for _, crd := range []string{ "aigateway.envoyproxy.io_llmroutes.yaml", "aigateway.envoyproxy.io_llmbackends.yaml", + "aigateway.envoyproxy.io_backendsecuritypolicies.yaml", } { crds = append(crds, filepath.Join(base, crd)) } @@ -138,3 +139,45 @@ func TestLLMBackends(t *testing.T) { }) } } + +func TestBackendSecurityPolicies(t *testing.T) { + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second)) + defer cancel() + + for _, tc := range []struct { + name string + expErr string + }{ + {name: "basic.yaml"}, + { + name: "unknown_provider.yaml", + expErr: "spec.type: Unsupported value: \"UnknownType\": supported values: \"APIKey\", \"AWSCredentials\"", + }, + { + name: "missing_type.yaml", + expErr: "spec.type: Unsupported value: \"\": supported values: \"APIKey\", \"AWSCredentials\"", + }, + { + name: "multiple_security_policies.yaml", + expErr: "Too many: 3: must have at most 2 items", + }, + {name: "aws_credential_file.yaml"}, + {name: "aws_oidc.yaml"}, + } { + t.Run(tc.name, func(t *testing.T) { + data, err := tests.ReadFile(path.Join("testdata/backendsecuritypolicies", tc.name)) + require.NoError(t, err) + + backendSecurityPolicy := &aigv1a1.BackendSecurityPolicy{} + err = yaml.UnmarshalStrict(data, backendSecurityPolicy) + require.NoError(t, err) + + if tc.expErr != "" { + require.ErrorContains(t, c.Create(ctx, backendSecurityPolicy), tc.expErr) + } else { + require.NoError(t, c.Create(ctx, backendSecurityPolicy)) + require.NoError(t, c.Delete(ctx, backendSecurityPolicy)) + } + }) + } +} diff --git a/tests/cel-validation/testdata/backendsecuritypolicies/aws_credential_file.yaml b/tests/cel-validation/testdata/backendsecuritypolicies/aws_credential_file.yaml new file mode 100644 index 00000000..7bf1ac1c --- /dev/null +++ b/tests/cel-validation/testdata/backendsecuritypolicies/aws_credential_file.yaml @@ -0,0 +1,12 @@ +apiVersion: aigateway.envoyproxy.io/v1alpha1 +kind: BackendSecurityPolicy +metadata: + name: dog-provider-policy + namespace: default +spec: + type: AWSCredentials + awsCredentials: + region: us-east-1 + credentialsFile: + secretRef: + name: placeholder diff --git a/tests/cel-validation/testdata/backendsecuritypolicies/aws_oidc.yaml b/tests/cel-validation/testdata/backendsecuritypolicies/aws_oidc.yaml new file mode 100644 index 00000000..bc379344 --- /dev/null +++ b/tests/cel-validation/testdata/backendsecuritypolicies/aws_oidc.yaml @@ -0,0 +1,20 @@ +apiVersion: aigateway.envoyproxy.io/v1alpha1 +kind: BackendSecurityPolicy +metadata: + name: dog-provider-policy + namespace: default +spec: + type: AWSCredentials + awsCredentials: + region: us-east-1 + oidcExchangeToken: + oidc: + provider: + issuer: placeholder + clientID: placeholder + clientSecret: + name: placeholder + credentialsFile: + secretRef: + name: placeholder + profile: default diff --git a/tests/cel-validation/testdata/backendsecuritypolicies/basic.yaml b/tests/cel-validation/testdata/backendsecuritypolicies/basic.yaml new file mode 100644 index 00000000..e2462f8a --- /dev/null +++ b/tests/cel-validation/testdata/backendsecuritypolicies/basic.yaml @@ -0,0 +1,7 @@ +apiVersion: aigateway.envoyproxy.io/v1alpha1 +kind: BackendSecurityPolicy +metadata: + name: dog-provider-policy + namespace: default +spec: + type: APIKey diff --git a/tests/cel-validation/testdata/backendsecuritypolicies/missing_type.yaml b/tests/cel-validation/testdata/backendsecuritypolicies/missing_type.yaml new file mode 100644 index 00000000..b4b4a75b --- /dev/null +++ b/tests/cel-validation/testdata/backendsecuritypolicies/missing_type.yaml @@ -0,0 +1,8 @@ +apiVersion: aigateway.envoyproxy.io/v1alpha1 +kind: BackendSecurityPolicy +metadata: + name: dog-provider-policy + namespace: default +spec: + awsCredentials: + region: us-east-1å diff --git a/tests/cel-validation/testdata/backendsecuritypolicies/multiple_security_policies.yaml b/tests/cel-validation/testdata/backendsecuritypolicies/multiple_security_policies.yaml new file mode 100644 index 00000000..b363e1d5 --- /dev/null +++ b/tests/cel-validation/testdata/backendsecuritypolicies/multiple_security_policies.yaml @@ -0,0 +1,12 @@ +apiVersion: aigateway.envoyproxy.io/v1alpha1 +kind: BackendSecurityPolicy +metadata: + name: dog-provider-policy + namespace: default +spec: + type: APIKey + apiKey: + secretRef: + name: placeholder + awsCredentials: + region: us-east-1 diff --git a/tests/cel-validation/testdata/backendsecuritypolicies/unknown_provider.yaml b/tests/cel-validation/testdata/backendsecuritypolicies/unknown_provider.yaml new file mode 100644 index 00000000..5ac6dbe4 --- /dev/null +++ b/tests/cel-validation/testdata/backendsecuritypolicies/unknown_provider.yaml @@ -0,0 +1,7 @@ +apiVersion: aigateway.envoyproxy.io/v1alpha1 +kind: BackendSecurityPolicy +metadata: + name: dog-provider-policy + namespace: default +spec: + type: UnknownType