Skip to content

Terminate TLS on listeners, require client certificates, originate TLS to upstreams, and select certificate chains by SNI.

TLS in Arion is configured through transport sockets: a DownstreamTlsContext on a filter chain terminates TLS for incoming connections, and an UpstreamTlsContext on a cluster originates TLS to your backends. Use it whenever traffic crosses a network you do not trust — and add client-certificate verification (mTLS) when you also need to know who is connecting.

Terminate TLS on a listener

Attach a transport socket to a filter chain and give it a certificate chain and private key. Both accept a file path (filename), inline_string, inline_bytes, or environment_variable.

filter_chains:
  - name: https
    filters:
      # http_connection_manager, router, ...
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
        common_tls_context:
          tls_certificates:
            - certificate_chain: { filename: certs/example.com.cert.pem }
              private_key: { filename: certs/example.com.key.pem }

Instead of inlining the certificate you can reference a named secret with tls_certificate_sds_secret_configs — see secrets and rotation.

Server certificates must carry a DNS name in their Subject Alternative Name extension. Arion reads the serving name from the SAN to pick a certificate during the SNI handshake; a certificate without a DNS SAN is rejected with secret doesn't contain server name. See troubleshooting.

Require client certificates (mTLS)

Add a validation_context with the CA that signs your clients, and set require_client_certificate. Without that flag the client certificate is verified only if one is presented.

typed_config:
  "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
  require_client_certificate: true
  common_tls_context:
    tls_certificates:
      - certificate_chain: { filename: certs/example.com.cert.pem }
        private_key: { filename: certs/example.com.key.pem }
    validation_context:
      trusted_ca: { filename: certs/ca.cert.pem }

Pin TLS versions

Arion negotiates TLS 1.2 or 1.3. The default minimum is 1.2; configurations asking for 1.0 or 1.1 are refused at startup.

common_tls_context:
  tls_params:
    tls_minimum_protocol_version: TLSv1_3

tls_maximum_protocol_version works the same way and defaults to the newest supported version.

Originate TLS to an upstream

Put an UpstreamTlsContext on the cluster. sni is required — Arion always sends it and uses it to verify the upstream certificate against the trusted_ca.

clusters:
  - name: api
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        sni: api.example.com
        common_tls_context:
          validation_context:
            trusted_ca: { filename: /etc/ssl/certs/ca-certificates.crt }

For development against self-signed backends, trust_chain_verification: ACCEPT_UNTRUSTED disables verification (Arion logs a warning). For upstream mTLS, add one client certificate under tls_certificates — a cluster accepts at most one.

Select a chain by SNI

Different hostnames on one port can get different certificates and filters. Add the TLS inspector so the chain is chosen from the ClientHello, then match with server_names:

listener_filters:
  - name: tls_inspector
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains:
  - name: api
    filter_chain_match:
      server_names: [api.example.com]
    # filters + transport_socket with the api.example.com certificate
  - name: fallback
    # no server_names: matches everything else

The most specific match wins: api.example.com beats *.example.com, which beats a chain with no server_names. Wildcards may only appear as a leading *. label; a bare "*" entry is refused. A single chain can also hold several certificates, and Arion picks one by matching SNI against each certificate's SAN.

Verify

curl -s http://127.0.0.1:9901/certs

The admin endpoint lists each loaded certificate with its SANs, validity window and days until expiration. To exercise the handshake end to end:

curl --cacert certs/ca.cert.pem --resolve example.com:8443:127.0.0.1 https://example.com:8443/

Limits

  • TLS 1.2 is the floor; 1.0 and 1.1 are rejected.
  • Cipher suites, ECDH curves, signature algorithms and ALPN lists are not configurable; configs that set them are refused.
  • The validation context checks the trust chain only: SAN matching, SPKI/hash pinning, CRLs and expired-certificate allowances are not supported.
  • CombinedValidationContext and certificate providers are not supported; use inline validation or an SDS reference.
  • full_scan_certs_on_sni_mismatch, session ticket keys and stateful session resumption options are not supported.

Continue

Start typing to search the site.

↑ ↓ to move Enter to open Esc to close