282 lines
7.3 KiB
Markdown
282 lines
7.3 KiB
Markdown
# Runtime Evidence Schema Reference
|
|
|
|
## Overview
|
|
|
|
Runtime evidence is serialized as NDJSON (Newline-Delimited JSON), with one event per line. The schema ensures deterministic output for reproducible evidence chains.
|
|
|
|
## Schema Location
|
|
|
|
- JSON Schema: `docs/schemas/runtime-evidence-v1.json`
|
|
- C# Models: `src/Signals/__Libraries/StellaOps.Signals.Ebpf/Schema/`
|
|
|
|
## Common Fields
|
|
|
|
Every evidence record includes these base fields:
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `ts_ns` | integer | Yes | Nanoseconds since system boot |
|
|
| `src` | string | Yes | Event source identifier |
|
|
| `pid` | integer | Yes | Process ID |
|
|
| `tid` | integer | No | Thread ID (if available) |
|
|
| `cgroup_id` | integer | Yes | Kernel cgroup ID |
|
|
| `container_id` | string | No | Container ID (enriched) |
|
|
| `image_digest` | string | No | Image digest (enriched) |
|
|
| `comm` | string | No | Process command name (max 16 chars) |
|
|
| `event` | object | Yes | Type-specific event data |
|
|
|
|
## Event Types
|
|
|
|
### File Access (`file_access`)
|
|
|
|
Captured from `sys_enter_openat` tracepoint.
|
|
|
|
```json
|
|
{
|
|
"ts_ns": 1234567890123456789,
|
|
"src": "tracepoint:syscalls:sys_enter_openat",
|
|
"pid": 1234,
|
|
"cgroup_id": 5678,
|
|
"container_id": "abc123def456",
|
|
"image_digest": "sha256:...",
|
|
"comm": "nginx",
|
|
"event": {
|
|
"type": "file_access",
|
|
"path": "/etc/nginx/nginx.conf",
|
|
"flags": 0,
|
|
"mode": 0,
|
|
"access": "read"
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `path` | string | File path (max 256 chars) |
|
|
| `flags` | integer | Open flags (`O_RDONLY`, `O_WRONLY`, etc.) |
|
|
| `mode` | integer | File mode (for creation) |
|
|
| `access` | string | Derived access type: `read`, `write`, `read_write` |
|
|
|
|
### Process Execution (`process_exec`)
|
|
|
|
Captured from `sched_process_exec` tracepoint.
|
|
|
|
```json
|
|
{
|
|
"ts_ns": 1234567890123456789,
|
|
"src": "tracepoint:sched:sched_process_exec",
|
|
"pid": 1234,
|
|
"cgroup_id": 5678,
|
|
"container_id": "abc123def456",
|
|
"image_digest": "sha256:...",
|
|
"comm": "python3",
|
|
"event": {
|
|
"type": "process_exec",
|
|
"filename": "/usr/bin/python3",
|
|
"ppid": 1000,
|
|
"argv": ["python3", "script.py", "--config", "/etc/app.conf"]
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `filename` | string | Executed binary path |
|
|
| `ppid` | integer | Parent process ID |
|
|
| `argv` | string[] | Command arguments (limited to first 4) |
|
|
|
|
### TCP State Change (`tcp_state`)
|
|
|
|
Captured from `inet_sock_set_state` tracepoint.
|
|
|
|
```json
|
|
{
|
|
"ts_ns": 1234567890123456789,
|
|
"src": "tracepoint:sock:inet_sock_set_state",
|
|
"pid": 1234,
|
|
"cgroup_id": 5678,
|
|
"container_id": "abc123def456",
|
|
"image_digest": "sha256:...",
|
|
"comm": "curl",
|
|
"event": {
|
|
"type": "tcp_state",
|
|
"family": "ipv4",
|
|
"old_state": "SYN_SENT",
|
|
"new_state": "ESTABLISHED",
|
|
"src_addr": "10.0.0.5",
|
|
"src_port": 45678,
|
|
"dst_addr": "93.184.216.34",
|
|
"dst_port": 443
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `family` | string | Address family: `ipv4` or `ipv6` |
|
|
| `old_state` | string | Previous TCP state |
|
|
| `new_state` | string | New TCP state |
|
|
| `src_addr` | string | Source IP address |
|
|
| `src_port` | integer | Source port |
|
|
| `dst_addr` | string | Destination IP address |
|
|
| `dst_port` | integer | Destination port |
|
|
|
|
TCP States: `CLOSED`, `LISTEN`, `SYN_SENT`, `SYN_RECV`, `ESTABLISHED`, `FIN_WAIT1`, `FIN_WAIT2`, `CLOSE_WAIT`, `CLOSING`, `LAST_ACK`, `TIME_WAIT`
|
|
|
|
### Network Operation (`network_op`)
|
|
|
|
Captured from libc `connect`/`accept` uprobes.
|
|
|
|
```json
|
|
{
|
|
"ts_ns": 1234567890123456789,
|
|
"src": "uprobe:libc.so.6:connect",
|
|
"pid": 1234,
|
|
"cgroup_id": 5678,
|
|
"container_id": "abc123def456",
|
|
"image_digest": "sha256:...",
|
|
"comm": "app",
|
|
"event": {
|
|
"type": "network_op",
|
|
"operation": "connect",
|
|
"family": "ipv4",
|
|
"addr": "10.0.1.100",
|
|
"port": 5432,
|
|
"result": 0
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `operation` | string | `connect` or `accept` |
|
|
| `family` | string | Address family |
|
|
| `addr` | string | Remote address |
|
|
| `port` | integer | Remote port |
|
|
| `result` | integer | Return value (0 = success) |
|
|
|
|
### SSL Operation (`ssl_op`)
|
|
|
|
Captured from OpenSSL `SSL_read`/`SSL_write` uprobes.
|
|
|
|
```json
|
|
{
|
|
"ts_ns": 1234567890123456789,
|
|
"src": "uprobe:libssl.so.3:SSL_write",
|
|
"pid": 1234,
|
|
"cgroup_id": 5678,
|
|
"container_id": "abc123def456",
|
|
"image_digest": "sha256:...",
|
|
"comm": "nginx",
|
|
"event": {
|
|
"type": "ssl_op",
|
|
"operation": "write",
|
|
"requested_bytes": 1024,
|
|
"actual_bytes": 1024,
|
|
"ssl_ptr": 140234567890
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `operation` | string | `read` or `write` |
|
|
| `requested_bytes` | integer | Bytes requested |
|
|
| `actual_bytes` | integer | Bytes actually transferred |
|
|
| `ssl_ptr` | integer | SSL context pointer (for correlation) |
|
|
|
|
### Symbol Call (`symbol_call`)
|
|
|
|
Captured from function uprobes.
|
|
|
|
```json
|
|
{
|
|
"ts_ns": 1234567890123456789,
|
|
"src": "uprobe:app:vulnerable_parse_json",
|
|
"pid": 1234,
|
|
"cgroup_id": 5678,
|
|
"container_id": "abc123def456",
|
|
"image_digest": "sha256:...",
|
|
"comm": "app",
|
|
"event": {
|
|
"type": "symbol_call",
|
|
"symbol": "vulnerable_parse_json",
|
|
"library": "/usr/lib/libapp.so",
|
|
"offset": 4096,
|
|
"address": 140234571986
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `symbol` | string | Function symbol name |
|
|
| `library` | string | Library/binary path |
|
|
| `offset` | integer | Offset within library |
|
|
| `address` | integer | Runtime address |
|
|
|
|
## Determinism Requirements
|
|
|
|
For byte-identical output across runs:
|
|
|
|
1. **Field Ordering**: All JSON keys sorted alphabetically
|
|
2. **Number Format**: Integers as-is, no floating point variance
|
|
3. **String Encoding**: UTF-8 with NFC normalization
|
|
4. **Null Handling**: Null fields omitted (not `"field": null`)
|
|
5. **Whitespace**: No trailing whitespace, single newline per record
|
|
|
|
## Chunk Metadata
|
|
|
|
Each evidence chunk includes metadata in its DSSE attestation:
|
|
|
|
```json
|
|
{
|
|
"predicateType": "stella.ops/runtime-evidence@v1",
|
|
"predicate": {
|
|
"chunk_id": "sha256:abc123...",
|
|
"chunk_sequence": 42,
|
|
"previous_chunk_id": "sha256:def456...",
|
|
"event_count": 150000,
|
|
"time_range": {
|
|
"start": "2026-01-27T10:00:00Z",
|
|
"end": "2026-01-27T11:00:00Z"
|
|
},
|
|
"collector_version": "1.0.0",
|
|
"kernel_version": "5.15.0-generic",
|
|
"compression": null,
|
|
"host_id": "node-01.cluster.local",
|
|
"container_ids": ["abc123", "def456"]
|
|
}
|
|
}
|
|
```
|
|
|
|
## Validation
|
|
|
|
Evidence can be validated against the JSON Schema:
|
|
|
|
```bash
|
|
# Validate single file
|
|
stella evidence validate evidence-chunk-001.ndjson
|
|
|
|
# Validate and show statistics
|
|
stella evidence validate --stats evidence-chunk-001.ndjson
|
|
```
|
|
|
|
## Migration from v0 Schemas
|
|
|
|
If using earlier per-language schemas, migrate to v1 unified schema:
|
|
|
|
1. Update field names to snake_case
|
|
2. Wrap type-specific fields in `event` object
|
|
3. Add `src` field with probe identifier
|
|
4. Ensure `ts_ns` uses nanoseconds since boot
|
|
|
|
Example migration:
|
|
```json
|
|
// v0 (old)
|
|
{"timestamp": 1234567890, "type": "file", "path": "/etc/config"}
|
|
|
|
// v1 (new)
|
|
{"ts_ns": 1234567890000000000, "src": "tracepoint:syscalls:sys_enter_openat", "pid": 1234, "cgroup_id": 5678, "event": {"type": "file_access", "path": "/etc/config", "flags": 0, "mode": 0, "access": "read"}}
|
|
```
|