docs: rewrite README and docs for the full-access design, generate tool inventory
This commit is contained in:
1 parent
68bd8700dc
commit
7c7cfc05ff
13 files changed
+1693
-1026
No files matched your search
+56
-25
@@ -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.
|
||||
Reference in new issue
Block a user