Skip to content

fix(lab): fence lab Grafana, BloodHound and scratch's UIs to Hicks - #1429

Merged
Gerrrt merged 3 commits into
mainfrom
fix/fence-lab-uis
Nov 11, 2026
Merged

Gerrrt merged 3 commits into
mainfrom
fix/fence-lab-uis

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Nov 11, 2026

Copy link
Copy Markdown
Owner

What changed

soc's #1139 fence, applied to the three other web UIs on VLAN 30:

  • stacks/lab (alexander): Grafana is expose-only. The existing caddy (the ingest proxy) gains a :3443 site, published on the host port Grafana had (GRAFANA_PORT, default 3000). It terminates TLS with Grafana's own leaf, verifies the upstream against certificates/ca.pem as grafana (the SAN its cert carries), answers remote_ip 10.0.50.0/24, and returns 403 to everyone else. Caddy gets group_add: RENDER_GID to read the 0640 key, the way Grafana reads it.
  • stacks/bloodhound (eden): BloodHound is expose-only. A new caddy (bloodhound-ui-proxy) does the same on BLOODHOUND_PORT (8443), with BloodHound's leaf and upstream name bloodhound. It's hardened like the estate's Caddys: read-only, cap_drop: ALL, uid 65534, a 64m limit and a healthcheck.
  • stacks/scratch (diabolos, not yet built): the dashboard and GUI are unpublished, and a new caddy (scratch-ui-proxy) is soc's, minus the agent-MSI site, recorded as DIFFERENCE 6.
  • Docs: the three stack READMEs' port tables, and a security.md threat-table row next to the SOC UIs row.

Why

Traffic between VLAN 30 hosts never crosses pfSense, so each of these answered the whole segment, the six deliberately weak domain guests included. BloodHound's graph is the domain's attack-path map, and diabolos is where samples are detonated. You decided these get fenced before the first red-team exercise (audit finding #9).

Closes #1428.

Not in this PR: the lab ingest proxy's plain HTTP (the other half of finding #9). It needs a server certificate on alexander and a trust change on six agents, so it gets its own issue and PR next.

Blast radius

  • alexander: the lab Caddy is also the ingest proxy. If it can't read Grafana's cert or key, it fails to start, and lab ingest from six agents stops until that's fixed. It reads the same files Grafana already reads, through the same group, so I expect it to start. Check docker logs lab-ingest-proxy after the next make up STACK=lab.

  • Reachability: Grafana and BloodHound now answer Hicks only. A WireGuard peer or any other VLAN that reached them before gets 403. I found nothing server-side that probes either port; Glance's link is a browser link used from Hicks.

  • scratch: not deployed anywhere yet.

  • No change to network segmentation or firewall rules (pfSense untouched; this is in-guest source filtering)

  • No new port published to a VLAN that could not already reach the service (the same host ports, now narrower)

  • No credential added outside secrets/*.sops.yaml

Verification

  • make validate: exit 0, 164 PASS, 0 FAIL, 41 SKIP. That's two more SKIPs than main, and they're the point: bloodhound and scratch now have Caddyfiles, so their no Caddyfile — nothing to validate PASSes became no docker daemon — Caddyfile unchecked SKIPs. caddy validate and caddy fmt on all three Caddyfiles are skipped here and run in CI (the Validate Caddyfiles step, under require-no-skip.sh).

  • I parsed the three compose files: each caddy publishes the expected host ports (lab: 9090, 3100 on the ingest address, plus GRAFANA_PORT→3443; bloodhound: BLOODHOUND_PORT→8443; scratch: 443→8443, 8889→8889).

  • The Caddyfiles are tab-indented, matching caddy fmt. editorconfig-checker is clean on all changed files. markdownlint-cli2 0.24.0 found 0 issues. check_docs.py passed.

  • Not provable here: a live request from Hicks (200) versus one from VLAN 30 (403). That's for after deploy, on alexander and eden: curl -k https://10.0.30.40:3000/api/health from Hicks, and the same from a lab guest, which should get 403.

  • make validate passes (with the skips above)

  • Deployed to the lab and confirmed working (the two curl checks above, on alexander and eden)

  • Docs updated (three stack READMEs, docs/security.md)


Generated by Claude Code

Traffic inside VLAN 30 never crosses pfSense, so lab Grafana and
BloodHound, and scratch's Wazuh dashboard and Velociraptor GUI, answered
the whole segment, the weak domain included. Each is now expose-only,
behind a Caddy that publishes the same host port, terminates TLS with
the UI's own leaf, verifies the upstream against the CA, and answers
Hicks's /24 alone: soc's #1139 shape. The READMEs and security.md follow.

Closes #1428.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2EweeKAdMf5A1aeFy1anN
Copilot AI balanced review requested due to automatic review settings November 11, 2026 20:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@Gerrrt
Gerrrt enabled auto-merge (squash) November 11, 2026 21:24

Gerrrt commented Nov 11, 2026

Copy link
Copy Markdown
Owner Author

Lint failed on 3d2622b for a reason unrelated to this PR. docker run of the pinned hashicorp/packer image got 502 Bad Gateway from registry-1.docker.io on two blob pulls, so the packer step never ran. This PR changes no packer files. Every other Lint step passed: shellcheck, actionlint, zizmor, markdownlint, tofu, ansible-lint and editorconfig-checker.

There's no fix to port, because the cause is the registry. GitHub refused to re-run the job while the rest of the run was still going, so I'll re-run it once when the run finishes.


Generated by Claude Code

…d and scratch headers

Validate configs' caddy fmt check failed on both new Caddyfiles for the one
blank line between the header comment and the global block, which soc's
Caddyfile does not have. Both adapted and provisioned already; only the
format check failed. Local runs skipped it for want of a docker daemon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2EweeKAdMf5A1aeFy1anN
@Gerrrt
Gerrrt merged commit 949c332 into main Nov 11, 2026
8 checks passed
@Gerrrt
Gerrrt deleted the fix/fence-lab-uis branch November 11, 2026 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lab Grafana and BloodHound answer all of VLAN 30; scratch re-exposes the SOC UIs #1139 fenced

3 participants