diff --git a/api/v1alpha1/ext_auth_types.go b/api/v1alpha1/ext_auth_types.go index faa0897e300..4a6bdd98ef3 100644 --- a/api/v1alpha1/ext_auth_types.go +++ b/api/v1alpha1/ext_auth_types.go @@ -33,6 +33,10 @@ type ExtAuth struct { // +optional HeadersToExtAuth []string `json:"headersToExtAuth,omitempty"` + // BodyToExtAuth defines the Body to Ext Auth configuration. + // +optional + BodyToExtAuth *BodyToExtAuth `json:"bodyToExtAuth,omitempty"` + // FailOpen is a switch used to control the behavior when a response from the External Authorization service cannot be obtained. // If FailOpen is set to true, the system allows the traffic to pass through. // Otherwise, if it is set to false or not set (defaulting to false), @@ -85,3 +89,23 @@ type HTTPExtAuthService struct { // +optional HeadersToBackend []string `json:"headersToBackend,omitempty"` } + +// BodyToExtAuth defines the Body to Ext Auth configuration +type BodyToExtAuth struct { + // MaxRequestBytes is the maximum size of a message body that the filter will hold in memory. + // Envoy will return HTTP 413 and will not initiate the authorization process when buffer + // reaches the number set in this field. + // Note that this setting will have precedence over failureModeAllow. + MaxRequestBytes uint32 `json:"maxRequestBytes"` + + // When AllowPartialMessage is true, Envoy will buffer the message until MaxRequestBytes is reached. + // The authorization request will be dispatched and no 413 HTTP error will be returned by the filter. + AllowPartialMessage bool `json:"allowPartialMessage"` + + // If PackAsBytes is true, the body sent to the external authorization service is set with raw bytes, + // it sets the raw_body field of HTTP request attribute context. Otherwise, body will be + // filled with UTF-8 string request body. + // This field only affects configurations using a grpcService. In configurations that use + // an httpService, this has no effect. + PackAsBytes bool `json:"packAsBytes"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 457afa58ac4..742ffed1b25 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -595,6 +595,21 @@ func (in *BasicAuth) DeepCopy() *BasicAuth { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BodyToExtAuth) DeepCopyInto(out *BodyToExtAuth) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BodyToExtAuth. +func (in *BodyToExtAuth) DeepCopy() *BodyToExtAuth { + if in == nil { + return nil + } + out := new(BodyToExtAuth) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CORS) DeepCopyInto(out *CORS) { *out = *in @@ -2115,6 +2130,11 @@ func (in *ExtAuth) DeepCopyInto(out *ExtAuth) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.BodyToExtAuth != nil { + in, out := &in.BodyToExtAuth, &out.BodyToExtAuth + *out = new(BodyToExtAuth) + **out = **in + } if in.FailOpen != nil { in, out := &in.FailOpen, &out.FailOpen *out = new(bool) diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index 3219f816da5..f88658fe227 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -933,6 +933,15 @@ func (t *Translator) buildExtAuth( Authority: authority, } } + + if policy.Spec.ExtAuth.BodyToExtAuth != nil { + extAuth.BodyToExtAuth = &ir.BodyToExtAuth{ + MaxRequestBytes: policy.Spec.ExtAuth.BodyToExtAuth.MaxRequestBytes, + AllowPartialMessage: policy.Spec.ExtAuth.BodyToExtAuth.AllowPartialMessage, + PackAsBytes: policy.Spec.ExtAuth.BodyToExtAuth.PackAsBytes, + } + } + return extAuth, nil } diff --git a/internal/gatewayapi/testdata/securitypolicy-with-extauth-body.in.yaml b/internal/gatewayapi/testdata/securitypolicy-with-extauth-body.in.yaml new file mode 100644 index 00000000000..a33f1c72964 --- /dev/null +++ b/internal/gatewayapi/testdata/securitypolicy-with-extauth-body.in.yaml @@ -0,0 +1,111 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: default + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - www.foo.com + parentRefs: + - namespace: default + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: /foo1 + backendRefs: + - name: service-1 + port: 8080 + - matches: + - path: + value: /foo2 + backendRefs: + - name: service-2 + port: 8080 + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-2 + spec: + hostnames: + - www.bar.com + parentRefs: + - namespace: default + name: gateway-1 + sectionName: http + rules: + - matches: + - path: + value: /bar + backendRefs: + - name: service-3 + port: 8080 +backends: + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + name: backend-fqdn + namespace: default + spec: + endpoints: + - fqdn: + hostname: 'primary.foo.com' + port: 3000 +referenceGrants: + - apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: ReferenceGrant + metadata: + namespace: envoy-gateway + name: referencegrant-1 + spec: + from: + - group: gateway.envoyproxy.io + kind: SecurityPolicy + namespace: default + to: + - group: "" + kind: Service +securityPolicies: + - apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + namespace: default + name: policy-for-http-route-1 + spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + extAuth: + failOpen: true + headersToExtAuth: + - header1 + - header2 + bodyToExtAuth: {} + grpc: + backendRefs: + - name: service-2 + kind: Service + port: 8080 + - name: backend-fqdn + kind: Backend + group: gateway.envoyproxy.io + port: 3000 diff --git a/internal/gatewayapi/testdata/securitypolicy-with-extauth-body.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-extauth-body.out.yaml new file mode 100644 index 00000000000..53bb26fe28e --- /dev/null +++ b/internal/gatewayapi/testdata/securitypolicy-with-extauth-body.out.yaml @@ -0,0 +1,341 @@ +backends: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: Backend + metadata: + creationTimestamp: null + name: backend-fqdn + namespace: default + spec: + endpoints: + - fqdn: + hostname: primary.foo.com + port: 3000 + status: + conditions: + - lastTransitionTime: null + message: The Backend was accepted + reason: Accepted + status: "True" + type: Accepted +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: default + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 2 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + hostnames: + - www.foo.com + parentRefs: + - name: gateway-1 + namespace: default + sectionName: http + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: /foo1 + - backendRefs: + - name: service-2 + port: 8080 + matches: + - path: + value: /foo2 + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: default + sectionName: http +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-2 + namespace: default + spec: + hostnames: + - www.bar.com + parentRefs: + - name: gateway-1 + namespace: default + sectionName: http + rules: + - backendRefs: + - name: service-3 + port: 8080 + matches: + - path: + value: /bar + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: default + sectionName: http +infraIR: + default/gateway-1: + proxy: + listeners: + - address: null + name: default/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: default + name: default/gateway-1 +securityPolicies: +- apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: SecurityPolicy + metadata: + creationTimestamp: null + name: policy-for-http-route-1 + namespace: default + spec: + extAuth: + bodyToExtAuth: + allowPartialMessage: false + maxRequestBytes: 0 + packAsBytes: false + failOpen: true + grpc: + backendRefs: + - kind: Service + name: service-2 + port: 8080 + - group: gateway.envoyproxy.io + kind: Backend + name: backend-fqdn + port: 3000 + headersToExtAuth: + - header1 + - header2 + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httproute-1 + status: + ancestors: + - ancestorRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-1 + namespace: default + sectionName: http + conditions: + - lastTransitionTime: null + message: Policy has been accepted. + reason: Accepted + status: "True" + type: Accepted + controllerName: gateway.envoyproxy.io/gatewayclass-controller +xdsIR: + default/gateway-1: + accessLog: + text: + - path: /dev/stdout + http: + - address: '::' + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: default + sectionName: http + name: default/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - destination: + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + hostname: www.foo.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/www_foo_com + pathMatch: + distinct: false + name: "" + prefix: /foo1 + security: + extAuth: + bodyToExtAuth: + allowPartialMessage: false + maxRequestBytes: 0 + packAsBytes: false + failOpen: true + grpc: + authority: service-2.default:8080 + destination: + name: securitypolicy/default/policy-for-http-route-1/extauth/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: GRPC + weight: 1 + - addressType: FQDN + endpoints: + - host: primary.foo.com + port: 3000 + protocol: GRPC + weight: 1 + headersToExtAuth: + - header1 + - header2 + name: securitypolicy/default/policy-for-http-route-1 + - destination: + name: httproute/default/httproute-1/rule/1 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + hostname: www.foo.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/1/match/0/www_foo_com + pathMatch: + distinct: false + name: "" + prefix: /foo2 + security: + extAuth: + bodyToExtAuth: + allowPartialMessage: false + maxRequestBytes: 0 + packAsBytes: false + failOpen: true + grpc: + authority: service-2.default:8080 + destination: + name: securitypolicy/default/policy-for-http-route-1/extauth/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: GRPC + weight: 1 + - addressType: FQDN + endpoints: + - host: primary.foo.com + port: 3000 + protocol: GRPC + weight: 1 + headersToExtAuth: + - header1 + - header2 + name: securitypolicy/default/policy-for-http-route-1 + - destination: + name: httproute/default/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + hostname: www.bar.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-2 + namespace: default + name: httproute/default/httproute-2/rule/0/match/0/www_bar_com + pathMatch: + distinct: false + name: "" + prefix: /bar diff --git a/internal/ir/xds.go b/internal/ir/xds.go index b0b9a1594b1..1e5dbe61049 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1007,6 +1007,10 @@ type ExtAuth struct { // +optional HeadersToExtAuth []string `json:"headersToExtAuth,omitempty"` + // BodyToExtAuth defines the Body to Ext Auth configuration. + // +optional + BodyToExtAuth *BodyToExtAuth `json:"bodyToExtAuth,omitempty"` + // FailOpen is a switch used to control the behavior when a response from the External Authorization service cannot be obtained. // If FailOpen is set to true, the system allows the traffic to pass through. // Otherwise, if it is set to false or not set (defaulting to false), @@ -1023,6 +1027,27 @@ type ExtAuth struct { RecomputeRoute *bool `json:"recomputeRoute,omitempty"` } +// BodyToExtAuth defines the Body to Ext Auth configuration +// +k8s:deepcopy-gen=true +type BodyToExtAuth struct { + // MaxRequestBytes is the maximum size of a message body that the filter will hold in memory. + // Envoy will return HTTP 413 and will not initiate the authorization process when buffer + // reaches the number set in this field. + // Note that this setting will have precedence over failureModeAllow. + MaxRequestBytes uint32 `json:"maxRequestBytes"` + + // When AllowPartialMessage is true, Envoy will buffer the message until MaxRequestBytes is reached. + // The authorization request will be dispatched and no 413 HTTP error will be returned by the filter. + AllowPartialMessage bool `json:"allowPartialMessage"` + + // If PackAsBytes is true, the body sent to the external authorization service is set with raw bytes, + // it sets the raw_body field of HTTP request attribute context. Otherwise, body will be + // filled with UTF-8 string request body. + // This field only affects configurations using a grpcService. In configurations that use + // an httpService, this has no effect. + PackAsBytes bool `json:"packAsBytes"` +} + // HTTPExtAuthService defines the HTTP External Authorization service // +k8s:deepcopy-gen=true type HTTPExtAuthService struct { diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index de0be09ff0f..f5a7165434c 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -330,6 +330,21 @@ func (in *BasicAuth) DeepCopy() *BasicAuth { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BodyToExtAuth) DeepCopyInto(out *BodyToExtAuth) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BodyToExtAuth. +func (in *BodyToExtAuth) DeepCopy() *BodyToExtAuth { + if in == nil { + return nil + } + out := new(BodyToExtAuth) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CORS) DeepCopyInto(out *CORS) { *out = *in @@ -893,6 +908,11 @@ func (in *ExtAuth) DeepCopyInto(out *ExtAuth) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.BodyToExtAuth != nil { + in, out := &in.BodyToExtAuth, &out.BodyToExtAuth + *out = new(BodyToExtAuth) + **out = **in + } if in.FailOpen != nil { in, out := &in.FailOpen, &out.FailOpen *out = new(bool) diff --git a/internal/xds/translator/extauth.go b/internal/xds/translator/extauth.go index 2f8766fe91c..a0d2d34aef7 100644 --- a/internal/xds/translator/extauth.go +++ b/internal/xds/translator/extauth.go @@ -117,6 +117,14 @@ func extAuthConfig(extAuth *ir.ExtAuth) *extauthv3.ExtAuthz { }) } + if extAuth.BodyToExtAuth != nil { + config.WithRequestBody = &extauthv3.BufferSettings{ + MaxRequestBytes: extAuth.BodyToExtAuth.MaxRequestBytes, + AllowPartialMessage: extAuth.BodyToExtAuth.AllowPartialMessage, + PackAsBytes: extAuth.BodyToExtAuth.PackAsBytes, + } + } + if len(headersToExtAuth) > 0 { config.AllowedHeaders = &matcherv3.ListStringMatcher{ Patterns: headersToExtAuth, diff --git a/internal/xds/translator/testdata/in/xds-ir/ext-auth-body.yaml b/internal/xds/translator/testdata/in/xds-ir/ext-auth-body.yaml new file mode 100644 index 00000000000..cb322f51d5c --- /dev/null +++ b/internal/xds/translator/testdata/in/xds-ir/ext-auth-body.yaml @@ -0,0 +1,127 @@ +http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + name: default/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - name: httproute/default/httproute-1/rule/0/match/0/www_foo_com + hostname: www.foo.com + isHTTP2: false + pathMatch: + distinct: false + name: "" + prefix: /foo1 + backendWeights: + invalid: 0 + valid: 0 + destination: + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + security: + extAuth: + name: securitypolicy/default/policy-for-http-route-1 + failOpen: false + grpc: + authority: primary.foo.com + destination: + name: securitypolicy/default/policy-for-http-route-1/default/grpc-backend + settings: + - addressType: FQDN + endpoints: + - host: primary.foo.com + port: 9000 + protocol: GRPC + weight: 1 + headersToExtAuth: + - header1 + - header2 + - name: httproute/default/httproute-1/rule/1/match/0/www_foo_com + hostname: www.foo.com + isHTTP2: false + pathMatch: + distinct: false + name: "" + prefix: /foo2 + backendWeights: + invalid: 0 + valid: 0 + destination: + name: httproute/default/httproute-1/rule/1 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + security: + extAuth: + name: securitypolicy/default/policy-for-http-route-1 + failOpen: false + grpc: + authority: primary.foo.com + destination: + name: securitypolicy/default/policy-for-http-route-1/default/grpc-backend + settings: + - addressType: IP + endpoints: + - host: primary.foo.com + port: 3000 + protocol: GRPC + weight: 1 + headersToExtAuth: + - header1 + - header2 + - name: httproute/default/httproute-2/rule/0/match/0/www_bar_com + hostname: www.bar.com + isHTTP2: false + pathMatch: + distinct: false + name: "" + prefix: /bar + backendWeights: + invalid: 0 + valid: 0 + destination: + name: httproute/default/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + protocol: HTTP + weight: 1 + security: + extAuth: + name: securitypolicy/default/policy-for-gateway-1 + failOpen: true + bodyToExtAuth: + maxRequestBytes: 32768 + allowPartialMessage: false + packAsBytes: true + http: + authority: primary.foo.com + destination: + name: securitypolicy/default/policy-for-gateway-1/envoy-gateway/http-backend + settings: + - addressType: FQDN + endpoints: + - host: primary.foo.com + port: 80 + protocol: HTTP + weight: 1 + headersToBackend: + - header1 + - header2 + path: /auth diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.clusters.yaml new file mode 100644 index 00000000000..79e1aed5ebe --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.clusters.yaml @@ -0,0 +1,115 @@ +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-1/rule/0 + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + name: httproute/default/httproute-1/rule/0 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-1/rule/1 + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + name: httproute/default/httproute-1/rule/1 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + edsClusterConfig: + edsConfig: + ads: {} + resourceApiVersion: V3 + serviceName: httproute/default/httproute-2/rule/0 + ignoreHealthOnHostRemoval: true + lbPolicy: LEAST_REQUEST + name: httproute/default/httproute-2/rule/0 + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + type: EDS +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: securitypolicy/default/policy-for-http-route-1/default/grpc-backend + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: primary.foo.com + portValue: 9000 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: securitypolicy/default/policy-for-http-route-1/default/grpc-backend/backend/0 + name: securitypolicy/default/policy-for-http-route-1/default/grpc-backend + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS + typedExtensionProtocolOptions: + envoy.extensions.upstreams.http.v3.HttpProtocolOptions: + '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions + explicitHttpConfig: + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 +- circuitBreakers: + thresholds: + - maxRetries: 1024 + commonLbConfig: + localityWeightedLbConfig: {} + connectTimeout: 10s + dnsLookupFamily: V4_PREFERRED + dnsRefreshRate: 30s + lbPolicy: LEAST_REQUEST + loadAssignment: + clusterName: securitypolicy/default/policy-for-gateway-1/envoy-gateway/http-backend + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: primary.foo.com + portValue: 80 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: securitypolicy/default/policy-for-gateway-1/envoy-gateway/http-backend/backend/0 + name: securitypolicy/default/policy-for-gateway-1/envoy-gateway/http-backend + outlierDetection: {} + perConnectionBufferLimitBytes: 32768 + respectDnsTtl: true + type: STRICT_DNS diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.endpoints.yaml new file mode 100644 index 00000000000..bf9f0023789 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.endpoints.yaml @@ -0,0 +1,36 @@ +- clusterName: httproute/default/httproute-1/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-1/rule/0/backend/0 +- clusterName: httproute/default/httproute-1/rule/1 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-1/rule/1/backend/0 +- clusterName: httproute/default/httproute-2/rule/0 + endpoints: + - lbEndpoints: + - endpoint: + address: + socketAddress: + address: 7.7.7.7 + portValue: 8080 + loadBalancingWeight: 1 + loadBalancingWeight: 1 + locality: + region: httproute/default/httproute-2/rule/0/backend/0 diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.listeners.yaml new file mode 100644 index 00000000000..f2a6bc10d65 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.listeners.yaml @@ -0,0 +1,73 @@ +- address: + socketAddress: + address: 0.0.0.0 + ipv4Compat: true + portValue: 10080 + defaultFilterChain: + filters: + - name: envoy.filters.network.http_connection_manager + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + commonHttpProtocolOptions: + headersWithUnderscoresAction: REJECT_REQUEST + http2ProtocolOptions: + initialConnectionWindowSize: 1048576 + initialStreamWindowSize: 65536 + maxConcurrentStreams: 100 + httpFilters: + - disabled: true + name: envoy.filters.http.ext_authz/securitypolicy/default/policy-for-http-route-1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz + allowedHeaders: + patterns: + - exact: header1 + ignoreCase: true + - exact: header2 + ignoreCase: true + grpcService: + envoyGrpc: + authority: primary.foo.com + clusterName: securitypolicy/default/policy-for-http-route-1/default/grpc-backend + timeout: 10s + transportApiVersion: V3 + - disabled: true + name: envoy.filters.http.ext_authz/securitypolicy/default/policy-for-gateway-1 + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz + failureModeAllow: true + httpService: + authorizationResponse: + allowedUpstreamHeaders: + patterns: + - exact: header1 + ignoreCase: true + - exact: header2 + ignoreCase: true + pathPrefix: /auth + serverUri: + cluster: securitypolicy/default/policy-for-gateway-1/envoy-gateway/http-backend + timeout: 10s + uri: http://primary.foo.com/auth + transportApiVersion: V3 + withRequestBody: + maxRequestBytes: 32768 + packAsBytes: true + - name: envoy.filters.http.router + typedConfig: + '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + suppressEnvoyHeaders: true + mergeSlashes: true + normalizePath: true + pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT + rds: + configSource: + ads: {} + resourceApiVersion: V3 + routeConfigName: default/gateway-1/http + serverHeaderTransformation: PASS_THROUGH + statPrefix: http-10080 + useRemoteAddress: true + name: default/gateway-1/http + name: default/gateway-1/http + perConnectionBufferLimitBytes: 32768 diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.routes.yaml new file mode 100644 index 00000000000..08edfc3c406 --- /dev/null +++ b/internal/xds/translator/testdata/out/xds-ir/ext-auth-body.routes.yaml @@ -0,0 +1,44 @@ +- ignorePortInHostMatching: true + name: default/gateway-1/http + virtualHosts: + - domains: + - www.foo.com + name: default/gateway-1/http/www_foo_com + routes: + - match: + pathSeparatedPrefix: /foo1 + name: httproute/default/httproute-1/rule/0/match/0/www_foo_com + route: + cluster: httproute/default/httproute-1/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.ext_authz/securitypolicy/default/policy-for-http-route-1: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + config: {} + - match: + pathSeparatedPrefix: /foo2 + name: httproute/default/httproute-1/rule/1/match/0/www_foo_com + route: + cluster: httproute/default/httproute-1/rule/1 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.ext_authz/securitypolicy/default/policy-for-http-route-1: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + config: {} + - domains: + - www.bar.com + name: default/gateway-1/http/www_bar_com + routes: + - match: + pathSeparatedPrefix: /bar + name: httproute/default/httproute-2/rule/0/match/0/www_bar_com + route: + cluster: httproute/default/httproute-2/rule/0 + upgradeConfigs: + - upgradeType: websocket + typedPerFilterConfig: + envoy.filters.http.ext_authz/securitypolicy/default/policy-for-gateway-1: + '@type': type.googleapis.com/envoy.config.route.v3.FilterConfig + config: {} diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index fc7142446c1..25929c76903 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -468,6 +468,22 @@ _Appears in:_ | `users` | _[SecretObjectReference](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.SecretObjectReference)_ | true | The Kubernetes secret which contains the username-password pairs in
htpasswd format, used to verify user credentials in the "Authorization"
header.

This is an Opaque secret. The username-password pairs should be stored in
the key ".htpasswd". As the key name indicates, the value needs to be the
htpasswd format, for example: "user1:\{SHA\}hashed_user1_password".
Right now, only SHA hash algorithm is supported.
Reference to https://httpd.apache.org/docs/2.4/programs/htpasswd.html
for more details.

Note: The secret must be in the same namespace as the SecurityPolicy. | +#### BodyToExtAuth + + + +BodyToExtAuth defines the Body to Ext Auth configuration + +_Appears in:_ +- [ExtAuth](#extauth) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `maxRequestBytes` | _integer_ | true | MaxRequestBytes is the maximum size of a message body that the filter will hold in memory.
Envoy will return HTTP 413 and will not initiate the authorization process when buffer
reaches the number set in this field.
Note that this setting will have precedence over failureModeAllow. | +| `allowPartialMessage` | _boolean_ | true | When AllowPartialMessage is true, Envoy will buffer the message until MaxRequestBytes is reached.
The authorization request will be dispatched and no 413 HTTP error will be returned by the filter. | +| `packAsBytes` | _boolean_ | true | If PackAsBytes is true, the body sent to the external authorization service is set with raw bytes,
it sets the raw_body field of HTTP request attribute context. Otherwise, body will be
filled with UTF-8 string request body.
This field only affects configurations using a grpcService. In configurations that use
an httpService, this has no effect. | + + #### BootstrapType _Underlying type:_ _string_ @@ -1478,6 +1494,7 @@ _Appears in:_ | `grpc` | _[GRPCExtAuthService](#grpcextauthservice)_ | true | GRPC defines the gRPC External Authorization service.
Either GRPCService or HTTPService must be specified,
and only one of them can be provided. | | `http` | _[HTTPExtAuthService](#httpextauthservice)_ | true | HTTP defines the HTTP External Authorization service.
Either GRPCService or HTTPService must be specified,
and only one of them can be provided. | | `headersToExtAuth` | _string array_ | false | HeadersToExtAuth defines the client request headers that will be included
in the request to the external authorization service.
Note: If not specified, the default behavior for gRPC and HTTP external
authorization services is different due to backward compatibility reasons.
All headers will be included in the check request to a gRPC authorization server.
Only the following headers will be included in the check request to an HTTP
authorization server: Host, Method, Path, Content-Length, and Authorization.
And these headers will always be included to the check request to an HTTP
authorization server by default, no matter whether they are specified
in HeadersToExtAuth or not. | +| `bodyToExtAuth` | _[BodyToExtAuth](#bodytoextauth)_ | false | BodyToExtAuth defines the Body to Ext Auth configuration. | | `failOpen` | _boolean_ | false | FailOpen is a switch used to control the behavior when a response from the External Authorization service cannot be obtained.
If FailOpen is set to true, the system allows the traffic to pass through.
Otherwise, if it is set to false or not set (defaulting to false),
the system blocks the traffic and returns a HTTP 5xx error, reflecting a fail-closed approach.
This setting determines whether to prioritize accessibility over strict security in case of authorization service failure. | | `recomputeRoute` | _boolean_ | false | RecomputeRoute clears the route cache and recalculates the routing decision.
This field must be enabled if the headers added or modified by the ExtAuth are used for
route matching decisions. If the recomputation selects a new route, features targeting
the new matched route will be applied. | diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index fc7142446c1..25929c76903 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -468,6 +468,22 @@ _Appears in:_ | `users` | _[SecretObjectReference](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.SecretObjectReference)_ | true | The Kubernetes secret which contains the username-password pairs in
htpasswd format, used to verify user credentials in the "Authorization"
header.

This is an Opaque secret. The username-password pairs should be stored in
the key ".htpasswd". As the key name indicates, the value needs to be the
htpasswd format, for example: "user1:\{SHA\}hashed_user1_password".
Right now, only SHA hash algorithm is supported.
Reference to https://httpd.apache.org/docs/2.4/programs/htpasswd.html
for more details.

Note: The secret must be in the same namespace as the SecurityPolicy. | +#### BodyToExtAuth + + + +BodyToExtAuth defines the Body to Ext Auth configuration + +_Appears in:_ +- [ExtAuth](#extauth) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `maxRequestBytes` | _integer_ | true | MaxRequestBytes is the maximum size of a message body that the filter will hold in memory.
Envoy will return HTTP 413 and will not initiate the authorization process when buffer
reaches the number set in this field.
Note that this setting will have precedence over failureModeAllow. | +| `allowPartialMessage` | _boolean_ | true | When AllowPartialMessage is true, Envoy will buffer the message until MaxRequestBytes is reached.
The authorization request will be dispatched and no 413 HTTP error will be returned by the filter. | +| `packAsBytes` | _boolean_ | true | If PackAsBytes is true, the body sent to the external authorization service is set with raw bytes,
it sets the raw_body field of HTTP request attribute context. Otherwise, body will be
filled with UTF-8 string request body.
This field only affects configurations using a grpcService. In configurations that use
an httpService, this has no effect. | + + #### BootstrapType _Underlying type:_ _string_ @@ -1478,6 +1494,7 @@ _Appears in:_ | `grpc` | _[GRPCExtAuthService](#grpcextauthservice)_ | true | GRPC defines the gRPC External Authorization service.
Either GRPCService or HTTPService must be specified,
and only one of them can be provided. | | `http` | _[HTTPExtAuthService](#httpextauthservice)_ | true | HTTP defines the HTTP External Authorization service.
Either GRPCService or HTTPService must be specified,
and only one of them can be provided. | | `headersToExtAuth` | _string array_ | false | HeadersToExtAuth defines the client request headers that will be included
in the request to the external authorization service.
Note: If not specified, the default behavior for gRPC and HTTP external
authorization services is different due to backward compatibility reasons.
All headers will be included in the check request to a gRPC authorization server.
Only the following headers will be included in the check request to an HTTP
authorization server: Host, Method, Path, Content-Length, and Authorization.
And these headers will always be included to the check request to an HTTP
authorization server by default, no matter whether they are specified
in HeadersToExtAuth or not. | +| `bodyToExtAuth` | _[BodyToExtAuth](#bodytoextauth)_ | false | BodyToExtAuth defines the Body to Ext Auth configuration. | | `failOpen` | _boolean_ | false | FailOpen is a switch used to control the behavior when a response from the External Authorization service cannot be obtained.
If FailOpen is set to true, the system allows the traffic to pass through.
Otherwise, if it is set to false or not set (defaulting to false),
the system blocks the traffic and returns a HTTP 5xx error, reflecting a fail-closed approach.
This setting determines whether to prioritize accessibility over strict security in case of authorization service failure. | | `recomputeRoute` | _boolean_ | false | RecomputeRoute clears the route cache and recalculates the routing decision.
This field must be enabled if the headers added or modified by the ExtAuth are used for
route matching decisions. If the recomputation selects a new route, features targeting
the new matched route will be applied. |