Jenkins Build - SS67/project-docs GitHub Wiki

VM Compliance Orchestrator: Design and Scaffold

AAP 2.6 native. Windows and Linux. Replaces the Jenkins orchestration plan.

Decisions made

Question Decision Reason
Orchestrator AAP, not Jenkins Inventory, Vault creds and child workflows already live there
Discovery source vSphere dynamic inventory Already syncing every 15 min
Lookup key vm_guest_hostname Webhook caller knows OS hostname, not vSphere VM name
OS classification vm_guest_full_name vm_guest_os reports the configured guest ID and lies
Domain detection Auth success with domain service account Real evidence. DNS lookup only proves a record exists
Approved domains dev.company.com, idm.dev.company.com Prod removed from scope entirely
Human approval None in pipeline Running the bootstrap script is the consent
Bootstrap credential Random per host, Vault KV v2 Shared static password is one host away from estate wide compromise
Compliance evidence Host side, single collection job One AAP launch per run, not one per control
vm_attr_* fields Hints only, never proof Likely written by our own workflows, so validating against them is circular

Final status values: compliant, remediated, partial, failed, join_unverified, remediation_unverified, host_not_in_inventory.

Project scaffold

vm-compliance-orchestrator/
├── ansible.cfg                                jinja2_native=True
├── collections/requirements.yml
├── inventory/                                 uses existing vSphere source
├── playbooks/
│   ├── orchestrate.yml                        entry point, webhook target
│   ├── discover.yml                           inventory lookup + OS classify
│   ├── preflight.yml                          all guards
│   ├── domain_join.yml                        routes windows vs linux
│   ├── collect_evidence.yml                   single pass, all controls
│   ├── remediate.yml                          conditional child launches
│   ├── cleanup.yml                            always runs
│   └── report.yml
├── roles/
│   ├── bootstrap_credential/
│   │   └── tasks/
│   │       ├── main.yml                       fetch from Vault, set conn vars
│   │       └── destroy.yml                    account removal + Vault destroy
│   ├── host_discovery/
│   │   └── tasks/main.yml                     lookup, retry, classify
│   ├── domain_join/
│   │   ├── defaults/main.yml                  approved domain map
│   │   └── tasks/
│   │       ├── main.yml                       routing
│   │       ├── preflight.yml
│   │       ├── windows.yml                    win_domain_membership + reboot
│   │       ├── linux.yml                      ipaclient
│   │       └── verify.yml                     independent confirmation
│   ├── compliance_evidence/
│   │   ├── defaults/main.yml                  thresholds, control enable flags
│   │   ├── tasks/
│   │   │   ├── main.yml                       assembles controls dict
│   │   │   ├── defender_windows.yml
│   │   │   ├── defender_linux.yml
│   │   │   ├── rapid7_windows.yml
│   │   │   ├── rapid7_linux.yml
│   │   │   ├── sccm.yml                       windows only
│   │   │   ├── wsus.yml                       windows standalone only
│   │   │   └── aap.yml
│   │   └── vars/main.yml                      service names, registry paths
│   ├── compliance_evaluate/
│   │   └── tasks/main.yml                     one rule applied to all controls
│   └── local_account/
│       └── tasks/
│           ├── windows.yml
│           └── linux.yml
├── templates/
│   └── compliance_report.json.j2
└── scripts/
    ├── bootstrap_windows.ps1                  user runs on target VM
    └── bootstrap_linux.sh

AAP objects

Job templates:

VMC Discover
VMC Preflight
VMC Domain Join
VMC Collect Evidence
VMC Evaluate
VMC Cleanup
VMC Report

Workflow template VMC Orchestrate chains them. Existing onboarding workflows attach as child nodes off the evaluate result. Enable webhook on the workflow, not on individual templates.

Credentials:

Vault Bootstrap AppRole      existing pattern, extend it
AD Join Custom               vault path secret/infra/dev/ad_join
IdM Join Custom              vault path secret/infra/dev/idm_join

Every input source binding sets Path to Auth = approle. Skip it and default_auth_path KeyError fires silently.

Join accounts get create computer object on the target OU only. Not domain admin.

Instance group: default is fine. Nothing here depends on local disk state.

Implementation sequence

  1. compliance_evidence role and job template. Read only, no writes. Run against 20 hosts and tune the health indicators. This also tells you how wrong the vm_attr_* values are.
  2. Discovery and classification. Report only across the estate. No remediation yet.
  3. Bootstrap script rewrite: random password on Windows to match the Linux ephemeral key model.
  4. Wire remediation for one control. Rapid7 first, low blast radius.
  5. Domain join port from Jenkins, run alongside the existing pipeline in report only mode until trusted.
  6. Remaining controls.
  7. Retire the Jenkins pipeline.

Steps 1 and 2 give a full compliance picture before anything on a host changes.

Open items

  1. Bootstrap script currently uses a fixed Windows password. Same value everywhere it has ever run. Fix in step 3.
  2. AAP Onboarding as a workflow may not exist. If the vSphere dynamic inventory already picks up every VM, it is a validation check, not a remediation. Confirm what it does today.
  3. Rapid7 has no vm_attr_* equivalent. Host side check only.
  4. Rotation job template for standalone and custom domain hosts. Per host value, not shared. Not MVP, but add the group now so it has a target.
  5. A host joined to a different domain looks identical to standalone from an auth failure. Accepted for dev scope. Do not carry the assumption anywhere near prod.
  6. Report retention on evidence artifacts. Currently unbounded.
⚠️ **GitHub.com Fallback** ⚠️