tracemill/tracemill
GitHub: tracemill/tracemill
Stars: 1 | Forks: 0
# Tracemill Content Library
Open source scenarios, jobs, and event types for validating detective controls end-to-end with [Tracemill](https://tracemill.io).
This library is distributed to end users via `tracemill update` and installed to `~/.tracemill/library/`. Users should not edit the installed copy directly — the entire directory is replaced on each update.
## Quick Start
Install the CLI via Homebrew or download a binary from the [download page](https://tracemill.io/download):
brew install tracemill/tap/tracemill
Update the library to get the latest content:
tracemill update
Run a scenario — events print to stdout in JSONL format:
tracemill run scenarios/aws/cloudtrail/delete-trail
Send events to Splunk HEC:
tracemill run scenarios/aws/cloudtrail/delete-trail \
--hec-url https://splunk.example.com:8088 \
--hec-token your-token
Run a multi-scenario job:
tracemill run jobs/aws/brute-force
For the full documentation — scenarios, jobs, pools, expressions, and CLI reference — see [tracemill.io/docs](https://tracemill.io/docs).
## Content Types
**Scenarios** are atomic and self-contained. A scenario is a single YAML file with no external dependencies — it uses generators, refs, and state, all defined inline.
**Jobs** wire scenarios together with pools, bindings, and concurrency settings. Jobs reference scenarios and shared pools by content ID.
**Pools** are reusable data sources (IP ranges, string lists, CSV references) that jobs bind to scenarios at runtime.
**Event types** declare the schema and engine metadata for a class of generated events. Scenarios reference event types by `id@version` (e.g. `aws.cloudtrail@v1`); the engine validates every emitted event against the declared JSON Schema.
## Repository Structure
Content is organized by type at the top level, then by provider and service.
scenarios/
aws/
cloudtrail/
delete-trail.yaml # type: scenario
iam/
create-access-key.yaml # type: scenario
update-login-profile.yaml # type: scenario
s3/
put-bucket-lifecycle.yaml # type: scenario
event-types/
aws/
cloudtrail/
v1.yaml # type: event-type
pools/
threat-ips.yaml # type: pool (ip_range)
jobs/
aws/
brute-force.yaml # type: job
The `type:` field in each YAML file identifies what it is. The tree structure provides organization, not type disambiguation.
## Content IDs
Every file has a content ID: its path from the repository root, minus the `.yaml` extension. Content IDs are how users and jobs reference content.
| File | Content ID |
|---|---|
| `scenarios/aws/cloudtrail/delete-trail.yaml` | `scenarios/aws/cloudtrail/delete-trail` |
| `scenarios/aws/iam/create-access-key.yaml` | `scenarios/aws/iam/create-access-key` |
| `scenarios/aws/s3/put-bucket-lifecycle.yaml` | `scenarios/aws/s3/put-bucket-lifecycle` |
Content IDs are stable identifiers. Users reference them in jobs, scripts, and CI pipelines. Renaming or moving a file is a breaking change.
## Directory Taxonomy
The directory path is part of the content ID, so the taxonomy is a contract. Follow these conventions:
- Cloud scenarios: `scenarios/{provider}/{service}/{scenario-name}` — e.g., `scenarios/aws/iam/create-access-key`
- Endpoint scenarios: `scenarios/{platform}/{log-source}/{scenario-name}` — e.g., `scenarios/windows/eventlog/lateral-movement`
- Network scenarios: `scenarios/{protocol-or-domain}/{scenario-name}` — e.g., `scenarios/dns/tunneling`
- Jobs: `jobs/{provider}/{job-name}` — e.g., `jobs/aws/brute-force`
- Pools: `pools/{pool-name}` — e.g., `pools/threat-ips`
## Event Types
Event type files define the schema and engine metadata for a class of generated events. Every scenario that uses `emit:` with an `event_type:` field relies on an event type definition being present in the content hierarchy.
### Fields
| Field | Required | Description |
|---|---|---|
| `type` | Yes | Must be `event-type`. |
| `id` | Yes | Stable dotted identifier, e.g. `aws.cloudtrail`. Pattern: `^[a-zA-Z][a-zA-Z0-9._-]*$` |
| `version` | Yes | Version label, e.g. `v1`. |
| `full_name` | No | Human-readable display name. |
| `format` | No | Serialisation format. Default: `json`. |
| `xml_envelope` | No | Root element config for XML format: `element` (name, default `Event`) and `attributes` (key-value map). |
| `schema` | Yes | JSON Schema (draft 2020-12) for the event payload. Validated on every emitted event. |
| `defaults` | No | Default field values merged before scenario overrides. ExprStr supported. |
| `timestamp` | No | Payload field stamped with the logical clock on every emit. Omit to disable clock stamping. |
| `correlation` | Yes | Array of payload field names that together uniquely identify a generated event instance in the SIEM. See below. |
### `correlation`
Declares which payload field(s) the engine uses to identify each generated event for SIEM correlation. Required on every event type.
For event types with a native UUID field: `correlation: [eventID]`
For event types without a native UUID, declare the combination of fields that makes each event uniquely identifiable: `correlation: [srcaddr, dstaddr, srcport, dstport, protocol]`
The declared fields must be part of the standard schema and survive SIEM ingestion unchanged. Do not use `tracemill_*` envelope fields — some ingestion tools strip unknown fields.
### XML attribute and text content convention
Event types with `format: xml` use a naming convention in their schema to control how the XMLFormatter renders elements, attributes, and text content:
- **`@key`** — renders as an XML attribute on the parent element.
- **`#text`** — renders as the text content of the parent element.
Keys without a prefix render as child elements (the default).
| Schema shape | XML output |
|---|---|
| `Provider: {"@Name": "Sysmon", "@Guid": "{...}"}` | ` ` |
| `Data: {"@Name": "User", "#text": "SYSTEM"}` | `SYSTEM` |
| `TimeCreated: {"@SystemTime": "2026-04-15T10:00:00Z"}` | ` ` |
| `EventID: 4624` | `4624 ` |
When a map contains only `@`-prefixed keys (no `#text`, no child elements), the formatter produces a self-closing element. When `#text` is present alongside `@` keys, the text becomes the element body. When non-`@` keys coexist with `@` keys, the non-`@` keys render as child elements.
Arrays of maps with `@Name`/`#text` produce repeated elements — this is how `EventData.Data` items render:
EventData:
Data:
- "@Name": SubjectUserSid
"#text": S-1-5-18
- "@Name": LogonType
"#text": "2"
S-1-5-18
2
This convention is handled entirely by the XMLFormatter — it is not specific to any event type. Schema authors use it to produce native XML shapes (Windows Event Log, etc.) without requiring event-type-specific formatter logic.
### Adding a new event type
1. Create `event-types/{provider}/{service}/v1.yaml` (or the appropriate version).
2. Declare `correlation` pointing to the field(s) that uniquely identify each event instance in the SIEM.
3. Define a `schema` that matches real event payloads from that source. Use `additionalProperties: true` to stay compatible with source-specific variations.
4. Mark required fields conservatively — follow the source's own documentation. Fields that appear in all real events but are documented as optional should be kept optional.
type: event-type
id: aws.cloudtrail
version: v1
full_name: AWS CloudTrail Management Event
timestamp: eventTime
correlation: [eventID]
defaults:
eventVersion: "1.08"
eventTime: gen.timestamp()
schema:
$schema: https://json-schema.org/draft/2020-12/schema
type: object
required: [eventID, eventTime, eventSource, eventName]
properties:
eventID:
type: string
description: CloudTrail-generated GUID uniquely identifying each event.
eventTime:
type: string
eventSource:
type: string
eventName:
type: string
additionalProperties: true
## Tags and MITRE ATT&CK Metadata
Every content file supports `tags` and an optional `mitre` block for ATT&CK mapping:
tags: [aws, cloudtrail]
mitre:
tactics: [defense-evasion]
techniques: [T1562.008]
- **`tags`** — free-form labels for filtering (`tracemill list scenarios --tags aws`). Use lowercase kebab-case. Common tags: provider (`aws`, `gcp`), service (`iam`, `s3`, `cloudtrail`), attack category (`brute-force`, `exfiltration`).
- **`mitre.tactics`** — one or more ATT&CK tactic slugs: `initial-access`, `execution`, `persistence`, `privilege-escalation`, `defense-evasion`, `credential-access`, `discovery`, `lateral-movement`, `collection`, `exfiltration`, `impact`.
- **`mitre.techniques`** — one or more ATT&CK technique or sub-technique IDs (e.g., `T1078`, `T1562.008`, `T1485.001`).
A scenario can map to multiple tactics and techniques when it covers compound behavior:
# scenarios/aws/s3/put-bucket-lifecycle.yaml
tags: [aws, s3]
mitre:
tactics: [defense-evasion, impact]
techniques: [T1562.008, T1485.001]
## File Naming Conventions
- Kebab-case, lowercase: `brute-force.yaml`
- `.yaml` extension for all YAML content, no type suffixes (no `.pool.yaml` or `.job.yaml`)
- Action-oriented, descriptive names: `brute-force.yaml`, `credential-stuffing.yaml`
- Don't repeat the directory context: `brute-force.yaml`, not `cloudtrail-brute-force.yaml`
- Variant suffix when needed: `brute-force-slow.yaml`
## Job References
Jobs reference scenarios and pools by content ID. The same disambiguation rule applies everywhere: values starting with `./`, `/`, or `~` are treated as file paths; everything else is a content ID resolved through the content layers.
type: job
workloads:
- scenario: scenarios/aws/cloudtrail/delete-trail
bindings:
account_id: ref.account_id
- scenario: scenarios/aws/iam/create-access-key
bindings:
account_id: ref.account_id
## Releasing
Releases are driven by the `release.yml` GitHub Actions workflow, triggered by pushing a `lib-v*` tag.
git tag lib-v2026.03.21
git push origin lib-v2026.03.21
The workflow:
1. Creates a `library.tar.gz` archive (excluding `.git`, `.github`, `LICENSE`, `README.md`, `library.json`)
2. Computes the SHA-256 digest
3. Reads `min_cli_version` from `library.json`
4. Builds a `version.json` manifest with version, sha256, min_cli_version, and published_at
5. Uploads to S3: versioned archive (`library/{version}/`), latest pointer (`library/latest/`), and manifest (`library/version.json`)
Same-day re-releases use a `.N` suffix: `lib-v2026.03.21.1`.
The `min_cli_version` field in `library.json` should be bumped only when new content requires CLI features not present in older versions (new generator, new YAML field, etc.).
## License
Apache 2.0
标签:AMSI绕过, AWS CloudTrail, IAM, JSONL格式, JSON Schema验证, SEO, Splunk HEC, Tracemill, YAML配置, 事件生成, 作业调度, 侦探控制, 关键词, 内容库, 威胁检测, 安全测试, 开源, 攻击性安全, 日志管道, 池管理, 端对端验证, 自动化场景