Files
reverse-proxy/tasks/tls/acme-tls.md

3.3 KiB

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
tls/acme-tls Implement ACME certificate provisioning with rustls-acme for automatic Let's Encrypt completed
setup/project-init
moderate high component implementation

Description

Implement ACME mode TLS certificate provisioning using rustls-acme. Each listener in ACME mode creates its own AcmeCertProvider with the listener's domain list, cache directory, and Let's Encrypt directory.

ACME Mode

For each listener in ACME mode:

  1. Create AcmeConfig::new(domains) with the domains from acme_domains
  2. Configure the ACME state machine as a background tokio task per listener
  3. ResolvesServerCertAcme serves the ACME-provisioned certificate
  4. Certificate renewal is automatic (~30 days before expiry)
  5. Cache directory persists ACME state between restarts via DirCache

Certificate Failure Behavior

Scenario Behavior
First start, no cached cert, ACME unreachable Fail to start with clear error
First start, no cached cert, ACME succeeds Normal startup
Start with cached cert, ACME unreachable for renewal Start normally with cached cert, log warn
Renewal failure after startup Continue serving existing cert, log warn
Cached cert expired, renewal fails at startup Fail to start
Cached cert expires during runtime Continue serving expired cert, log error

Key principle: never start without a valid TLS certificate, but always continue serving if a valid cert exists.

ACME Challenge Type

Default is TLS-ALPN-01 since the proxy already listens on port 443. HTTP-01 is available as a fallback via the port 80 redirect listener serving /.well-known/acme-challenge/{token}.

ServerConfig for ACME Mode

Build ServerConfig with with_cert_resolver(), passing the ResolvesServerCertAcme resolver. Register acme-tls/1 in alpn_protocols for TLS-ALPN-01 challenge handling.

Acceptance Criteria

  • ACME state machine runs as background tokio task per listener
  • AcmeConfig created per listener with correct domains, cache dir, and directory
  • ResolvesServerCertAcme integrated into ServerConfig
  • acme-tls/1 ALPN protocol registered for TLS-ALPN-01 challenges
  • Cipher suite and protocol version restrictions applied (same as manual mode)
  • Certificate failure behavior matches the table above
  • Cache directory (DirCache) persists ACME state between restarts
  • Each listener uses its own cache directory to avoid conflicts
  • ACME renewal is automatic, no manual intervention
  • staging vs production ACME directory selection works
  • Unit tests for ACME config construction (mocked, not real Let's Encrypt calls)

References

  • docs/architecture/tls.md — ACME mode, certificate failure behavior, challenge types
  • docs/architecture/decisions/004-rustls-acme.md — ACME-primary rationale
  • docs/architecture/decisions/005-tokio-rustls-direct.md — direct tokio-rustls for ACME integration

Notes

Real ACME integration tests require a network connection to Let's Encrypt staging. For CI, consider mock tests that verify the config and state machine setup without making real ACME requests. Manual testing against staging should be done before deployment.

Summary

To be filled on completion