Manual Test Runbook — H1: Azure AD Tenant Baseline
Owner: Sagar | Time: ~5 min (Parts A + B, offline) · +25 min Part C (tenant apply) · +15 min Part D (Graph PATCH steps) | Sandbox: snowops-sandbox-tenant-01
Promotes H1 (
modules/azure/aad-baseline/) from 🟦 Code Complete → 🟩 Shipped. Part C costs $0 (configuration-only). Part D is the operator-side Graph PATCH step for password protection + branding (no Terraform resource available).
Prerequisites
- Sandbox AAD tenant access (Global Administrator role active or eligible via PIM)
-
az login --tenant <SNOWOPS_SANDBOX_TENANT_ID>done;az account showconfirms the tenant - At least one verified custom domain in the sandbox tenant (e.g.,
snowops-sandbox.example.com) - Local tooling:
terraform >= 1.6,go >= 1.22,az CLI >= 2.50,jq -
SNOWOPS_SANDBOX_TENANT_IDenv var set - Working directory: repo root
Steps
Part A — terraform fmt + validate (offline, ~2 min)
- Confirm formatting + structural validity of the module:
terraform -chdir=modules/azure/aad-baseline fmt -check
terraform -chdir=modules/azure/aad-baseline init -backend=false -input=false
terraform -chdir=modules/azure/aad-baseline validate
Expected: Success! The configuration is valid.
- Confirm the example also passes:
terraform -chdir=modules/azure/aad-baseline/examples/basic fmt -check
terraform -chdir=modules/azure/aad-baseline/examples/basic init -backend=false -input=false
terraform -chdir=modules/azure/aad-baseline/examples/basic validate
Expected: Success!.
- Run the H1 offline Terratest case:
Expected: 1 top-level test passes.
Part B — full Terratest suite (offline, ~3 min)
- Run the whole offline suite to confirm H1 hasn't regressed any earlier module:
Expected: 18 top-level tests pass.
Part C — tenant integration (real AAD apply, ~25 min, $0)
- Export tenant env var + cd into the H1 fixture:
- Apply against the sandbox tenant:
- Spot-check the AAD portal (Microsoft Entra ID → Security → Conditional Access → Named locations):
snowops-office-ips(Trusted, 2 IP ranges)snowops-corp-vpn-egress(Untrusted, 1 IP range)snowops-allowed-countries(US, IN, GB)-
snowops-blocked-countries(KP, IR, Include Unknown = Yes) -
Spot-check the auth-strength policy (Microsoft Entra ID → Security → Authentication methods → Authentication strengths):
SnowOps - Phishing Resistant MFAwith FIDO2 + WHfB + X.509 multi-factor.
Part D — Graph PATCH steps (operator, ~15 min)
Apply the password protection + branding PATCHes via
az rest. Both are idempotent — re-running yields the same state.
- Apply password protection:
terraform output -raw password_protection_patch_body | az rest \
--method PATCH \
--uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/PasswordProtection' \
--headers 'Content-Type=application/json' \
--body @-
Expected: no output (Graph returns 204 No Content on success).
-
Apply tenant branding:
TENANT_ID=$(terraform output -raw tenant_id 2>/dev/null || az account show --query tenantId -o tsv) terraform output -raw branding_patch_body | az rest \ --method PATCH \ --uri "https://graph.microsoft.com/v1.0/organization/$TENANT_ID/branding/localizations/0" \ --headers 'Content-Type=application/json' \ --body @-Expected: returns the updated branding object as JSON.
-
Verify both via the portal:
- Microsoft Entra ID → Protection → Authentication methods → Password protection: Lockout threshold = 10, Lockout duration = 60s, Mode = Enforced, Banned password list contains "Welcome1" + "Summer2026" etc.
- Microsoft Entra ID → Company branding: sign-in page text shows "Authorized access only. Activity is monitored and logged ..."
Pass criteria
- Part A —
terraform validatepasses for the module + example - Part B — full offline Terratest suite passes (18 top-level tests)
- Part C — all 4 named locations visible in the portal
- Part C — phishing-resistant auth-strength policy visible in the portal
- Part D —
Password protectionpage shows the SnowOps banned-password list (count ≥ 10) - Part D — sign-in page renders the SnowOps compliance disclaimer text
(open a private browser window and visit
https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/authorize?client_id=...&response_type=code&...) - All
Destroycalls (Part E below) complete without error
Teardown
cd tests/terratest/fixtures/aad-baseline
terraform destroy -var "tenant_id=$SNOWOPS_SANDBOX_TENANT_ID"
Removes the named locations + auth-strength policy. The Graph PATCHes (password protection + branding) are NOT reverted by destroy — to roll them back manually:
# Reset password protection to Microsoft default (Audit mode, threshold 10).
az rest --method PATCH \
--uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/PasswordProtection' \
--headers 'Content-Type=application/json' \
--body '{"@odata.type":"#microsoft.graph.passwordAuthenticationMethodConfiguration","lockoutThreshold":10,"lockoutDurationInSeconds":60,"bannedPasswordCheckOnPremisesMode":"Audit","enableBannedPasswordCheckOnPremises":false,"enableBannedPasswordCheck":true,"bannedPasswordList":[]}'
# Reset branding to Microsoft default (empty).
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/organization/$TENANT_ID/branding/localizations/0" \
--headers 'Content-Type=application/json' \
--body '{"signInPageText":"","usernameHintText":"","backgroundColor":"#FFFFFF"}'
Sign-off
- Tester: _ | Date: _ | Result: PASS / FAIL / N/A
- Notes: