- Migrate IP-based temporary whitelisting from file to SQLite storage - Add REST API endpoints for managing temporary and permanent whitelists - Create `.env.example` with required environment variables - Document API endpoints in README.md and docs/api.md - Add new dependency `modernc.org/sqlite` for SQLite support - Update deployment and security documentation
121 lines
2.6 KiB
Markdown
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-gate 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.
|