Skip to content

feat: add lab drift reconciliation, per-environment regions, and config integrity checks - #33

Merged
l50 merged 1 commit into
mainfrom
fix/lab-reset-reconciles-password-and-group-drift
Jul 30, 2026
Merged

feat: add lab drift reconciliation, per-environment regions, and config integrity checks#33
l50 merged 1 commit into
mainfrom
fix/lab-reset-reconciles-password-and-group-drift

Conversation

@l50

@l50 l50 commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Key Changes:

  • Added password and group-membership drift reconciliation to lab reset so an attack run's changes converge back to the baseline instead of leaving the lab at a superset of the declared config
  • Introduced per-environment AWS region resolution with an explicit --region/DREADGOAD_REGION precedence chain, replacing the single inventory-derived region
  • Added a lab config referential-integrity checker that validates merged overlays, plus topology-gating and ares category-drift detection for the scoreboard
  • Parameterized hardcoded GOAD entity names (passwords, hostnames, domains) across scripts, playbooks, and the diagnose command so they work for any generated variant

Added:

  • AD drift reconciliation - New ad role passes reconcile user passwords (via real network logon probes, skipping locked and Protected Users accounts) and remove unmanaged group members while sparing cross-domain, machine, built-in (RID < 1000), and protected accounts - ansible/roles/ad/tasks/reconcile_passwords.yml, reconcile_group_membership.yml, defaults/main.yml
  • Lab config integrity checker - New labconfig package walks a merged config and reports dangling group/user/vulns_vars references, missing vuln roles, and unpaired vulnerabilities, gated by a shrink-only baseline and regression tests against the real overlays
  • Per-environment region support - Added Region to EnvironmentConfig, SetRegionOverride, and a documented resolution order in ResolveRegion, surfaced in config tracing and docs/cli.md
  • Scoreboard drift detection - AresTransport now cross-checks ares token_coverage against the technique prefix table and surfaces uncredited categories in the TUI footer and --once stderr, with the superseded set filtered out of scored objectives
  • Topology-gated technique scoring - ADCS and child-to-parent objectives are now credited only when the lab actually provisions a CA or a parent/child domain pair, with tests pinning MINILAB, SCCM, DRACARYS, TEMPLATE, and NHA behavior
  • Deeper ADCS validation - ESC6 now checks the validating DC's StrongCertificateBindingEnforcement, and ESC13 confirms the issuance-policy OID's msDS-OIDToGroupLink, so a CA-side flag alone no longer reports a non-exploitable finding as PASS
  • New lab environments and overlays - Added the GOAD-variant-1 and TEMPLATE labs and prod/staging/test overlays, and regenerated GOAD-variant-1 with randomized entities including a third domain and expanded ADCS ESC coverage

Changed:

  • PowerShell provisioning scripts - Delegation, scheduled-task, and ESC13 scripts are now idempotent (add-only SPN/delegation edits, Register-ScheduledTask -Force, OID reuse) and bot passwords are templated from the lab config, with the ps role rendering scripts as Jinja templates - ad/GOAD*/scripts/*, ansible/roles/vulns_adcs_esc13/files/esc13.ps1, ansible/roles/ps/tasks/main.yml
  • Variant generator round-trip - LabConfig structs now model os, vulns_adcs_templates, ca_web_enrollment, and sccm, and generated JSON regains its trailing newline, guarded by a key-preservation test across every lab config - cli/internal/variant/generator.go
  • Scoreboard config resolution - scoreboard generate-key and demo now resolve the active env's lab config (variant plus overlay) instead of hardcoding ad/GOAD/data/config.json
  • Inventory sync now errors on an empty discovery result rather than reporting a false "all current"
  • Diagnose command and playbook read target host/domain from the lab config instead of hardcoded guardian-app/deltasystems.local
  • Test helpers - Introduced mustHost/mustLab helpers and consolidated nil-check-then-dereference patterns across inventory, discovery, and validator tests

Removed:

  • Deleted the standalone tools/ variant-generator entry from the repo layout in favor of the CLI, and dropped the empty wwwroot/upload/.gitkeep and the essos.local group overrides that duplicated base config in GOAD overlays
  • Dropped the shares vuln from GOAD-Light dc02 and GOAD-variant-1, removing the previously-baselined "shares vuln with no vulns_vars" integrity findings

Build:

  • Bumped GitHub Actions, pre-commit hooks, .hooks/requirements.txt Python deps, the AWS/Azure Terraform providers, microsoft.ad, and the CLI's Go module dependencies to current releases

**Added:**

- Password reconciliation task that authenticates each user with the configured credential via LogonUser and resets only accounts whose password has drifted, including a credential probe to guard against APIs that falsely validate any password, plus handling for locked-out and Protected Users accounts - `reconcile_passwords.yml`
- Group membership reconciliation task that diffs each lab-managed group against config and removes unexpected members, while skipping cross-domain members, machine accounts, built-in principals (RID < 1000), and protected accounts - `reconcile_group_membership.yml`
- Default variables controlling reconciliation behavior: `ad_reconcile_passwords`, `ad_reconcile_group_membership`, `ad_reconcile_check_only`, `ad_reconcile_protected_accounts`, and `ad_multi_domain_groups_member` - `defaults/main.yml`

**Changed:**

- Wired the two reconciliation passes into the AD role after user and group tasks so `lab reset` converges on the baseline instead of a superset - `tasks/main.yml`
- Passed cross-domain group membership data into the AD data play so same-domain members applied by a later play are not treated as unmanaged - `playbooks/ad-data.yml`
- Documented the new default variables and reconciliation tasks - `roles/ad/README.md`
- Expanded the `lab reset` command help to explain that stage 2 reconciles drift rather than only re-applying, and which principals are never touched - `cli/cmd/lab_reset.go`
@l50 l50 changed the title feat: add drift reconciliation for AD passwords and group membership feat: add lab drift reconciliation, per-environment regions, and config integrity checks Jul 30, 2026
@l50
l50 merged commit 393b206 into main Jul 30, 2026
9 checks passed
@l50
l50 deleted the fix/lab-reset-reconciles-password-and-group-drift branch July 30, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant