- Correct "proxyway" typo in README - Rewrite design.md to explain SQLite decision over in-memory map, highlighting persistence, ACID transactions, and concurrent read support via WAL mode - Increase audit log rotation limit from 100k to 200k entries
88 lines
3.2 KiB
Markdown
88 lines
3.2 KiB
Markdown
# Auth-proxy Security Model
|
|
|
|
## Authentication flow
|
|
|
|
1. Client request arrives at NGINX.
|
|
2. NGINX sends an internal auth_request subrequest to auth-proxy.
|
|
3. Auth-proxy checks:
|
|
- Is the IP in the permanent whitelist? → Allow.
|
|
- Is the IP in the temporary whitelist and not expired? → Allow.
|
|
- Otherwise → 401 Unauthorized.
|
|
4. NGINX passes the request to the upstream service if auth-proxy returned 200.
|
|
5. NGINX returns 401 to the client if auth-proxy returned 401/403.
|
|
|
|
## IP handling
|
|
|
|
### Permanent whitelist
|
|
|
|
- Stored in SQLite `permanent_whitelist` table.
|
|
- Only single IPs and CIDR ranges (as strings) are supported.
|
|
- Added/removed via the `/api/whitelist/perm` API.
|
|
|
|
### Temporary whitelist
|
|
|
|
- Stored in SQLite `temp_whitelist` table.
|
|
- Entries expire after their TTL.
|
|
- The cleanup goroutine runs every 60 seconds (configurable) to remove expired entries.
|
|
|
|
## API key
|
|
|
|
The API key is the only secret for the /api/* endpoints. It's sent as a bearer token
|
|
in the Authorization header.
|
|
|
|
- **Required.** The service will not start without it.
|
|
- Keep it secret. Don't log it. Don't put it in the URL.
|
|
- Use a strong random string.
|
|
- Rotate it regularly.
|
|
|
|
## Audit log
|
|
|
|
All whitelist operations are logged to the `audit_log` table in SQLite.
|
|
Each entry records:
|
|
|
|
- `action` — what happened (`add_temp`, `delete_temp`, `add_perm`, `delete_perm`, `expire_temp`)
|
|
- `ip` — the affected IP or CIDR range
|
|
- `ttl_seconds` — for temp entries
|
|
- `reason` — the reason provided
|
|
- `api_client_ip` — the IP that made the API call (from NGINX `X-Real-IP`)
|
|
|
|
Retrieve logs via the `/api/logs` endpoint.
|
|
|
|
The audit log is automatically rotated to maintain a maximum of 200,000 entries.
|
|
|
|
## IP validation
|
|
|
|
The `/api/whitelist/temp` and `/api/whitelist/perm` endpoints validate inputs:
|
|
|
|
- `/api/whitelist/temp` requires a valid IP address.
|
|
- `/api/whitelist/perm` requires a valid IP address or CIDR range.
|
|
- Invalid inputs return `400 Bad Request`.
|
|
|
|
## Graceful shutdown
|
|
|
|
The service listens for SIGTERM and SIGINT. On signal:
|
|
|
|
1. Stop accepting new connections.
|
|
2. Close idle connections.
|
|
3. Wait for in-flight requests to complete (up to 30 seconds).
|
|
4. Exit.
|
|
|
|
This ensures Docker deployments can shut down cleanly.
|
|
|
|
## What we don't do
|
|
|
|
- We don't support JWT/OAuth. If you need these, add them later.
|
|
- We don't support session state. The auth decision is made per-request.
|
|
- We don't support rate limiting. Use NGINX's limit_req for that.
|
|
- We don't support IP-based rate limiting. Use NGINX's limit_conn for that.
|
|
- We don't support IPv6. If you need IPv6, add it later.
|
|
- We don't support TLS. The auth endpoint should always be served over TLS.
|
|
- We don't support logging to a file. Logs go to stdout (Docker).
|
|
- We don't support metrics. If you need metrics, add them later.
|
|
- We don't support health checks with Prometheus. The /status endpoint returns a JSON response with uptime, DB status, and whitelist counts.
|
|
- We don't support configuration via a config file. Use environment variables.
|
|
- We don't support multiple domains. The auth-proxy service doesn't care about domains.
|
|
- We don't support HTTP/2. The auth-proxy service uses HTTP/1.1 only.
|
|
- We don't support WebSocket. The auth-proxy service doesn't need WebSocket.
|
|
- We don't support gRPC. The auth-proxy service is a simple REST API.
|