Files
reverse-proxy/docs/architecture/decisions/004-rustls-acme.md
glm-5.1 8ee6284b62 Add architecture specification for Rust/axum reverse proxy
Phase 1 architecture docs covering proxy handler, TLS termination (ACME +
manual), TOML config with static/dynamic split (ArcSwap), and operations
(rate limiting, logging, health check, systemd, graceful shutdown).

Nine ADRs documenting key decisions: Rust/axum, custom proxy handler,
TOML config, rustls-acme for cert management, tokio-rustls direct,
token bucket rate limiting, custom log format for fail2ban,
static/dynamic config split, and signal handling strategy.

Includes threat landscape research documenting the nginx CVEs motivating
this project.
2026-06-11 07:25:50 +00:00

67 lines
2.5 KiB
Markdown

# ADR-004: ACME-Primary Certificate Management
## Status
Accepted
## Context
The proxy needs TLS certificates for HTTPS. Two approaches are available:
1. **certbot (external ACME client)**: Run certbot as a cron job or systemd
timer to obtain and renew certificates. The proxy loads certificates from
files on disk. Renewal requires either SIGHUP/restart or inotify file
watching to pick up new certs.
2. **rustls-acme (built-in ACME client)**: The proxy handles ACME
certificate provisioning and renewal internally as a background task. No
external certbot dependency. The `ResolvesServerCertAcme` cert resolver
automatically serves the correct certificate and updates when renewed.
The alknet project has successfully implemented the rustls-acme approach, and
its patterns are directly reusable.
## Decision
Use `rustls-acme` as the primary certificate management mode, with manual
certificate paths as a fallback mode for testing, self-signed certs, and
corporate CA environments.
## Rationale
- **Eliminates certbot dependency**: No external cron job, no deploy hooks, no
certbot package to install and maintain. The proxy is self-contained.
- **Automatic renewal**: `rustls-acme` runs as a background tokio task that
handles certificate provisioning and renewal automatically (~30 days before
expiry).
- **No restart needed**: When `rustls-acme` provisions a new certificate, the
`ResolvesServerCertAcme` resolver updates atomically. No SIGHUP, no restart,
no file watching.
- **Proven pattern**: alknet uses the same approach successfully.
- **Cache persistence**: `DirCache` persists ACME state between restarts,
avoiding re-provisioning.
- **Fallback mode**: Manual cert paths are still supported for environments
where ACME is not possible.
## Consequences
**Positive:**
- Single binary deployment (no certbot dependency)
- Zero-downtime certificate renewal
- Simpler operational model (no certbot cron, no deploy hooks)
- Proven in alknet
**Negative:**
- `rustls-acme` is an additional dependency
- ACME challenges require either port 80 (HTTP-01) or TLS-ALPN-01 on port 443,
which our proxy already listens on
- Less control over certificate issuance compared to certbot (e.g., no DNS-01
challenge support, though rustls-acme supports TLS-ALPN-01 which is sufficient
for our use case)
- Manual mode requires restart for cert changes (acceptable for fallback)
## References
- [tls.md](../tls.md)
- alknet ADR-008: ACME/Let's Encrypt decision
- `rustls-acme` crate: https://github.com/FlorianUekermann/rustls-acme