Skip to content

Add listener-wide TLS version and cipher options - #129

Merged
Shine-neko merged 1 commit into
mainfrom
feat/tls-listener-options
Jul 21, 2026
Merged

Add listener-wide TLS version and cipher options#129
Shine-neko merged 1 commit into
mainfrom
feat/tls-listener-options

Conversation

@Shine-neko

Copy link
Copy Markdown
Contributor

Exposes TLS protocol versions and cipher selection on the HTTPS listener, under proxy.https.tls.

proxy:
  https:
    listen_address: 443
    tls:
      min_version: "1.3"        # refuse TLS 1.2 entirely
      max_version: "1.3"        # optional upper bound (>= min_version)
      ciphers:                  # rustls names, both TLS 1.2 and 1.3
        - "TLS13_AES_256_GCM_SHA384"
        - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"

All fields optional; each absent one keeps Sōzu's default.

Scope: listener-wide, not per-route

The board item was "Per-router TLS options", but Sōzu applies TLS versions and ciphers at bind time — they're a property of the listener (the address:port), not the frontend/route. RequestHttpFrontend carries no TLS fields. So per-route TLS options are not possible on this proxy; these are listener-wide, shared by every hostname on the HTTPS port. That covers the actual need (hardening: refuse TLS 1.2, restrict ciphers). The docs say so plainly.

Details worth noting

  • Versions are a list, not a range, in Sōzu. min/max are expanded into the enabled versions they span (1.2 and 1.3 only). max_version < min_version fails startup rather than emptying the list.
  • One ciphers list, rustls names. Sōzu's worker reads ciphers only from its cipher_list field (its cipher_suites field is never consulted), using rustls names for both TLS 1.2 and 1.3. So there's a single ciphers field, not two. Listing only 1.2 suites leaves no 1.3 suite enabled — the doc calls this out.
  • Invalid config fails startup, it isn't silently ignored: an unknown version, an inverted range, or an all-unrecognised cipher list aborts before the listener is created.

Verified

Unit tests cover the version expansion (each min/max combination), the inverted-range and unknown-version rejections, and the cipher forwarding. An e2e test sets min_version: "1.3" on the listener and asserts a TLS 1.2 client is rejected at the handshake while a 1.3 client passes version negotiation.

Review

Codex caught two cipher bugs in the first pass — the dead cipher_suites field and OpenSSL-vs-rustls cipher naming — both fixed (single ciphers field, rustls names). Re-reviewed clean.

@Shine-neko
Shine-neko merged commit 12fa4aa into main Jul 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant