Greenfield Azure Baseline — Infrastructure & Identity Handover
Package: Baseline "Cloud Secure" [B] (part 1 of 2) · Milestone: M2a
Scenario: Day-0 greenfield Azure client on GitHub Actions, no existing IaC.
Ownership: Primarily [CO] Client-Owned — SnowOps provisions; you own and operate after handover.
This is the infrastructure and identity half of the Baseline package. The compliance-monitoring half is covered in the M2b Compliance Monitoring Handover. A full Baseline engagement delivers both.
What You Now Own
A hardened, policy-governed Azure subscription with secure networking, identity with MFA + PIM + break-glass, an AKS-ready foundation, and a complete CI/CD pipeline with policy gates. Everything is Terraform-managed and reproducible.
| Layer | Assets | Module / Workflow |
|---|---|---|
| Subscription baseline | F1, B3 | modules/azure/baseline/, modules/azure/subscription-baseline/ (Mgmt Group, Policy, Defender, Log Analytics, MCSB) |
| Network | F2, N5, N6 | modules/azure/network-hub/, private-endpoint-policy/, nsg-baseline/ |
| Compute (AKS-ready) | F3, D4 | modules/azure/aks-secure/ + Kyverno policies (policy/kyverno/) |
| Registry | F4 | modules/azure/acr/ (Premium, private endpoint, AAD-only) |
| Secrets | F5 | modules/azure/key-vault/ (Premium, RBAC mode, purge-protect) |
| State backend | F6, B4 | modules/azure/state-backend/, client-state-backend/ |
| Identity | H1, H2, H3, H5, H7, B2, B5 | aad-baseline/, conditional-access/, pim-templates/, pim-azure-resources/, break-glass/, client-bootstrap/, apps/sp-inventory/ |
| Data protection (policy) | M1, M2, M3, M6 | encryption-policy/, cmk/, tls-policy/, data-residency-policy/ |
| Cost governance | U1, U2 | budget-alert/, tag-policy/ |
| CI/CD | C1, C2, C3 | .github/workflows/terraform-plan-apply.yml, container-build-sign.yml, aks-deploy.yml |
| Sandbox hygiene | X7 | .github/workflows/sandbox-cleanup.yml |
Module names above are the real on-disk paths under
modules/azure/. Pin every module reference to a semver tag via the F11 registry — neverref=main.
The Identity Model You Are Inheriting
This is the most important thing to understand at handover. SnowOps follows Identity > Secrets — there are deliberately no long-lived cloud credentials anywhere in your pipeline.
| Concept | What it means for your team |
|---|---|
| Federated OIDC (B2) | GitHub Actions authenticates to Azure via federated identity. No client secret exists to leak or rotate. |
| PIM — Azure resource roles (B5) | Owner/Contributor/UAA are eligible, not standing. Activate just-in-time with MFA + justification; Tier-0 (Owner) is capped at 8h with approval, Tier-1 (Contributor) at 4h. |
| PIM — Entra directory roles (H3) | Same model for directory roles, activated via the Graph PATCH rules in the runbook. |
| Break-glass (H7) | Two emergency Global Admin accounts in a role-assignable group, excluded from all Conditional Access, with a severity-0 sign-in alert. These are your last-resort access — store the credentials per the ceremony in the H7 runbook (hardware FIDO2 + split-knowledge). Test break-glass sign-in quarterly. |
| Conditional Access (H2) | 6 policies: MFA mandatory, Tier-0 phishing-resistant + compliant device, block legacy auth, geo-block, high/medium-risk gating. Every policy excludes the break-glass group. |
| SP credential hygiene (H5) | sp-inventory-rotation.yml scans app-registration credentials weekly and opens a rotation PR for anything aged/expiring. Federated-OIDC SPs never go stale. |
Day-one action for your team: confirm you can activate PIM, and run a break-glass sign-in drill so you're never locked out.
How to Deploy a Change (Your New Workflow)
Your infrastructure changes flow through the C1 pipeline (terraform-plan-apply.yml), which enforces the policy gates automatically:
1. Open a PR with a Terraform change
2. C1 runs `terraform plan` → posts the plan as a PR comment
3. The D3 OPA bundle runs against the plan JSON (post-plan gate)
4. CODEOWNER review + passing checks required (branch protection from C4)
5. Merge → C1 applies against the target environment (with environment gates)
Container workloads follow C2 (container-build-sign.yml): build → push to ACR by digest → Notation v2 sign → Syft SBOM → Grype scan. AKS deployments follow C3 (aks-deploy.yml): ArgoCD image override → sync → smoke probe → optional rollback drill.
The OPA gate (D3) and Kyverno admission policies (D4) mean non-compliant infrastructure cannot be applied — encryption, tagging, network isolation, and region constraints are enforced at plan-time and admission-time, not audited after the fact.
What This Delivers for Compliance
| Control theme | Framework reference | Asset / Evidence |
|---|---|---|
| Logical access — least privilege, JIT | SOC 2 CC6.1–CC6.3 · ISO 27001 A.8.2/A.8.3 | PIM (B5/H3), Conditional Access (H2), RBAC (B3) |
| MFA enforced | SOC 2 CC6.1 · ISO 27001 A.8.5 | Conditional Access policy export (H2) |
| Encryption at rest / in transit | SOC 2 CC6.7 · ISO 27001 A.8.24 | Deny initiatives M1/M3 + CMK (M2) |
| Network security | SOC 2 CC6.6 · ISO 27001 A.8.20/A.8.22 | F2 topology, N5/N6, private endpoints |
| Audit logging | SOC 2 CC7.2 · ISO 27001 A.8.15 | Log Analytics (F1), diagnostic policies |
| Vulnerability management | SOC 2 CC7.1 · ISO 27001 A.8.8 | Defender for Cloud (F1/B3), image signing+scan (C2) |
Full mappings:
compliance/soc2/control-mapping.md,compliance/iso27001/control-mapping.md,compliance/cis-azure/control-mapping.md.
Verification at Handover
SnowOps signs off each asset against its manual test runbook (docs/runbooks/test/<id>.md) in a sandbox before handover. To independently verify your own environment:
-
terraform planagainst each stack shows no drift (clean plan). - A deliberately non-compliant test PR (e.g. unencrypted storage) is blocked by the C1 OPA gate.
- PIM activation works for at least one Tier-0 and one Tier-1 role.
- Break-glass sign-in succeeds and fires the severity-0 alert.
- Defender for Cloud is On with the MCSB initiative assigned (B3).
- The C2 pipeline produces a signed image;
notation verifysucceeds.
Failure Modes You Should Know
| Symptom | Cause | Response |
|---|---|---|
| Pipeline can't authenticate to Azure | Federated OIDC subject mismatch (branch/environment changed) | Update the federated credential subject in B2; the repo: prefix is validated. |
| Locked out of the subscription | PIM eligibility misconfigured or expired | Use break-glass (H7) — this is exactly what it's for. |
terraform apply blocked by a Deny policy |
A resource violates M1/M3/N5/U2 | Fix the resource, or file a D5 waiver (time-boxed) if it's a temporary, justified exception. |
| AKS pod rejected at admission | Kyverno policy (D4) — unsigned image, latest tag, privileged container |
Sign the image / pin the tag / drop privilege. This is the gate working. |
Removal / Offboarding Path
Every module ships with a verified terraform destroy path (DoD #8). Because you own the state and subscription ([CO]), offboarding from SnowOps does not strand your infrastructure:
- Module sources are pinned to public git tags — they keep resolving even without SnowOps.
- Run
terraform destroyper stack to tear down, or simply keep operating the infrastructure yourself; nothing depends on SnowOps' tenancy. - Revoke the SnowOps operator's PIM eligibility and any guest access.
- For a formal handover/exit, follow the engagement offboarding checklist (M3 deliverable — see the Brownfield Adoption guide's offboarding section).
Cost note: This baseline runs real Azure resources (AKS, Premium ACR/KV, Log Analytics). Per-module estimated costs are in each module README. Budget alerts (U1) are wired in to warn at your configured thresholds.
Next
- Add compliance monitoring, backup/DR, and evidence: M2b Compliance Monitoring Handover.
- Already have infrastructure? See Brownfield Adoption.