docs: rewrite README and docs for the full-access design, generate tool inventory

This commit is contained in:
Latte committed 2026-10-14 16:13:11 +02:00
1 parent 68bd8700dc
commit 7c7cfc05ff
13 files changed
+1693 -1026

No files matched your search

+56 -25
View File
@@ -1,45 +1,68 @@
# Audit Logging
# Audit logging
## Design
Every tool call produces exactly one event in an append-only, hash-chained JSON-lines log,
whether it succeeded, failed at Gitea, failed validation or hit an internal error. Security
events are logged in the same chain.
Audit logs are append-only JSON lines with hash chaining:
- `prev_hash`: previous entry hash.
- `entry_hash`: hash of current entry payload + previous hash.
## What an event contains
This makes tampering detectable.
Each line is one JSON object:
## Event Types
| Field | Meaning |
|---|---|
| `timestamp` | UTC, ISO 8601 |
| `event_type` | `tool_invocation` or `security_event` |
| `request_id` | Correlation id of the request |
| `payload` | The event data, see below |
| `prev_hash` | `entry_hash` of the previous line (`GENESIS` for the first) |
| `entry_hash` | SHA-256 over the previous hash and this entry |
- `tool_invocation`
- `access_denied`
- `security_event`
A tool invocation payload records:
Each event includes timestamps and correlation context.
- the tool name, its domain, the HTTP method and the path template (for example
`/repos/{owner}/{repo}/issues`, never the filled-in values);
- the identity: Gitea login and mode (`admin-token` or `oauth`), and the sudo user when one was
given;
- the HTTP status when Gitea answered, and the outcome: success, or the error kind
(`not_found`, `forbidden`, `invalid_argument`, `internal_error`, ...);
- the duration in milliseconds and the correlation id;
- the argument names, sorted. Argument values are never logged, so request bodies, secret values
and file contents do not reach the log.
## Integrity Validation
All payloads also pass through secret masking before they are written
(`SECRET_DETECTION_MODE` other than `off`).
Use:
## Integrity
Each entry hashes the previous one, so editing, deleting or reordering a line breaks the chain
from that point on. Validate it with:
```bash
python3 scripts/validate_audit_log.py --path /var/log/aegis-mcp/audit.log
make validate-audit # default path
uv run python scripts/validate_audit_log.py --path /var/lib/aegis-mcp/audit.log
```
Exit code `0` indicates valid chain, non-zero indicates tamper/corruption.
Exit code 0 means the chain is intact; 1 lists the lines that do not verify. The default path is
`AUDIT_LOG_PATH`, else `DATA_DIR/audit.log`.
## Operational Expectations
The chain proves that history was not altered after the fact. It does not stop someone with
write access to the whole file from rewriting it consistently from the start, so also ship the
log to storage the server cannot modify, and compare the latest `entry_hash` against a copy you
keep elsewhere.
- Persist audit logs to durable storage.
- Protect write permissions (service account only).
- Validate integrity during incident response and release checks.
## Location and permissions
The log is written to `AUDIT_LOG_PATH`, default `DATA_DIR/audit.log` (`/var/lib/aegis-mcp` in the
image). Keep it on durable storage, readable and writable only by the service account.
## Rotation
The server appends to a single audit file and does not rotate it in process — rotating
mid-stream would break the `prev_hash`/`entry_hash` chain. Manage growth externally with
`logrotate` using `copytruncate` so the open file handle keeps appending:
The server appends to one file and does not rotate it, because rotating mid-stream would break
the chain. Rotate externally with `logrotate` and `copytruncate`, so the open file handle keeps
appending:
```
/var/log/aegis-mcp/audit.log {
/var/lib/aegis-mcp/audit.log {
weekly
rotate 12
compress
@@ -49,5 +72,13 @@ mid-stream would break the `prev_hash`/`entry_hash` chain. Manage growth externa
}
```
Run `scripts/validate_audit_log.py` against each rotated segment to confirm the chain
remains intact across rotations before archiving.
The validator expects a chain to start at `GENESIS`, so only the first segment verifies as it
is. For a later segment, check that its first `prev_hash` equals the last `entry_hash` of the
previous segment. Validate segments before archiving them, and keep them in order.
## Operating it
- Alert on bursts of `forbidden` or `unauthorized` outcomes and on tool calls by unexpected
identities.
- Review calls to admin, secret and delete tools. The tool name makes them easy to filter.
- Run the integrity check regularly and during incident response.