Files
auth-proxy/docs/design.md

121 lines
2.6 KiB
Markdown

# Design Decisions
## Why Go?
- Single binary — no external dependencies.
- Small memory footprint — ~10 MB for a typical deployment.
- Fast startup — < 1 second.
- Simple to compile and distribute.
## Why not NGINX auth_basic?
NGINX's auth_basic is simpler but doesn't support:
- IP whitelisting (you'd need the geo module or a third-party module).
- Temporary whitelisting (requires config reload).
- API-based management.
Our auth-proxy service fills these gaps while keeping the architecture simple.
## Why not Authelia?
Authelia is a full-featured self-hosted auth portal with:
- SSO integration
- 2FA
- MFA
- LDAP
- OIDC
But for our use case:
- It's heavier (requires Postgres, Redis, etc.).
- It doesn't support temporary whitelisting out of the box.
- It requires a login portal.
We wanted something simpler.
## Why not Authentik?
Authentik is a full-featured identity provider with:
- SSO
- MFA
- OIDC
- LDAP
- SCIM
But it's too heavy for our use case. We just need IP whitelisting + Basic Auth.
## Why not Pomerium?
Pomerium is a zero-trust proxy with:
- OIDC
- MFA
- IP-based access control
- Policy engine
But it's overkill for our use case. We just need IP whitelisting + Basic Auth.
## Why not oauth2-proxy?
oauth2-proxy is a reverse proxy with:
- OIDC
- SSO
- MFA
But it's designed for OIDC, not for IP whitelisting.
## Why not a custom script?
A shell script would work but:
- No type safety.
- No built-in HTTP server (need to use Python/Node).
- No standard library (need to install packages).
- No built-in JSON encoding/decoding.
Go's standard library is sufficient for our needs.
## Why SQLite?
SQLite provides:
- Single file — no external dependencies.
- Persistence across restarts.
- ACID transactions.
- Simple WAL mode for concurrent reads.
For a handful of IPs (dozens at most), SQLite is:
- Simple to deploy.
- Fast (single-file, no network).
- No external dependencies.
## Why in-memory temporary whitelist?
For a handful of IPs (dozens at most), an in-memory map is:
- Simple to implement.
- Fast (O(1) lookup).
- No external dependencies.
If you need persistence across restarts, add a disk-backed store later.
## Why a background cleanup goroutine?
Checking expiry on every request adds latency (two map lookups per request).
The cleanup goroutine is a one-time cost that keeps the hot path fast.
## Why poll instead of inotify?
Polling is simpler and works inside Docker containers where inotify
may not be available (no host filesystem access).
## Why not use Redis?
For our use case, Redis is overkill.
We chose an in-memory map + periodic cleanup.