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.
This commit is contained in:
67
docs/architecture/decisions/004-rustls-acme.md
Normal file
67
docs/architecture/decisions/004-rustls-acme.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user