# Envoy extension

Synapse implements the [Envoy external authorization API](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_authz_filter) natively and its behaviour can be configured either declratively or programmatically.

A typical Envoy configuration to use Synapse as the external authorization service is as follows.

## Envoy configuration

```yaml
static_resources:
  listeners:
    - name: listener_0
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 8080
      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
                http_filters:
                  - name: envoy.filters.http.ext_authz
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
                      transport_api_version: V3
                      grpc_service:
                        envoy_grpc:
                          cluster_name: synapse
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
                route_config:
                  ...

clusters:
    - name: synapse
      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: synapse
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: 127.0.0.1
                      port_value: 3594

transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
          sni: synapse.localhost
          common_tls_context:
            validation_context:
              trust_chain_verification: ACCEPT_UNTRUSTED
```

## Declarative mapping

Map Envoy `Check` requests to Cerbos `CheckResources` and back using CEL expressions.

```yaml
extensions:
  envoyExternalAuthz:
    enabled: true
    mapping:
      request:
        requestID: 'request.attributes.request.http.headers["x-request-id"]'
        principal:
          id: 'request.attributes.request.http.headers["x-user-id"]'
          roles: '[
            "user"
          ]'
        resource:
          id: '"foo"'
          kind: '"request"'
        action: 'request.attributes.request.http.method'
```

|     |     |
| --- | --- |
| **1** | Enable the Envoy `Check` endpoint on the server |
| **2** | Declarative mapping of request and response. See below for mapping reference. |

### Mapping reference

|     |     |
| --- | --- |
|  | Documentation about Cerbos request and response formats can be found at [https://docs.cerbos.dev/cerbos/latest/api/#_request_and_response_formats](https://docs.cerbos.dev/cerbos/latest/api/#_request_and_response_formats). For Envoy `Check` request and response formats, refer to [https://buf.build/envoyproxy/envoy/docs/main:envoy.service.auth.v3#envoy.service.auth.v3.CheckRequest](https://buf.build/envoyproxy/envoy/docs/main:envoy.service.auth.v3#envoy.service.auth.v3.CheckRequest). |

- `request` (required):

- `requestID`: a CEL expression returning a string.

- `principal` (required):

- `id` (required): a CEL expression returning a string.

- `roles` (required): a CEL expression returning a list of strings, or a list of CEL expressions each returning a string.

- `attr`: a CEL expression returning a map of strings to values, or a map of strings to CEL expressions each returning a value.

- `policyVersion`: a CEL expression returning a string.

- `scope`: a CEL expression returning a string.

- `resource` (required):

- `kind` (required): a CEL expression returning a string.

- `id` (required): a CEL expression returning a string.

- `attr`: a CEL expression returning a map of strings to values, or a map of strings to CEL expressions each returning a value.

- `policyVersion`: a CEL expression returning a string.

- `scope`: a CEL expression returning a string.

- `action` (required): a CEL expression returning a string.

- `auxData`:

- `jwt`:

- `token`: a CEL expression returning a string.

- `keySetID`: a CEL expression returning a string.

- `response`:

- `status`: a CEL expression returning an HTTP status code as an integer. Defaults to 200 when allowed and 403 when denied.

- `headers`: a CEL expression returning a map of strings to strings, or a map of strings to CEL expressions each returning a string.

- `body`: a CEL expression returning bytes or a string.

Request expressions have access to the incoming HTTP request in the CEL variable `request`, which has the following fields:

- `method`: the request’s HTTP method as an uppercase string.

- `header`: map of HTTP request headers. Keys are header names in [canonical form](https://pkg.go.dev/net/http#CanonicalHeaderKey) and values are strings (comma-separated when multiple headers with the same name are present in the request).

- `headers`: map of HTTP request headers. Keys are header names in [canonical form](https://pkg.go.dev/net/http#CanonicalHeaderKey) and values are lists of strings.

- `body`: object with the following fields:

- `bytes`: the raw request body

- `text`: the request body as a string

- `json`: the JSON-decoded request body

Response expressions have access to the `CheckResources` result in the CEL variable `check` which has the following fields:

- `requestId`, `principal`, `resource`, and `action`: the inputs produced by the request expressions.

- `cerbosCallId`: the ID for audit logging as a string.

- `allow`: whether the action is allowed as a boolean.

- `outputs`: the output from the policy as a map of source (`policy-id#rule-name`) to value.

- `validationErrors`: errors encountered when validating the principal and resource against the corresponding schemas as a list of [`cerbos.schema.v1.ValidationError` messages](https://github.com/cerbos/cerbos/blob/main/api/public/cerbos/schema/v1/schema.proto).

Using the YAML scalar block syntax `>` for CEL expressions is recommended to avoid quoting issues. `action: "view"` would be interpreted as the CEL expression `view` (which would fail to compile because a variable named `view` is not defined), when the desired setting was the CEL expression `"view"` (which just returns the intended string literal).

## Minimal configuration

## Customizing the response

```yaml
extensions:
  envoyExternalAuthz:
    enabled: true
    mapping:
      request:
        requestID: 'request.attributes.request.http.headers["x-request-id"]'
        principal:
          id: 'request.attributes.request.http.headers["x-user-id"]'
          roles: '[
            "user"
          ]'
        resource:
          id: '"foo"'
          kind: '"request"'
        action: 'request.attributes.request.http.method'
      response: >
        check.allow ? {"status": {"code": google.rpc.Code.OK }} : {
            "status": {"code": google.rpc.Code.OK },
            "deniedResponse": {
               "status": {"code": 401 },
               "body": json.encode(check.outputs["resource.example.v1#route"].body)
             }
        }
```

## Programmatic mapping

```yaml
extensions:
  envoyExternalAuthz:
    enabled: true
    extension:
      extensionURL: /extensions/envoy.wasm
      configuration:
        environment: staging
```

|     |     |
| --- | --- |
| **1** | Enable the Envoy `Check` endpoint. |
| **2** | URL to fetch the extension from. See [extension URL format](https://docs.cerbos.dev/synapse/latest/extensions/url-format) for more information. |
| **3** | Configuration values needed by the extension. [Optional] |

### Building an Envoy extension

See [Building custom Synapse extensions](https://docs.cerbos.dev/synapse/latest/extensions/building).
