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`

View File

@@ -2,7 +2,7 @@
# ASTRAL Security Review Questionnaire
Prepared: 2026-03-27
Prepared: 2026-04-20
This appendix is a shorter, copy/paste-friendly companion to the full ASTRAL security review package.
@@ -12,21 +12,21 @@ This appendix is a shorter, copy/paste-friendly companion to the full ASTRAL sec
| What deployment modes are supported? | The same repository can be operated in progressive modes: backup-only, review package, or full package with restore/remediation. AI is optional in all modes. |
| Is it a public-facing application? | No. It is an administrative pipeline workflow with no public UI or inbound application endpoint created by this repository. |
| Does it require inbound network access from the internet? | No. The implemented workflow is outbound-only over HTTPS. |
| What production systems does it access? | Microsoft Graph for Intune and Entra configuration, plus Azure DevOps APIs for pull request and pipeline operations. |
| What production systems does it access? | Microsoft Graph for Intune and Entra configuration and audit logs; Azure DevOps APIs for pull request and pipeline operations; Azure Storage (Table and Queue) for probe state and trigger messages. |
| Does it make production changes? | Backup and review pipelines are read-oriented against Microsoft Graph. The restore pipeline is write-capable and can apply approved baseline configuration back to the tenant when explicitly enabled and authorized. |
| What data is processed? | Administrative configuration data such as Intune policies, device configuration, enrollment profiles, apps, scripts, conditional access, named locations, authentication strengths, app registrations, and enterprise application metadata. |
| Does it process end-user business content? | It is not designed for business content. However, exported admin-authored scripts or custom payloads can contain sensitive operational data if the tenant already stores it there. |
| Where is data stored? | In the Azure DevOps Git repository, Azure DevOps pull requests/threads, build logs, and optional build artifacts such as markdown, HTML, and PDF documentation. |
| How does it authenticate to Microsoft Graph? | By obtaining a Microsoft Graph token at runtime through an Azure DevOps Azure service connection using workload identity / federated credential flow. |
| How does it authenticate to Azure DevOps APIs? | With `System.AccessToken` scoped to the pipeline identity. |
| Are long-lived secrets stored in the repository? | The pipeline logic does not require repository-stored application secrets. Runtime tokens are acquired during pipeline execution, but exported tenant content should still be treated as potentially sensitive and reviewed for embedded secrets in admin-authored scripts or custom payloads. |
| Are long-lived secrets stored in the repository? | The pipeline logic does not require repository-stored application secrets. The change probe app secret is stored in Azure Function App settings, not in the repository. Runtime tokens are acquired during pipeline execution, but exported tenant content should still be treated as potentially sensitive and reviewed for embedded secrets in admin-authored scripts or custom payloads. |
| How are secrets handled in the pipeline? | The Graph access token is set as a secret pipeline variable. The implementation logs token claims and granted roles for diagnostics, but not the token value. |
| What minimum permissions are required? | Read-only Microsoft Graph application permissions for backup/review, and additional write permissions only for restore. Exact permissions are listed in the full package. |
| Is there separation between read and write access? | The code supports a safe separation model. For production, create separate read-only and write-enabled service principals/connections so backup and restore use different identities. |
| What change-control mechanism exists? | Drift is committed to dedicated workload branches and reviewed through rolling pull requests into `main`. New rolling PRs can be created as drafts until the automated summary is inserted, and optional per-file change-ticket threads and reviewer `/reject` commands are supported. |
| Can reviewers block or scope changes? | Yes. Reviewers can approve the rolling PR, reject it, or reject individual file-level drift items through PR threads when that feature is enabled. |
| Is rollback supported? | Yes. The restore pipeline supports full restore, selective restore by file path, historical restore by Git ref, and dry-run mode. |
| What external network destinations are required? | Microsoft Graph, Azure DevOps APIs, optional Azure OpenAI, Python package registry for `IntuneCD`, npm registry for `md-to-pdf`, and optionally OS package repositories when browser dependencies are installed for HTML/PDF generation. |
| What external network destinations are required? | Microsoft Graph, Azure DevOps APIs, Azure Storage (Table and Queue), optional Azure OpenAI, Python package registry for `IntuneCD`, npm registry for `md-to-pdf`, and optionally OS package repositories when browser dependencies are installed for HTML/PDF generation. |
| Does the system send data to AI services? | Only if Azure OpenAI summary generation is explicitly configured. It is optional for the platform overall. |
| What AI service is intended? | A customer-controlled Azure OpenAI deployment configured through the Azure OpenAI endpoint and deployment variables, rather than an unrelated public AI service. |
| What data is sent to Azure OpenAI when enabled? | A reduced change-review payload containing changed paths, semantic summaries, deterministic summary text, and fingerprints derived from the repo diff. This is intended to support review summarization, not raw tenant-wide export ingestion. |