collector: emit ONE consolidated report per run (SOC_SLUG), not one per source
Build and push soc-collector / build (push) Successful in 6s

All enabled sources merge into a single report keyed by SOC_SLUG, criticals first.
One server = one report; run per server with a distinct SOC_SLUG. Avoids the
4-reports-per-host explosion when scanning several servers. README updated.
This commit is contained in:
Steffen Skui
2026-06-24 18:42:38 +02:00
parent 800bda12cb
commit 67eaf409b9
2 changed files with 65 additions and 41 deletions
+17 -9
View File
@@ -12,12 +12,16 @@ and alerts you only on *new* findings.
docker run --rm \
-e SOC_URL=https://soc.ethica.no \
-e SOC_TOKEN=soc_xxxxxxxx \
-e SOC_SLUG=my-server \
-e SOC_TARGETS=10.0.0.5,10.0.0.6 \
-e SOC_DOMAINS=soc.ethica.no,ethica.no \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
git.skui.io/ethica/soc-collector:latest
```
Each run produces **one report** (named by `SOC_SLUG`) merging all the sources below.
One server = one report; run it per server with a distinct `SOC_SLUG` for one report each.
It runs once and exits. To keep reports fresh, schedule that command — e.g. nightly:
```cron
@@ -30,16 +34,19 @@ Reports are owned by, and visible per, that token's user.
## What it collects
| Report (slug) | Source | Needs |
One run = **one consolidated report** (slug = `SOC_SLUG`) merging whichever of these
sources have their inputs, criticals first:
| Source | What it checks | Needs |
|---|---|---|
| `attack-surface` | `nmap` open-port / service scan, flags risky exposed ports | `SOC_TARGETS` |
| `container-cves` | `trivy` vuln scan of every **running** image (HIGH/CRITICAL) | Docker socket |
| `tls-exposure` | cert-expiry, weak TLS, missing security headers | `SOC_DOMAINS` |
| `config-drift` | `0.0.0.0` port binds, `--privileged`, rw docker-socket mounts | Docker socket |
| surface | `nmap` open-port / service scan, flags risky exposed ports | `SOC_TARGETS` |
| cve | `trivy` of every **running** image **fixable** HIGH/CRITICAL only, grouped by package | Docker socket |
| tls | cert-expiry, weak TLS, missing security headers | `SOC_DOMAINS` |
| config | `0.0.0.0` port binds, `--privileged`, rw docker-socket mounts | Docker socket |
Each source **self-skips** when its inputs are absent — no `SOC_TARGETS` → no nmap; no
socket mount → no Trivy / config-drift. So the same image is safe to run anywhere; you
just enable what you give it.
socket mount → no Trivy / config. So the same image is safe to run anywhere; you just
enable what you give it.
## Configuration (all via env)
@@ -50,7 +57,8 @@ just enable what you give it.
| `SOC_TARGETS` | for nmap | — | comma/space hosts or IPs to scan |
| `SOC_DOMAINS` | for tls | — | comma hostnames to TLS-probe |
| `SOC_SOURCES` | | `surface,cve,tls,config` | which sources to run |
| `SOC_SLUG_PREFIX` | | — | prefix slugs (e.g. `hetzner`) so multiple sites don't collide |
| `SOC_SLUG` | | `soc-scan` | the report's slug — **set one per server** (e.g. `hetzner-prod`) |
| `SOC_TITLE` | | `Security scan — <slug>` | the report's title |
| `SOC_VISIBILITY` | | `private` | `private` or `authenticated` |
| `SOC_TAGS` | | `collector` | extra report tags |
@@ -60,7 +68,7 @@ just enable what you give it.
containers and *inspect* their config. For extra isolation, point it at a scoped
socket-proxy instead of the raw socket.
- The collector is **pure-stdlib Python**; the image just adds `nmap` and `trivy`.
- Multi-site: run one container per site with a distinct `SOC_SLUG_PREFIX`.
- Multi-server: run one container per server with a distinct `SOC_SLUG` — one report each.
## License