Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add body to ext auth #4671

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions api/v1alpha1/ext_auth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
AurelienPillevesse marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment about the maximum body size supported for this option? If I understand the docs correctly, when the body size is greater than 1024, the request would be blocked with status code 413 instead of being sent to ext-auth.

Copy link
Author

@AurelienPillevesse AurelienPillevesse Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding, the maximum body size will not be take into account because in the BufferSettings object, AllowPartialMessage is hardcoded to false for the moment (so I put 1024 as random value).

extauthv3.BufferSettings{
	MaxRequestBytes:     1024,
	AllowPartialMessage: false,
	PackAsBytes:         false,
}

In my opinion, it's better the release this feature like that (so basic feature first) and in next iteration for this feature, allow the possibility for partial message.

So for the moment, all the body will be sent.

https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto#extensions-filters-http-ext-authz-v3-buffersettings

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm agree with that if the AllowPartialMessage values is false by default I think we can open another PR about that. This feature is very important because now we cannot add a body.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the following config:

static_resources:
  listeners:
    - address:
        socket_address:
          address: 0.0.0.0
          port_value: 8000
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                codec_type: AUTO
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: upstream
                      domains:
                        - "*"
                      typed_per_filter_config:
                        envoy.filters.http.ext_authz:
                          "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
                          check_settings:
                            with_request_body:
                              max_request_bytes: 1
                              allow_partial_message: false
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: upstream-service
                http_filters:
                  - name: envoy.filters.http.ext_authz
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
                      http_service:
                        server_uri:
                          uri: ext_authz
                          cluster: ext_authz-http-service
                          timeout: 0.250s
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
    - name: upstream-service
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: upstream-service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: upstream-service
                      port_value: 8080

    - name: ext_authz-http-service
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: ext_authz-http-service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ext_authz-http-service
                      port_value: 9002

Specifying a body large enough will lead to request being rejected with 413 without being inspected by the ext-auth server.

curl -I http://localhost:8000
HTTP/1.1 403 Forbidden
date: Fri, 22 Nov 2024 15:30:44 GMT
server: envoy
content-length: 0

No body: rejected due to fail closed (ext auth doesn't really exist in this example).

curl -X POST http://localhost:8000 -d "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
[...]
< HTTP/1.1 413 Payload Too Large
< content-length: 17
< content-type: text/plain
< date: Fri, 22 Nov 2024 15:33:56 GMT
< server: envoy
< connection: close
Payload Too Large

Large body: rejected before being processed by ext auth.


// 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),
Expand Down Expand Up @@ -85,3 +89,6 @@ type HTTPExtAuthService struct {
// +optional
HeadersToBackend []string `json:"headersToBackend,omitempty"`
}

// BodyToExtAuth defines the Body to Ext Auth configuration
type BodyToExtAuth struct{}
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

5 changes: 5 additions & 0 deletions internal/gatewayapi/securitypolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,11 @@ func (t *Translator) buildExtAuth(
Authority: authority,
}
}

if policy.Spec.ExtAuth.BodyToExtAuth != nil {
extAuth.BodyToExtAuth = &ir.BodyToExtAuth{}
}

return extAuth, nil
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Loading