Sync from dev @ 497baf0

Source: main (497baf0)
Excluded: live tenant exports, generated artifacts, and dev-only tooling.
This commit is contained in:
2026-04-21 22:21:43 +02:00
parent b6ac9524f7
commit 2c41eaca44
25 changed files with 2258 additions and 79 deletions

View File

@@ -2,7 +2,7 @@
# ASTRAL Security Review Package
Prepared: 2026-03-27
Prepared: 2026-04-20
## Purpose
@@ -59,34 +59,43 @@ Important clarifications:
| Azure DevOps pipeline `azure-pipelines.yml` | Scheduled backup, drift commit, rolling PR management, documentation artifact publishing | Main execution path |
| Azure DevOps pipeline `azure-pipelines-review-sync.yml` | Processes reviewer `/reject` and `/accept` decisions and refreshes PR summaries | Uses Azure DevOps API token |
| Azure DevOps pipeline `azure-pipelines-restore.yml` | Restores approved baseline to tenant | Write-capable path |
| Azure Function App (`infra/change-probe`) | Event-driven probe: polls audit logs, debounces, triggers backup pipeline on demand | Outbound-only; uses separate Entra app registration |
| Azure Table Storage | Persists probe debouncer state (`ProbeState` table) | No sensitive tenant data |
| Azure Queue Storage | Receives trigger messages from probe timer for queue consumer | No sensitive tenant data |
| Azure DevOps Git repository | Stores approved baseline, drift branches, JSON exports, reports, docs | Primary configuration store |
| Microsoft Graph | Source of Intune and Entra configuration; optional target for restore | Production tenant access |
| Azure DevOps REST APIs | PR creation/update, review thread sync, restore queueing | Change-management control plane |
| Microsoft Graph | Source of Intune and Entra configuration; optional target for restore; audit log source for probe | Production tenant access |
| Azure DevOps REST APIs | PR creation/update, review thread sync, restore queueing, pipeline trigger | Change-management control plane |
| Optional Azure OpenAI | PR summary generation only | Optional data egress path |
### High-Level Flow
```mermaid
flowchart LR
A["Azure DevOps scheduled pipeline"] --> B["Federated service connection"]
B --> C["Microsoft Graph"]
A --> D["Git repo: main + drift branches"]
A --> E["Azure DevOps PR and thread APIs"]
A --> F["Build artifacts: markdown / HTML / PDF"]
A -. optional .-> G["Azure OpenAI"]
H["Reviewer in Azure DevOps"] --> E
E --> I["Rolling PR approval / rejection"]
I -. optional remediation .-> J["Restore pipeline"]
J --> C
A["Azure Function App<br/>probe_timer"] --> B["Microsoft Graph<br/>audit logs"]
A --> C["Azure Table Storage<br/>ProbeState"]
A --> D["Azure Queue Storage<br/>backup-trigger-queue"]
E["Azure Function App<br/>queue_consumer"] --> D
E --> F["Azure DevOps REST API<br/>queue pipeline run"]
G["Azure DevOps scheduled pipeline<br/>daily snapshot + reports"] --> H["Federated service connection"]
H --> B
G --> I["Git repo: main + drift branches"]
G --> J["Azure DevOps PR and thread APIs"]
G --> K["Build artifacts: markdown / HTML / PDF"]
G -. optional .-> L["Azure OpenAI"]
M["Reviewer in Azure DevOps"] --> J
J --> N["Rolling PR approval / rejection"]
N -. optional remediation .-> O["Restore pipeline"]
O --> B
```
## Deployment Model
### Backup and Review
The main pipeline runs hourly on `main`.
The main pipeline runs daily at 02:00 on `main` to generate a full tenant snapshot, reports, and documentation artifacts. The primary trigger is the event-driven change probe, which queues the pipeline on demand when drift is detected.
- Every hour: export Intune and Entra configuration, generate reports, commit drift to rolling workload branches, and update one rolling PR per workload.
- On change detection: the probe timer polls audit logs every 5 minutes. After a 15-minute quiet window with no new events, it queues the backup pipeline.
- Daily at 02:00: export Intune and Entra configuration, generate reports, commit drift to rolling workload branches, and update one rolling PR per workload.
- When delayed reviewer notifications are enabled, newly created rolling PRs are opened as Azure DevOps draft PRs, the automated summary is inserted, and the PR is then published for reviewer notification.
- At the configured full-run hour: perform the same work plus documentation artifact generation (Markdown, and optionally HTML/PDF if browser dependencies are available).
@@ -129,6 +138,7 @@ It supports:
| Generated reports | assignment inventories, object inventories, app inventories | Derived from exported configuration | `tenant-state/reports/**` and build artifacts |
| Documentation artifacts | split markdown, optional HTML/PDF | Derived from exported configuration | build artifacts |
| Review metadata | PR descriptions, review threads, accept/reject commands | Azure DevOps reviewers | Azure DevOps PR APIs |
| Probe state | debouncer state (timestamps, enum values) | Derived from audit log evaluation | Azure Table Storage (`ProbeState`) |
| Optional AI summary payload | sampled changed paths, semantic change descriptions, deterministic summary, fingerprints | Derived from repo diff | Azure OpenAI request payload |
### Data Sensitivity Notes
@@ -145,6 +155,8 @@ It supports:
The pipelines obtain a Microsoft Graph access token at runtime using the Azure DevOps service connection configured in `SERVICE_CONNECTION_NAME` (e.g. `sc-astral-backup`).
The change probe uses a **separate Entra app registration** (`ASTRAL Change Probe`) with its own client credentials to authenticate to Microsoft Graph for audit log polling. This app is created by `deploy/provision-change-probe.ps1` and is distinct from the pipeline service connection identity.
Observed controls in the implementation:
- token acquisition is performed at runtime with `Get-AzAccessToken`,
@@ -196,6 +208,20 @@ Read-oriented Graph application permissions documented in the repository:
- `RoleManagement.Read.Directory` or `Directory.Read.All` for richer enrichment
- `AuditLog.Read.All` if commit author attribution is desired
#### Change Probe Mode
The probe app registration requires these read-only Graph application permissions:
- `AuditLog.Read.All` (reads directory and Intune audit logs)
- `DeviceManagementApps.Read.All`
- `DeviceManagementConfiguration.Read.All`
- `DeviceManagementManagedDevices.Read.All`
- `Policy.Read.All`
- `Policy.Read.ConditionalAccess`
- `Application.Read.All`
The probe does **not** require write permissions. It only polls audit logs and queues the backup pipeline.
#### Restore Mode
Write-capable Graph application permissions documented in the repository:
@@ -219,6 +245,8 @@ Write-capable Graph application permissions documented in the repository:
- Required outbound destinations are:
- `graph.microsoft.com`
- Azure DevOps organization APIs
- Azure Table Storage (for probe state)
- Azure Queue Storage (for probe trigger messages)
- optional Azure OpenAI endpoint
- Python package registry for `IntuneCD`
- npm registry for `md-to-pdf`
@@ -229,6 +257,7 @@ Write-capable Graph application permissions documented in the repository:
- Graph tokens are obtained just-in-time rather than stored in the repository.
- The pipeline marks the Graph token as a secret variable.
- The implementation logs token claims and roles for diagnostics, but not the token value itself.
- The change probe app secret is stored as an Azure Function App setting (`PROBE_APP_SECRET`), not in the repository.
- Azure OpenAI uses a pipeline secret variable when enabled.
- The pipeline logic itself does not depend on repository-stored application secrets; separate secret scanning of exported tenant content is still recommended.
@@ -329,6 +358,7 @@ The following items are not fully solved by the repository alone and should be a
| --- | --- | --- |
| Restore capability | Supported by design; can change production tenant state | Keep restore manual only, or disable auto-remediation by default until operational controls are approved |
| Backup vs restore identity separation | Sample config uses the same service connection name in backup and restore pipelines | Use separate service principals: read-only for backup/review, write-enabled only for restore |
| Change probe identity separation | Probe uses a separate Entra app registration from the pipeline service connection | Keep probe app read-only; do not grant write permissions to the probe identity |
| Azure OpenAI egress | Optional and customer-configurable | Enable only when the organization approves the payload scope and Azure OpenAI deployment model |
| Artifact retention | Not defined in repo; inherited from Azure DevOps settings | Set explicit retention for builds, logs, and artifacts |
| Repo access model | Not defined in repo | Restrict repo and artifact access to administrators/reviewers only |
@@ -400,3 +430,7 @@ The statements in this document are based on the implementation in:
- `scripts/apply_reviewer_rejections.py`
- `scripts/queue_post_merge_restore.py`
- `scripts/export_entra_baseline.py`
- `scripts/probe_tenant_changes.py`
- `scripts/trigger_backup_pipeline.py`
- `infra/change-probe/probe_timer/__init__.py`
- `infra/change-probe/queue_consumer/__init__.py`