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.
CombinedValidationContextand 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.