docs: Add documentation site and API reference

This commit is contained in:
matsv
2026-02-13 15:12:14 +01:00
parent d82fe87113
commit e17d34e6d7
7 changed files with 968 additions and 0 deletions

155
docs/security.md Normal file
View File

@@ -0,0 +1,155 @@
# Security
## Authentication
AegisGitea MCP uses bearer token authentication. Clients must include a valid API key with every tool call.
### How It Works
1. The client sends `Authorization: Bearer <key>` with its request.
2. The server extracts the token and validates it against the configured `MCP_API_KEYS`.
3. Comparison is done in **constant time** to prevent timing attacks.
4. If validation fails, the failure is counted against the client's IP address.
### Generating API Keys
Use the provided script to generate cryptographically secure 64-character hex keys:
```bash
make generate-key
# or: python scripts/generate_api_key.py
```
Keys must be at least 32 characters long. The script also saves metadata (creation date, expiration) to a `keys/` directory.
### Multiple Keys (Grace Period During Rotation)
You can configure multiple keys separated by commas. This allows you to add a new key and remove the old one without downtime:
```env
MCP_API_KEYS=newkey...,oldkey...
```
Remove the old key from the list after all clients have been updated.
---
## Key Rotation
Rotate keys regularly (recommended: every 90 days).
```bash
make rotate-key
# or: python scripts/rotate_api_key.py
```
The rotation script:
1. Reads the current key from `.env`
2. Generates a new key
3. Offers to replace the key immediately or add it alongside the old key (grace period)
4. Creates a backup of your `.env` before modifying it
### Checking Key Age
```bash
make check-key-age
# or: python scripts/check_key_age.py
```
Exit codes: `0` = OK, `1` = expiring within 7 days (warning), `2` = already expired (critical).
---
## Rate Limiting
Failed authentication attempts are tracked per client IP address.
| Setting | Default | Description |
|---|---|---|
| `MAX_AUTH_FAILURES` | `5` | Maximum failures before the IP is blocked |
| `AUTH_FAILURE_WINDOW` | `300` | Rolling window in seconds |
Once an IP exceeds the threshold, all further requests from that IP return HTTP 429 until the window resets. This is enforced entirely in memory — a server restart resets the counters.
---
## Audit Logging
All security-relevant events are written to a structured JSON log file.
### Log Location
Default: `/var/log/aegis-mcp/audit.log`
Configurable via `AUDIT_LOG_PATH`.
The directory is created automatically on startup.
### What Is Logged
| Event | Description |
|---|---|
| Tool invocation | Every call to a tool: tool name, arguments, result status, correlation ID |
| Access denied | Failed authentication attempts: IP address, reason |
| Security event | Rate limit triggers, invalid key formats, startup authentication status |
### Log Format
Each entry is a JSON object on a single line:
```json
{
"timestamp": "2026-02-13T10:00:00Z",
"event": "tool_invocation",
"correlation_id": "a1b2c3d4-...",
"tool": "get_file_contents",
"owner": "myorg",
"repo": "backend",
"path": "src/main.py",
"result": "success",
"client_ip": "10.0.0.1"
}
```
### Using Logs for Monitoring
Because entries are newline-delimited JSON, they are easy to parse:
```bash
# Show all failed tool calls
grep '"result": "error"' /var/log/aegis-mcp/audit.log | jq .
# Show all access-denied events
grep '"event": "access_denied"' /var/log/aegis-mcp/audit.log | jq .
```
---
## Access Control Model
AegisGitea MCP does **not** implement its own repository access control. Access to repositories is determined entirely by the Gitea bot user's permissions:
- If the bot user has no access to a repository, it will not appear in `list_repositories` and `get_repository_info` will return an error.
- Grant the bot user the minimum set of repository permissions needed.
**Principle of least privilege:** create a dedicated bot user and grant it read-only access only to the repositories that the AI needs to see.
---
## Network Security Recommendations
- Run the MCP server behind a reverse proxy (e.g. Traefik or nginx) with TLS.
- Do not expose the server directly on a public port without TLS.
- Restrict inbound connections to known AI client IP ranges where possible.
- The `/mcp/tools` endpoint is intentionally public (required for ChatGPT plugin discovery). If this is undesirable, restrict it at the network/proxy level.
---
## Container Security
The provided Docker image runs with:
- A non-root user (`aegis`, UID 1000)
- `no-new-privileges` security option
- CPU and memory resource limits (1 CPU, 512 MB)
See [Deployment](deployment.md) for details.