refactor: reorganize project into src layout and update API documentation
Update project structure to use a src/ directory layout and improve documentation across multiple files. - Update README.md build command to use ./src - Add directory structure documentation - Update status endpoint to include DB health status - Add pagination support (limit/offset) to whitelist list endpoints - Document new query parameters with examples - Update deployment guide to mark API token as required - Add testing instructions - Clarify audit log rotation in design documentation
This commit is contained in:
25
README.md
25
README.md
@@ -18,7 +18,7 @@ On 401/403 NGINX returns the response to the client. Whitelisted IPs never see a
|
|||||||
## Build
|
## Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build -o auth-proxy .
|
go build -o auth-proxy ./src
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
@@ -42,6 +42,27 @@ vim .env
|
|||||||
./auth-proxy
|
./auth-proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Directory structure
|
||||||
|
|
||||||
|
```
|
||||||
|
├── src/
|
||||||
|
│ ├── main.go — entry point
|
||||||
|
│ ├── auth.go — HTTP handlers
|
||||||
|
│ ├── db.go — database operations
|
||||||
|
│ ├── config.go — configuration
|
||||||
|
│ ├── cleanup.go — cleanup goroutine
|
||||||
|
│ └── auth_test.go — unit tests
|
||||||
|
├── docs/
|
||||||
|
│ ├── api.md
|
||||||
|
│ ├── deploy.md
|
||||||
|
│ ├── design.md
|
||||||
|
│ └── security.md
|
||||||
|
├── Dockerfile
|
||||||
|
├── docker-compose.yml
|
||||||
|
├── go.mod
|
||||||
|
└── openapi.yaml
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
The API requires a bearer token set via `AUTH_PROXY_API_TOKEN`. All endpoints return `401 Unauthorized` if the token is missing or invalid.
|
The API requires a bearer token set via `AUTH_PROXY_API_TOKEN`. All endpoints return `401 Unauthorized` if the token is missing or invalid.
|
||||||
@@ -55,7 +76,7 @@ The API requires a bearer token set via `AUTH_PROXY_API_TOKEN`. All endpoints re
|
|||||||
| GET | `/api/whitelist/perm/list` | List active permanent entries |
|
| GET | `/api/whitelist/perm/list` | List active permanent entries |
|
||||||
| DELETE | `/api/whitelist/perm/{entry}` | Remove a permanent entry |
|
| DELETE | `/api/whitelist/perm/{entry}` | Remove a permanent entry |
|
||||||
| GET | `/api/logs` | Retrieve audit log entries |
|
| GET | `/api/logs` | Retrieve audit log entries |
|
||||||
| GET | `/status` | Health check |
|
| GET | `/status` | Health check with DB status |
|
||||||
|
|
||||||
See `docs/api.md` for full API reference.
|
See `docs/api.md` for full API reference.
|
||||||
|
|
||||||
|
|||||||
42
docs/api.md
42
docs/api.md
@@ -35,6 +35,13 @@ List all currently active temporary whitelisted IPs.
|
|||||||
|
|
||||||
**Authorization:** Bearer `{API_TOKEN}`
|
**Authorization:** Bearer `{API_TOKEN}`
|
||||||
|
|
||||||
|
**Query parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|--------|----------|---------|---------------------------------------------------------------------|
|
||||||
|
| `limit` | int | No | 200 | Number of entries to return (max 1000) |
|
||||||
|
| `offset` | int | No | 0 | Number of entries to skip |
|
||||||
|
|
||||||
**Response body:**
|
**Response body:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -47,6 +54,13 @@ List all currently active temporary whitelisted IPs.
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET "http://127.0.0.1:8080/api/whitelist/temp/list?limit=50&offset=0" \
|
||||||
|
-H "Authorization: Bearer CHANGE_ME"
|
||||||
|
```
|
||||||
|
|
||||||
### DELETE /api/whitelist/temp/{ip}
|
### DELETE /api/whitelist/temp/{ip}
|
||||||
|
|
||||||
Remove a temporary whitelisted IP.
|
Remove a temporary whitelisted IP.
|
||||||
@@ -86,6 +100,13 @@ List all currently active permanent whitelisted IPs.
|
|||||||
|
|
||||||
**Authorization:** Bearer `{API_TOKEN}`
|
**Authorization:** Bearer `{API_TOKEN}`
|
||||||
|
|
||||||
|
**Query parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Required | Default | Description |
|
||||||
|
|-----------|--------|----------|---------|---------------------------------------------------------------------|
|
||||||
|
| `limit` | int | No | 200 | Number of entries to return (max 1000) |
|
||||||
|
| `offset` | int | No | 0 | Number of entries to skip |
|
||||||
|
|
||||||
**Response body:**
|
**Response body:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -96,6 +117,13 @@ List all currently active permanent whitelisted IPs.
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET "http://127.0.0.1:8080/api/whitelist/perm/list?limit=50&offset=0" \
|
||||||
|
-H "Authorization: Bearer CHANGE_ME"
|
||||||
|
```
|
||||||
|
|
||||||
### DELETE /api/whitelist/perm/{entry}
|
### DELETE /api/whitelist/perm/{entry}
|
||||||
|
|
||||||
Remove a permanent whitelisted IP or CIDR range.
|
Remove a permanent whitelisted IP or CIDR range.
|
||||||
@@ -149,9 +177,19 @@ The NGINX auth_request endpoint. Do NOT call this directly.
|
|||||||
|
|
||||||
### GET /status
|
### GET /status
|
||||||
|
|
||||||
Health check.
|
Health check with DB status.
|
||||||
|
|
||||||
**Response:** 200 `ok`
|
**Response:** 200 `application/json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"uptime": "1h30m0s",
|
||||||
|
"perm_whitelist_count": 15,
|
||||||
|
"temp_whitelist_count": 3,
|
||||||
|
"db_ok": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Security notes
|
## Security notes
|
||||||
|
|
||||||
|
|||||||
@@ -83,11 +83,17 @@ nginx -s reload
|
|||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
|----------|-------------|---------|
|
|----------|-------------|---------|
|
||||||
| AUTH_PROXY_PORT | HTTP listen port | 8080 |
|
| AUTH_PROXY_PORT | HTTP listen port | 8080 |
|
||||||
| AUTH_PROXY_API_TOKEN | API bearer token | (none) |
|
| AUTH_PROXY_API_TOKEN | API bearer token | (required) |
|
||||||
| AUTH_PROXY_DB_PATH | SQLite database path | /data/auth-proxy.db |
|
| AUTH_PROXY_DB_PATH | SQLite database path | /data/auth-proxy.db |
|
||||||
| DATA_DIR | Data directory | /data |
|
| DATA_DIR | Data directory | /data |
|
||||||
| CLEANUP_INTERVAL | Cleanup interval | 60s |
|
| CLEANUP_INTERVAL | Cleanup interval | 60s |
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test ./src/...
|
||||||
|
```
|
||||||
|
|
||||||
## Graceful shutdown
|
## Graceful shutdown
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -106,8 +106,9 @@ If you need persistence across restarts, add a disk-backed store later.
|
|||||||
|
|
||||||
## Why a background cleanup goroutine?
|
## Why a background cleanup goroutine?
|
||||||
|
|
||||||
Checking expiry on every request adds latency (two map lookups per request).
|
The cleanup goroutine removes expired temporary entries and rotates the audit log.
|
||||||
The cleanup goroutine is a one-time cost that keeps the hot path fast.
|
It runs every 60 seconds (configurable). The audit log rotation keeps the database
|
||||||
|
from growing indefinitely — it maintains a maximum of 100,000 entries.
|
||||||
|
|
||||||
## Why poll instead of inotify?
|
## Why poll instead of inotify?
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
The API key is the only secret for the /api/* endpoints. It's sent as a bearer token
|
The API key is the only secret for the /api/* endpoints. It's sent as a bearer token
|
||||||
in the Authorization header.
|
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.
|
- Keep it secret. Don't log it. Don't put it in the URL.
|
||||||
- Use a strong random string.
|
- Use a strong random string.
|
||||||
- Rotate it regularly.
|
- Rotate it regularly.
|
||||||
@@ -43,10 +44,20 @@ Each entry records:
|
|||||||
- `ip` or `cidr` — the affected IP or CIDR
|
- `ip` or `cidr` — the affected IP or CIDR
|
||||||
- `ttl_seconds` — for temp entries
|
- `ttl_seconds` — for temp entries
|
||||||
- `reason` — the reason provided
|
- `reason` — the reason provided
|
||||||
- `api_client_ip` — the IP that made the API call
|
- `api_client_ip` — the IP that made the API call (from NGINX `X-Real-IP`)
|
||||||
|
|
||||||
Retrieve logs via the `/api/logs` endpoint.
|
Retrieve logs via the `/api/logs` endpoint.
|
||||||
|
|
||||||
|
The audit log is automatically rotated to maintain a maximum of 100,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
|
## Graceful shutdown
|
||||||
|
|
||||||
The service listens for SIGTERM and SIGINT. On signal:
|
The service listens for SIGTERM and SIGINT. On signal:
|
||||||
@@ -68,7 +79,7 @@ This ensures Docker deployments can shut down cleanly.
|
|||||||
- We don't support TLS. The auth endpoint should always be served over TLS.
|
- 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 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 metrics. If you need metrics, add them later.
|
||||||
- We don't support health checks with Prometheus. The /status endpoint is a simple text response.
|
- 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 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 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 HTTP/2. The auth-proxy service uses HTTP/1.1 only.
|
||||||
|
|||||||
62
openapi.yaml
62
openapi.yaml
@@ -39,17 +39,32 @@ paths:
|
|||||||
/status:
|
/status:
|
||||||
get:
|
get:
|
||||||
summary: Health check
|
summary: Health check
|
||||||
description: Simple health check endpoint.
|
description: Returns JSON with uptime, DB status, and whitelist counts.
|
||||||
operationId: healthCheck
|
operationId: healthCheck
|
||||||
security: []
|
security: []
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: OK
|
description: OK
|
||||||
content:
|
content:
|
||||||
text/plain:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: object
|
||||||
example: "ok\n"
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: "ok"
|
||||||
|
uptime:
|
||||||
|
type: string
|
||||||
|
example: "1h30m0s"
|
||||||
|
perm_whitelist_count:
|
||||||
|
type: integer
|
||||||
|
example: 15
|
||||||
|
temp_whitelist_count:
|
||||||
|
type: integer
|
||||||
|
example: 3
|
||||||
|
db_ok:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
|
||||||
/api/whitelist/temp:
|
/api/whitelist/temp:
|
||||||
post:
|
post:
|
||||||
@@ -99,6 +114,24 @@ paths:
|
|||||||
summary: List temporary whitelisted IPs
|
summary: List temporary whitelisted IPs
|
||||||
description: List all currently active temporary whitelisted IPs.
|
description: List all currently active temporary whitelisted IPs.
|
||||||
operationId: listTempWhitelist
|
operationId: listTempWhitelist
|
||||||
|
parameters:
|
||||||
|
- name: limit
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
maximum: 1000
|
||||||
|
default: 200
|
||||||
|
description: Number of entries to return (default 200, max 1000)
|
||||||
|
- name: offset
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 0
|
||||||
|
default: 0
|
||||||
|
description: Number of entries to skip (default 0)
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: List of temporary whitelisted IPs
|
description: List of temporary whitelisted IPs
|
||||||
@@ -168,7 +201,7 @@ paths:
|
|||||||
'204':
|
'204':
|
||||||
description: Created
|
description: Created
|
||||||
'400':
|
'400':
|
||||||
description: Bad request — entry required
|
description: Bad request — missing entry or invalid entry (must be valid IP or CIDR range)
|
||||||
'401':
|
'401':
|
||||||
description: Unauthorized — invalid API token
|
description: Unauthorized — invalid API token
|
||||||
'409':
|
'409':
|
||||||
@@ -186,6 +219,24 @@ paths:
|
|||||||
summary: List permanent whitelisted IPs
|
summary: List permanent whitelisted IPs
|
||||||
description: List all currently active permanent whitelisted IPs.
|
description: List all currently active permanent whitelisted IPs.
|
||||||
operationId: listPermWhitelist
|
operationId: listPermWhitelist
|
||||||
|
parameters:
|
||||||
|
- name: limit
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
maximum: 1000
|
||||||
|
default: 200
|
||||||
|
description: Number of entries to return (default 200, max 1000)
|
||||||
|
- name: offset
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 0
|
||||||
|
default: 0
|
||||||
|
description: Number of entries to skip (default 0)
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: List of permanent whitelisted IPs
|
description: List of permanent whitelisted IPs
|
||||||
@@ -233,6 +284,7 @@ paths:
|
|||||||
Retrieve the last 200 audit log entries (up to 1000 with `limit`).
|
Retrieve the last 200 audit log entries (up to 1000 with `limit`).
|
||||||
Each entry records a whitelist operation with its timestamp, action, affected IP,
|
Each entry records a whitelist operation with its timestamp, action, affected IP,
|
||||||
and the IP of the API client that performed the action.
|
and the IP of the API client that performed the action.
|
||||||
|
The audit log is automatically rotated to a maximum of 200,000 entries.
|
||||||
operationId: getLogs
|
operationId: getLogs
|
||||||
parameters:
|
parameters:
|
||||||
- name: action
|
- name: action
|
||||||
|
|||||||
Reference in New Issue
Block a user