Sync from dev @ 252c1cf
Source: main (252c1cf) Excluded: live tenant exports, generated artifacts, and dev-only tooling.
This commit is contained in:
422
README.md
Normal file
422
README.md
Normal file
@@ -0,0 +1,422 @@
|
||||
# Intune / Entra Drift Backup
|
||||
|
||||
This repository keeps Git-tracked snapshots of Microsoft Intune and selected Entra ID configuration, generates review reports, and drives a rolling pull-request workflow for post-change review and remediation.
|
||||
|
||||
> **Product name:** ASTRAL (Admin Security Through Review, Automation & Least-privilege)
|
||||
|
||||
## Getting Started
|
||||
|
||||
This repository is designed to be forked or downloaded into your own Azure DevOps organization. Each tenant gets its own project and pipeline instance.
|
||||
|
||||
Quick start:
|
||||
|
||||
1. Fork or import this repository into an Azure DevOps project.
|
||||
2. Review `templates/variables-tenant.yml` and create a matching Azure DevOps Variable Group in your project (e.g. `vg-astral-tenant`).
|
||||
3. Uncomment the variable group reference in the three pipeline YAMLs.
|
||||
4. Run `deploy/bootstrap-tenant.ps1` to create the Azure AD app registration, assign Graph permissions, and configure the federated credential.
|
||||
5. Create the Azure DevOps service connection using the app registration details from the bootstrap script.
|
||||
6. Import the three pipelines (`azure-pipelines.yml`, `azure-pipelines-review-sync.yml`, `azure-pipelines-restore.yml`) into Azure DevOps.
|
||||
7. Run `deploy/validate-deployment.yml` to verify connectivity and permissions.
|
||||
8. Set `AUTO_REMEDIATE_RESTORE_PIPELINE_ID` in your variable group after the restore pipeline is imported.
|
||||
|
||||
See [`deploy/onboarding-runbook.md`](deploy/onboarding-runbook.md) for the full step-by-step guide.
|
||||
|
||||
## What The Repository Does
|
||||
|
||||
The implementation is centered on three Azure DevOps pipelines:
|
||||
|
||||
- `azure-pipelines.yml`: hourly backup/export pipeline with rolling PR management.
|
||||
- `azure-pipelines-review-sync.yml`: 20-minute reviewer-decision sync and post-merge remediation queue.
|
||||
- `azure-pipelines-restore.yml`: manual or auto-queued restore pipeline for approved baseline rollback.
|
||||
|
||||
The main workflow is:
|
||||
|
||||
1. Export Intune and Entra configuration into `tenant-state/`.
|
||||
2. Generate Markdown/CSV reports in `tenant-state/reports/`.
|
||||
3. Filter known non-actionable drift noise before commit.
|
||||
4. Commit workload drift to `drift/intune` and `drift/entra`.
|
||||
5. Create or update one rolling PR per workload into `main`.
|
||||
6. Refresh the PR description with deterministic change/risk summary and optional Azure OpenAI narrative.
|
||||
7. Apply reviewer `/reject` or `/accept` decisions and queue restore when needed.
|
||||
|
||||
This is an ex-post change-management model: admins can change settings in the Microsoft admin portals, and the repo turns those changes into auditable Git drift with a review and rollback path.
|
||||
|
||||
## Current Baseline Coverage
|
||||
|
||||
Intune currently tracks:
|
||||
|
||||
- App Configuration
|
||||
- App Protection
|
||||
- Apple Push Notification
|
||||
- Apple VPP Tokens
|
||||
- Applications
|
||||
- Compliance Policies
|
||||
- Device Configurations
|
||||
- Device Management Settings
|
||||
- Enrollment Configurations
|
||||
- Enrollment Profiles
|
||||
- Filters
|
||||
- Scope Tags
|
||||
- Scripts
|
||||
- Settings Catalog
|
||||
|
||||
Entra currently tracks:
|
||||
|
||||
- Named Locations
|
||||
- Authentication Strengths
|
||||
- Conditional Access
|
||||
- App Registrations
|
||||
- Enterprise Applications
|
||||
|
||||
Current scope behavior:
|
||||
|
||||
- Named Locations, Authentication Strengths, and Conditional Access run on hourly light runs and midnight full runs.
|
||||
- App Registrations and Enterprise Applications are enabled in the pipeline but exported only on full runs.
|
||||
- During light runs, the previous drift-branch snapshot of `App Registrations` and `Enterprise Applications` is preserved to avoid churn and heavy export cost.
|
||||
|
||||
## Repository Layout
|
||||
|
||||
- `README.md`: operational overview.
|
||||
- `azure-pipelines.yml`: backup/export, report generation, drift commit, rolling PR, and docs/artifact flow.
|
||||
- `azure-pipelines-review-sync.yml`: reviewer decision sync and post-merge remediation helper.
|
||||
- `azure-pipelines-restore.yml`: baseline restore pipeline with full or selective scope.
|
||||
- `docs/m365-baseline-roadmap.md`: expansion roadmap beyond current workload scope.
|
||||
- `docs/security-review-package.md`: implementation-focused security review package.
|
||||
- `docs/security-review-questionnaire.md`: short-form security review answers.
|
||||
- `scripts/`: export, reporting, PR automation, validation, and remediation helpers.
|
||||
- `tests/`: focused unit coverage for the Python helpers.
|
||||
- `tenant-state/intune`: committed Intune JSON export.
|
||||
- `tenant-state/entra`: committed Entra JSON export.
|
||||
- `tenant-state/reports/intune`: Intune CSV/Markdown reports.
|
||||
- `tenant-state/reports/entra`: Entra CSV/Markdown reports.
|
||||
- `prod-as-built.md`: generated as-built document source.
|
||||
- `md2pdf/`: HTML/PDF styling and config for documentation publish.
|
||||
|
||||
## Pipeline Model
|
||||
|
||||
### Main Backup Pipeline
|
||||
|
||||
`azure-pipelines.yml` runs hourly on `main`.
|
||||
|
||||
For Intune it:
|
||||
|
||||
1. Prepares `drift/intune` from `main`.
|
||||
2. Chooses light vs full mode from the configured local timezone, with `forceFullRun=true` override.
|
||||
3. Runs IntuneCD export.
|
||||
4. Reverts partial Settings Catalog exports with `scripts/filter_intune_partial_settings_noise.py`.
|
||||
5. Resolves assignment group names from Graph when needed.
|
||||
6. Generates assignment and object inventory reports.
|
||||
7. Validates outputs with `scripts/validate_backup_outputs.py`.
|
||||
8. Commits drift and updates the rolling PR flow.
|
||||
|
||||
For Entra it:
|
||||
|
||||
1. Prepares `drift/entra` from `main`.
|
||||
2. Chooses effective export scope per mode.
|
||||
3. Exports selected categories with `scripts/export_entra_baseline.py`.
|
||||
4. Resolves Conditional Access reference names with `scripts/resolve_ca_references.py`.
|
||||
5. Generates assignment, app, and object inventory reports.
|
||||
6. Validates outputs with `scripts/validate_backup_outputs.py`.
|
||||
7. Reverts enrichment-only JSON churn with `scripts/filter_entra_enrichment_noise.py`.
|
||||
8. Commits drift with `scripts/commit_entra_drift.py`.
|
||||
|
||||
### Review Sync Pipeline
|
||||
|
||||
`azure-pipelines-review-sync.yml` runs every 20 minutes on `main` and exists to shorten the reviewer feedback loop.
|
||||
|
||||
Per workload it can:
|
||||
|
||||
- apply reviewer `/reject` and `/accept` decisions with `scripts/apply_reviewer_rejections.py`
|
||||
- refresh the automated PR summary
|
||||
- queue restore after merged PRs that contained reviewer `/reject` decisions using `scripts/queue_post_merge_restore.py`
|
||||
|
||||
### Restore Pipeline
|
||||
|
||||
`azure-pipelines-restore.yml` restores from approved baseline (`main` by default) or from a historical branch, tag, or commit.
|
||||
|
||||
Supported restore modes:
|
||||
|
||||
- `full`: restore the full committed Intune baseline
|
||||
- `selective`: restore only selected file paths
|
||||
|
||||
It also supports optional Entra update when restore automation is triggered for Entra review outcomes.
|
||||
|
||||
## Schedule And Run Modes
|
||||
|
||||
- Main backup schedule: hourly, `0 * * * *`, on `main`
|
||||
- Review sync schedule: every 20 minutes, `*/20 * * * *`, on `main`
|
||||
- Full mode: configured full-run hour (default 00:00) or manual queue with `forceFullRun=true`
|
||||
- Light mode: every other scheduled hour
|
||||
|
||||
Full mode adds:
|
||||
|
||||
- full Entra scope, including App Registrations and Enterprise Applications
|
||||
- Intune split-documentation generation
|
||||
- HTML/PDF artifact generation when browser dependencies are available
|
||||
- optional tagging and documentation publish steps
|
||||
|
||||
## Branch And PR Model
|
||||
|
||||
- Baseline branch: `main`
|
||||
- Drift branches:
|
||||
- `drift/intune`
|
||||
- `drift/entra`
|
||||
|
||||
Each workload keeps one rolling PR open to `main`.
|
||||
|
||||
Key behavior:
|
||||
|
||||
- reports are generated in `tenant-state/reports/*` but excluded from rolling drift commits and PR diffs
|
||||
- rolling PRs can be created as draft first, then published after automated summary generation when `ROLLING_PR_DELAY_REVIEWER_NOTIFICATIONS=true`
|
||||
- merge strategy for the rolling PR is controlled by `ROLLING_PR_MERGE_STRATEGY` and defaults to `rebase`
|
||||
|
||||
## Review, Tickets, And Remediation
|
||||
|
||||
The PR automation currently supports:
|
||||
|
||||
- deterministic operation counts and risk assessment
|
||||
- rename-aware semantic comparison
|
||||
- stable change fingerprinting for idempotent summary refresh
|
||||
- optional Azure OpenAI reviewer narrative
|
||||
- optional per-file `Change Needed` review threads when `REQUIRE_CHANGE_TICKETS=true`
|
||||
|
||||
Reviewer thread commands:
|
||||
|
||||
- `/reject`: remove that file-level drift from the rolling PR by resetting it to baseline
|
||||
- `/accept`: keep that file in PR scope
|
||||
|
||||
Supported remediation paths:
|
||||
|
||||
1. Reject and abandon a whole rolling PR.
|
||||
The next run can detect the matching rejected snapshot and queue restore automatically.
|
||||
2. Reject selected files in ticket threads, then merge the accepted remainder.
|
||||
The review-sync pipeline can queue restore after merge so the tenant is reconciled to the merged baseline.
|
||||
3. Queue `azure-pipelines-restore.yml` manually for full or selective historical rollback.
|
||||
|
||||
## Key Variables
|
||||
|
||||
Core repo and branch settings:
|
||||
|
||||
- `BASELINE_BRANCH`
|
||||
- `DRIFT_BRANCH_INTUNE`
|
||||
- `DRIFT_BRANCH_ENTRA`
|
||||
- `ROLLING_PR_TITLE_INTUNE`
|
||||
- `ROLLING_PR_TITLE_ENTRA`
|
||||
- `BACKUP_FOLDER`
|
||||
- `INTUNE_BACKUP_SUBDIR`
|
||||
- `ENTRA_BACKUP_SUBDIR`
|
||||
- `REPORTS_SUBDIR`
|
||||
|
||||
Workload toggles:
|
||||
|
||||
- `ENABLE_WORKLOAD_INTUNE`
|
||||
- `ENABLE_WORKLOAD_ENTRA`
|
||||
- `ENABLE_ENTRA_CONDITIONAL_ACCESS`
|
||||
|
||||
Intune behavior:
|
||||
|
||||
- `INTUNECD_VERSION`
|
||||
- `EXCLUDE_SCRIPT_BACKUP`
|
||||
- `INTUNE_EXCLUDE_CSV`
|
||||
- `SPLIT_DOCUMENTATION`
|
||||
|
||||
Entra behavior:
|
||||
|
||||
- `ENTRA_INCLUDE_NAMED_LOCATIONS`
|
||||
- `ENTRA_INCLUDE_AUTHENTICATION_STRENGTHS`
|
||||
- `ENTRA_INCLUDE_CONDITIONAL_ACCESS`
|
||||
- `ENTRA_INCLUDE_APP_REGISTRATIONS`
|
||||
- `ENTRA_INCLUDE_ENTERPRISE_APPS`
|
||||
- `ENTRA_ENTERPRISE_APP_WORKERS`
|
||||
|
||||
PR and reviewer automation:
|
||||
|
||||
- `ENABLE_PR_REVIEW_SUMMARY`
|
||||
- `ENABLE_PR_REVIEWER_DECISIONS`
|
||||
- `ROLLING_PR_DELAY_REVIEWER_NOTIFICATIONS`
|
||||
- `ROLLING_PR_MERGE_STRATEGY`
|
||||
- `REQUIRE_CHANGE_TICKETS`
|
||||
- `CHANGE_TICKET_REGEX`
|
||||
- `DEBUG_CHANGE_TICKET_THREADS`
|
||||
|
||||
Auto-remediation:
|
||||
|
||||
- `AUTO_REMEDIATE_ON_PR_REJECTION`
|
||||
- `AUTO_REMEDIATE_AFTER_MERGE`
|
||||
- `AUTO_REMEDIATE_AFTER_MERGE_LOOKBACK_HOURS`
|
||||
- `AUTO_REMEDIATE_RESTORE_PIPELINE_ID`
|
||||
- `AUTO_REMEDIATE_DRY_RUN`
|
||||
- `AUTO_REMEDIATE_UPDATE_ASSIGNMENTS`
|
||||
- `AUTO_REMEDIATE_REMOVE_OBJECTS`
|
||||
- `AUTO_REMEDIATE_MAX_WORKERS`
|
||||
- `AUTO_REMEDIATE_EXCLUDE_CSV`
|
||||
|
||||
Azure OpenAI integration:
|
||||
|
||||
- `ENABLE_PR_AI_SUMMARY`
|
||||
- `AZURE_OPENAI_ENDPOINT`
|
||||
- `AZURE_OPENAI_DEPLOYMENT`
|
||||
- `AZURE_OPENAI_API_KEY`
|
||||
- `AZURE_OPENAI_API_VERSION`
|
||||
- `PR_AI_PAYLOAD_MAX_BYTES`
|
||||
- `PR_AI_MAX_TOKENS`
|
||||
- `PR_AI_COMPACT_MAX_CHARS`
|
||||
|
||||
## Required Azure DevOps Permissions
|
||||
|
||||
The pipeline build identity should have repository permissions to:
|
||||
|
||||
- contribute
|
||||
- create branch
|
||||
- force push
|
||||
- create and update pull requests
|
||||
- create tag if tagging is enabled
|
||||
|
||||
For auto-queued restore, the same identity also needs on `azure-pipelines-restore.yml`:
|
||||
|
||||
- `View builds`
|
||||
- `Queue builds`
|
||||
- pipeline authorization if explicit pipeline permissions are enforced
|
||||
|
||||
Also enable script access to `System.AccessToken`.
|
||||
|
||||
## Required Microsoft Graph Application Permissions
|
||||
|
||||
Baseline read permissions used by the current implementation:
|
||||
|
||||
- `Device.Read.All`
|
||||
- `DeviceManagementApps.Read.All`
|
||||
- `DeviceManagementConfiguration.Read.All`
|
||||
- `DeviceManagementManagedDevices.Read.All`
|
||||
- `DeviceManagementRBAC.Read.All`
|
||||
- `DeviceManagementScripts.Read.All`
|
||||
- `DeviceManagementServiceConfig.Read.All`
|
||||
- `Group.Read.All`
|
||||
- `Policy.Read.All`
|
||||
- `Policy.Read.ConditionalAccess`
|
||||
- `Policy.Read.DeviceConfiguration`
|
||||
- `User.Read.All`
|
||||
|
||||
Additional read permissions used by the current Entra scope:
|
||||
|
||||
- `Application.Read.All`
|
||||
- `RoleManagement.Read.Directory` or `Directory.Read.All` for richer name resolution
|
||||
- `AuditLog.Read.All` for best-effort Entra drift author attribution
|
||||
|
||||
Restore pipeline write permissions:
|
||||
|
||||
- `DeviceManagementApps.ReadWrite.All`
|
||||
- `DeviceManagementConfiguration.ReadWrite.All`
|
||||
- `DeviceManagementManagedDevices.ReadWrite.All`
|
||||
- `DeviceManagementRBAC.ReadWrite.All`
|
||||
- `DeviceManagementScripts.ReadWrite.All`
|
||||
- `DeviceManagementServiceConfig.ReadWrite.All`
|
||||
- `Group.Read.All`
|
||||
|
||||
Additional restore permission when `includeEntraUpdate=true`:
|
||||
|
||||
- `Policy.Read.All`
|
||||
- `Policy.ReadWrite.ConditionalAccess`
|
||||
|
||||
## Outputs
|
||||
|
||||
Intune outputs:
|
||||
|
||||
- JSON backup under `tenant-state/intune/**`
|
||||
- `tenant-state/reports/intune/policy-assignments.md`
|
||||
- `tenant-state/reports/intune/policy-assignments.csv`
|
||||
- `tenant-state/reports/intune/object-inventory-all.csv`
|
||||
- `tenant-state/reports/intune/Object Inventory/*-inventory.csv`
|
||||
|
||||
Entra outputs:
|
||||
|
||||
- JSON backup under `tenant-state/entra/**`
|
||||
- `tenant-state/reports/entra/policy-assignments.md`
|
||||
- `tenant-state/reports/entra/policy-assignments.csv`
|
||||
- `tenant-state/reports/entra/apps-inventory.csv`
|
||||
- `tenant-state/reports/entra/object-inventory-all.csv`
|
||||
- `tenant-state/reports/entra/Object Inventory/*-inventory.csv`
|
||||
|
||||
Full-run documentation artifacts:
|
||||
|
||||
- `prod-as-built-split-markdown`
|
||||
- `prod-as-built-split-html`
|
||||
- `prod-as-built-split-pdf`
|
||||
|
||||
## Local Script Usage
|
||||
|
||||
Generate Entra export locally:
|
||||
|
||||
```bash
|
||||
python3 ./scripts/export_entra_baseline.py \
|
||||
--root ./tenant-state/entra \
|
||||
--token "$GRAPH_TOKEN" \
|
||||
--enterprise-app-workers 8
|
||||
```
|
||||
|
||||
Resolve Conditional Access references:
|
||||
|
||||
```bash
|
||||
python3 ./scripts/resolve_ca_references.py \
|
||||
--root ./tenant-state/entra \
|
||||
--token "$GRAPH_TOKEN"
|
||||
```
|
||||
|
||||
Generate Intune assignment report:
|
||||
|
||||
```bash
|
||||
python3 ./scripts/generate_assignment_report.py \
|
||||
--root ./tenant-state/intune \
|
||||
--output-dir ./tenant-state/reports/intune
|
||||
```
|
||||
|
||||
Generate Entra assignment report:
|
||||
|
||||
```bash
|
||||
python3 ./scripts/generate_assignment_report.py \
|
||||
--root ./tenant-state/entra \
|
||||
--output-dir ./tenant-state/reports/entra
|
||||
```
|
||||
|
||||
Generate Entra apps inventory:
|
||||
|
||||
```bash
|
||||
python3 ./scripts/generate_app_inventory_report.py \
|
||||
--root ./tenant-state/entra \
|
||||
--output-dir ./tenant-state/reports/entra
|
||||
```
|
||||
|
||||
Generate workload object inventories:
|
||||
|
||||
```bash
|
||||
python3 ./scripts/generate_object_inventory_reports.py \
|
||||
--root ./tenant-state/intune \
|
||||
--output-dir ./tenant-state/reports/intune
|
||||
|
||||
python3 ./scripts/generate_object_inventory_reports.py \
|
||||
--root ./tenant-state/entra \
|
||||
--output-dir ./tenant-state/reports/entra
|
||||
```
|
||||
|
||||
Validate backup outputs:
|
||||
|
||||
```bash
|
||||
python3 ./scripts/validate_backup_outputs.py \
|
||||
--workload intune \
|
||||
--mode light \
|
||||
--root ./tenant-state/intune \
|
||||
--reports-root ./tenant-state/reports/intune
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
The repository includes focused unit tests for:
|
||||
|
||||
- Entra export behavior
|
||||
- backup output validation
|
||||
- rolling PR creation/update logic
|
||||
- PR summary generation
|
||||
- reviewer rejection processing
|
||||
- post-merge restore queueing
|
||||
- Intune partial-export noise filtering
|
||||
- Entra enrichment-noise filtering
|
||||
Reference in New Issue
Block a user