External Authorization
External authorization architecture overview
This filter should be configured with the type URL
type.googleapis.com/envoy.extensions.filters.network.ext_authz.v3.ExtAuthz.
The external authorization network filter calls an external authorization service to check if the incoming request is authorized or not. If the request is deemed unauthorized by the network filter then the connection will be closed, unless shadow mode is enabled.
Tip
It is recommended that this filter is configured first in the filter chain so that requests are authorized prior to rest of the filters processing the request.
The content of the request that are passed to an authorization service is specified by CheckRequest.
The network filter, gRPC service, can be configured as follows. You can see all the configuration options at Network filter.
Example
A sample filter configuration could be:
filters:
- name: envoy.filters.network.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.ext_authz.v3.ExtAuthz
stat_prefix: ext_authz
grpc_service:
envoy_grpc:
cluster_name: ext-authz
include_peer_certificate: true
# Optional: Send TLS alert on denial for better client diagnostics.
send_tls_alert_on_denial: true
clusters:
- name: ext-authz
type: static
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: {}
load_assignment:
cluster_name: ext-authz
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 10003
A sample request body to the specified auth service looks like
{
"source":{
"address":{
"socket_address":{
"address": "172.17.0.1",
"port_value": 56746
}
}
}
"destination":{
"service": "www.bing.com",
"address":{
"socket_address": {
"address": "127.0.0.1",
"port_value": 10003
}
}
}
}
Statistics
The network filter outputs statistics in the config.ext_authz. namespace.
Name |
Type |
Description |
|---|---|---|
total |
Counter |
Total responses from the filter. |
error |
Counter |
Total errors contacting the external service. |
denied |
Counter |
Total responses from the authorizations service that were to deny the traffic. |
disabled |
Counter |
Total requests that are allowed without calling external services due to the filter is disabled. |
failure_mode_allowed |
Counter |
Total requests that were error(s) but were allowed through because of failure_mode_allow set to true. |
ok |
Counter |
Total responses from the authorization service that were to allow the traffic. |
cx_closed |
Counter |
Total connections that were closed. |
active |
Gauge |
Total currently active requests in transit to the authorization service. |
See Shadow Mode for how these counters behave when the filter is configured not to close the connection.
TLS Alert on Denial
When send_tls_alert_on_denial
is set to true, the filter will send a TLS access_denied(49) alert before closing the connection
when authorization is denied. This improves debuggability by providing TLS clients with explicit information
about why the connection was closed, rather than experiencing a silent connection closure.
The TLS alert is only sent when:
The connection is using TLS/SSL.
Authorization is denied either due to explicit denial or error with
failure_mode_allowset tofalse.
For non-TLS connections, the connection is closed without sending an alert.
Shadow Mode
When shadow_mode
is set to true, the filter still calls the authorization service but never closes the connection.
The decision is written to the connection’s FilterState under envoy.filters.network.ext_authz, so a
subsequent filter can read it and decide whether to enforce it. This allows a new authorization
service to run alongside the enforcing one and have its decisions compared before it is trusted to
reject traffic.
Attention
Shadow mode disables enforcement in this filter. Traffic is allowed whatever the authorization service returns, so a subsequent filter has to read the decision and close the connection for a denial to take effect.
The denied and error counters are incremented as usual, while cx_closed is not, since
no connection is closed. failure_mode_allowed is not incremented either, because traffic is
allowed by shadow mode rather than by failure_mode_allow. No TLS alert is sent, whatever
send_tls_alert_on_denial is
set to.
The recorded decision exposes a check_result field (OK, DENIED or ERROR) and, on a
denial, the status_code returned by the authorization service. It is available in access logs,
either as JSON or field by field:
%FILTER_STATE(envoy.filters.network.ext_authz:PLAIN)%
%FILTER_STATE(envoy.filters.network.ext_authz:FIELD:check_result)%
Usage with TCP Proxy
When using the External Authorization network filter with the TCP proxy filter, the default behavior establishes upstream connections immediately when a downstream connection is accepted. This means the upstream connection may be established before authorization completes.
To ensure upstream connections are only established after authorization succeeds, configure the TCP proxy filter to delay upstream connection establishment using upstream_connect_mode.
Example configuration:
filter_chains:
- filters:
- name: envoy.filters.network.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.ext_authz.v3.ExtAuthz
stat_prefix: ext_authz
grpc_service:
envoy_grpc:
cluster_name: ext-authz
include_peer_certificate: true
- name: envoy.filters.network.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: tcp
cluster: backend
upstream_connect_mode: ON_DOWNSTREAM_DATA
max_early_data_bytes: 8192
In this configuration:
upstream_connect_mode: ON_DOWNSTREAM_DATAdelays the upstream connection until data is received from the downstream client.The External Authorization check happens when data arrives, before the TCP proxy establishes the upstream connection.
If authorization is denied, the connection is closed without ever connecting to the upstream.
Alternatively, use ON_DOWNSTREAM_TLS_HANDSHAKE to wait for the TLS handshake to complete, which
provides access to client certificates when using include_peer_certificate.
Attention
The ON_DOWNSTREAM_DATA mode is not suitable for server-first protocols where the server sends
the initial greeting (e.g., SMTP, MySQL, POP3). For such protocols, use the default IMMEDIATE
mode and accept that upstream connections may be established before authorization completes.
Metadata Context
The network filter can be configured to pass specific metadata to the authorization service by using metadata_context_namespaces and typed_metadata_context_namespaces.
When configured, the filter will collect metadata from the connection’s dynamic metadata that matches the specified namespaces and include it in the CheckRequest sent to the authorization service. This is useful for passing information from other network-layer or listener filters to the authorization service for decision making.
For example, if the proxy protocol listener filter extracts TLV metadata from PROXY protocol headers, you can pass that metadata to the authorization service:
filters:
- name: envoy.filters.network.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.ext_authz.v3.ExtAuthz
stat_prefix: ext_authz
grpc_service:
envoy_grpc:
cluster_name: ext-authz
metadata_context_namespaces:
- envoy.filters.listener.proxy_protocol
typed_metadata_context_namespaces:
- envoy.filters.listener.proxy_protocol
The metadata_context_namespaces field passes untyped metadata as protobuf::Struct, while
typed_metadata_context_namespaces passes typed metadata as protobuf::Any for type-safe
unpacking when both Envoy and the authorization server share the protobuf message definition.
Dynamic Metadata
The External Authorization filter emits dynamic metadata as an opaque google.protobuf.Struct
only when the gRPC authorization server returns a CheckResponse with a non-empty dynamic_metadata field.