From 8d25bda3868b825a5d183694097e3693a5dd00f7 Mon Sep 17 00:00:00 2001 From: db123-test Date: Tue, 5 May 2026 11:51:45 +0330 Subject: [PATCH] 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 --- README.md | 25 +++++++++++++++++-- docs/api.md | 42 ++++++++++++++++++++++++++++++-- docs/deploy.md | 8 ++++++- docs/design.md | 5 ++-- docs/security.md | 15 ++++++++++-- openapi.yaml | 62 ++++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 143 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 74add28..78a3c10 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ On 401/403 NGINX returns the response to the client. Whitelisted IPs never see a ## Build ```bash -go build -o auth-proxy . +go build -o auth-proxy ./src ``` ## Docker @@ -42,6 +42,27 @@ vim .env ./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 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 | | DELETE | `/api/whitelist/perm/{entry}` | Remove a permanent entry | | 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. diff --git a/docs/api.md b/docs/api.md index be2fa96..8d632fe 100644 --- a/docs/api.md +++ b/docs/api.md @@ -35,6 +35,13 @@ List all currently active temporary whitelisted IPs. **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:** ```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} Remove a temporary whitelisted IP. @@ -86,6 +100,13 @@ List all currently active permanent whitelisted IPs. **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:** ```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} Remove a permanent whitelisted IP or CIDR range. @@ -149,9 +177,19 @@ The NGINX auth_request endpoint. Do NOT call this directly. ### 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 diff --git a/docs/deploy.md b/docs/deploy.md index 565d882..ee3bd3e 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -83,11 +83,17 @@ nginx -s reload | Variable | Description | Default | |----------|-------------|---------| | 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 | | DATA_DIR | Data directory | /data | | CLEANUP_INTERVAL | Cleanup interval | 60s | +## Testing + +```bash +go test ./src/... +``` + ## Graceful shutdown ```bash diff --git a/docs/design.md b/docs/design.md index 3823c44..70bb55d 100644 --- a/docs/design.md +++ b/docs/design.md @@ -106,8 +106,9 @@ 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. +The cleanup goroutine removes expired temporary entries and rotates the audit log. +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? diff --git a/docs/security.md b/docs/security.md index 7cdfc2b..7230181 100644 --- a/docs/security.md +++ b/docs/security.md @@ -30,6 +30,7 @@ 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. @@ -43,10 +44,20 @@ Each entry records: - `ip` or `cidr` — the affected IP or CIDR - `ttl_seconds` — for temp entries - `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. +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 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 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 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 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. diff --git a/openapi.yaml b/openapi.yaml index 2a21c71..68339ca 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -39,17 +39,32 @@ paths: /status: get: summary: Health check - description: Simple health check endpoint. + description: Returns JSON with uptime, DB status, and whitelist counts. operationId: healthCheck security: [] responses: '200': description: OK content: - text/plain: + application/json: schema: - type: string - example: "ok\n" + type: object + 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: post: @@ -99,6 +114,24 @@ paths: summary: List temporary whitelisted IPs description: List all currently active temporary whitelisted IPs. 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: '200': description: List of temporary whitelisted IPs @@ -168,7 +201,7 @@ paths: '204': description: Created '400': - description: Bad request — entry required + description: Bad request — missing entry or invalid entry (must be valid IP or CIDR range) '401': description: Unauthorized — invalid API token '409': @@ -186,6 +219,24 @@ paths: summary: List permanent whitelisted IPs description: List all currently active permanent whitelisted IPs. 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: '200': description: List of permanent whitelisted IPs @@ -233,6 +284,7 @@ paths: Retrieve the last 200 audit log entries (up to 1000 with `limit`). Each entry records a whitelist operation with its timestamp, action, affected IP, 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 parameters: - name: action