A minimal, opinionated starter repo for managing Sumo Logic Cloud
SIEM rules as code in GitHub. Detections live in YAML, get linted
and unit-tested in CI, then deployed to Sumo via the official
SumoLogic/sumologic Terraform provider.
This is the companion repo to the blog post "Setting up Detection as Code the Hard Way."
First time here? → docs/SETUP.md is the full step-by-step environment guide: Sumo access keys, AWS OIDC, GitHub secrets, branch protection, first deploy, troubleshooting. Start there.
rules/ YAML detection definitions
aws_cloudtrail_disable_logging.yml
aws_cloudtrail_root_console_login.yml
okta_brute_force_single_ip.yml
_example_failing_rule.yml <-- deliberately broken; demos the linter
validator/
schema.py JSON Schema for the YAML format
validate.py CLI: schema-check + sanity passes
compile_to_terraform.py CLI: YAML -> HCL
terraform/
providers.tf sumologic provider + S3 backend
main.tf (compiled resources are written to generated/)
tests/
test_validator.py pytest unit tests for the validator
.github/workflows/
detection-ci.yml lint -> plan (PR) -> apply (main)
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Lint every rule
python -m validator.validate rules/
# Run the validator's own unit tests
pytest -q
# Compile YAML -> Terraform (writes terraform/generated/*.tf)
python -m validator.compile_to_terraformYou should see the three real rules pass and _example_failing_rule.yml
fail with three distinct errors — that file is intentionally broken to
prove the linter is doing something.
The full walkthrough — Sumo access keys, AWS OIDC role, S3 state backend, GitHub secrets and environments — is in docs/SETUP.md. Summary of what ends up where:
| Name | Type | What it is |
|---|---|---|
SUMO_ACCESS_ID |
Repo Secret | Sumo API auth |
SUMO_ACCESS_KEY |
Repo Secret | Sumo API auth |
SUMO_DEPLOYMENT |
Repo Variable | us1 / us2 / eu / … |
AWS_ROLE_ARN |
Repo Variable | OIDC role for Terraform state |
TF_STATE_BUCKET |
Repo Variable | S3 bucket for Terraform state |
TF_STATE_REGION |
Repo Variable | AWS region of that bucket |
TF_LOCK_TABLE |
Repo Variable | (optional — only if using DynamoDB locking) |
Locally, copy .env.example → .env, fill it in, and source it.
The Sumo Terraform provider reads its own env-var names
(SUMOLOGIC_ACCESSID etc.) — .env.example re-exports our SUMO_*
values under the names the provider expects, so you only configure
them once.
- Drop a YAML file into
rules/(use one of the existing files as a template). python -m validator.validate rules/— fix any errors.pytest -q— make sure nothing else regressed.- Open a PR. CI runs the linter, compiles to HCL, runs
terraform plan, and attaches the plan as an artifact for review. - Merge to
main. CI applies to the prod tenant (gated by theprodGitHub environment so a human approves the apply).
id: kebab-case-stable-id
name: Human-readable name (shows up in Sumo UI)
type: match | threshold | aggregation | chain | first_seen | outlier
enabled: true
severity: 1-10
expression: |
metadata_vendor = 'AWS' AND ...
entity_selectors:
- { entity_type: _ip, expression: srcDevice_ip }
- { entity_type: _username, expression: user_username }
signal:
# name_expression: "..." # match/aggregation/chain only — drop for threshold/first_seen/outlier
summary_expression: "..."
description_expression: "..."
tags:
- _mitreAttackTactic:TA0005
- _mitreAttackTechnique:T1562.008
metadata:
owner: detection-engineering@example.com
runbook: https://runbooks.example.com/...
references: [https://attack.mitre.org/techniques/T1562/008/]
is_prototype: false
# Threshold / aggregation-specific:
group_by: [srcDevice_ip]
window: T10M # T05M | T10M | T30M | T60M | T12H | T24H | T05D | CUSTOM
count: 10- It doesn't run unit tests against synthetic log events. The Sumo
rules engine is server-side, so true "fire this fake event and
assert a signal" tests need a Sumo dev tenant. The closest you can
get locally is the linter +
terraform plan. - It doesn't (yet) support every rule type.
matchandthresholdare wired up end-to-end. Aggregation / chain / first-seen / outlier follow the same pattern — seevalidator/compile_to_terraform.py.