feat: add AD drift reconciliation for passwords and group membership - #398
Merged
Merged
Conversation
**Added:** - Password reconciliation task that authenticates each user with the configured password and resets only accounts that fail, handling lockouts and skipping Protected Users members - `roles/ad/tasks/reconcile_passwords.yml` - Credential probe safety check that aborts if a nonexistent principal authenticates, preventing the role from silently becoming a no-op - Group membership reconciliation task that diffs lab-managed groups against config and removes unexpected members, skipping cross-domain members, machine accounts, built-in principals (RID < 1000), and protected accounts - `roles/ad/tasks/reconcile_group_membership.yml` - Role defaults declaring `ad_reconcile_passwords`, `ad_reconcile_group_membership`, `ad_reconcile_check_only`, `ad_reconcile_protected_accounts`, and `ad_multi_domain_groups_member` - `roles/ad/defaults/main.yml` - Repeatable `--extra-vars`/`-E` flag on `provision`, `ad-users`, and `lab reset` to pass Ansible variables from the command line, primarily to enable `ad_reconcile_check_only=true` dry runs - `cli/cmd/provision.go`, `cli/cmd/lab_reset.go` - `parseExtraVars`, `applyExtraVars`, and `sortedPairs` helpers, with user vars layered over SOCKS tunnel vars so explicit `-e` always wins - `cli/cmd/provision.go` - Test coverage for extra-vars parsing, malformed rejection, precedence layering, and stable rendering - `cli/cmd/provision_test.go` - Documented default variables and new reconciliation tasks in role docs - `roles/ad/README.md` **Changed:** - Wired `ad_multi_domain_groups_member` into the ad-data play so the membership reconciler recognises same-domain principals declared via cross-domain groups - `playbooks/ad-data.yml` - Ordered reconciliation tasks after all add-member steps in the ad role so they diff against a fully built baseline - `roles/ad/tasks/main.yml` - Threaded `extraVars` through `provisionPlaybooks` and added structured logging on provisioning success and failure - `cli/cmd/provision.go` - Expanded `lab reset` help and examples to document that Stage 2 reconciles drift and how to rehearse with `ad_reconcile_check_only=true` - `cli/cmd/lab_reset.go`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Key Changes:
lab resetconverges on the declared baseline instead of a superset, since both operations were previously add-only and left attack-run changes in place-E/--extra-varsCLI flag acrossprovision,ad-users, andlab reset, enablingad_reconcile_check_only=truedry-runs to report drift without correcting itAdded:
reconcile_group_membership.ymldiffs each lab-managed group against config and removes unexpected members via PowerShell, filtering foreign SIDs, computer accounts, built-in RIDs, and protected accountsreconcile_passwords.ymlauthenticates each user with its configured password viaLogonUserand resets only accounts that fail, including a credential probe that aborts if the host authenticates a nonexistent principal, plus lockout clearing and Protected Users handlingdefaults/main.ymlfor theadrole definingad_reconcile_passwords,ad_reconcile_group_membership,ad_reconcile_check_only,ad_reconcile_protected_accounts, andad_multi_domain_groups_memberparseExtraVars,applyExtraVars, andsortedPairshelpers inprovision.go, wired the sharedextraVarsUsageflag intoprovision,ad-users, andlab reset, and layered user vars over SOCKS tunnel connection varsprovision_test.govalidating extra-vars parsing edge cases, precedence rules, caller-map immutability, and stable renderingadrole READMEChanged:
adrole'smain.ymlafter all add-member tasks, guarded by their enable flags, so they reconcile against a fully built baselinead_multi_domain_groups_memberthroughad-data.ymlso the membership reconciler recognizes same-domain principals applied by the latergroups_domainsplay as managedprovisionPlaybooksto accept anextraVarsmap, merged into the runner'sExtraVars, and added structured success/failure logging around playbook executionlab resethelp text and examples to explain that Stage 2 now reconciles rather than only re-applies, and how to rehearse with-E ad_reconcile_check_only=true