Manual Test Runbook — J6: WORM Audit-Log Archive
Owner: Sagar | Time: ~10 min (Parts A + B) · +5 min (optional Part C integration) · +20 min (optional Part D WORM drill) | Sandbox: snowops-sandbox-01
Promotes J6 (
modules/azure/audit-log-archive/) from 🟦 Code Complete → 🟩 Shipped. Parts C/D cost ~$0 (empty StorageV2 account + low-volume Activity Log). The immutability state in this runbook stays Unlocked so teardown works — neverLocka sandbox archive (Locked is permanent).
Prerequisites
- Sandbox subscription access active (PIM activated if required)
-
az logindone;az account showconfirms the sandbox subscription is selected - Identity has Contributor on the sandbox sub (+ Storage Blob Data Contributor for the Part D blob writes)
- Local tooling:
terraform >= 1.6,go >= 1.22,az CLI >= 2.50,jq -
SNOWOPS_SANDBOX_SUBSCRIPTION_IDandSNOWOPS_SANDBOX_TENANT_IDenv vars set - Working directory: repo root
Steps
Part A — terraform fmt + validate (offline, ~3 min)
- Module + example:
terraform -chdir=modules/azure/audit-log-archive fmt -recursive -check
terraform -chdir=modules/azure/audit-log-archive init -backend=false -input=false
terraform -chdir=modules/azure/audit-log-archive validate
terraform -chdir=modules/azure/audit-log-archive/examples/basic init -backend=false -input=false
terraform -chdir=modules/azure/audit-log-archive/examples/basic validate
Expected: Success! The configuration is valid. for both.
- Offline Terratest case:
Expected: PASS.
Part B — full Terratest suite (offline, ~3 min)
- Confirm no regression:
Expected: full offline suite green (27 top-level tests across all packages).
Part C — integration test (real Azure apply + destroy, ~5 min, ~$0)
The fixture sets
enable_immutability = falseso the deferred destroy tears the account down unattended.
- Export sandbox env vars:
export SNOWOPS_SANDBOX_SUBSCRIPTION_ID="<sandbox-subscription-guid>"
export SNOWOPS_SANDBOX_TENANT_ID="<sandbox-tenant-guid>"
- Run the J6 integration test:
cd tests/terratest
go test -v -tags integration -timeout 30m ./modules/azure/... -run TestAuditLogArchiveModule
- Watch for:
Plan: 3 to add, 0 to change, 0 to destroy.— RG + storage account + Activity Log diagnostic setting.- All output assertions PASS (
storage_account_id,primary_blob_endpoint,activity_log_diagnostic_id,immutability_enabled = false). Destroy complete!
Part D — WORM verification drill (optional, ~20 min)
Proves the catalog criterion: "mutation attempt fails." Applies the example with immutability ON (Unlocked), writes an audit blob, then proves a delete/overwrite is refused within the retention window.
- Apply the example with immutability on (a short 1-day period keeps the sandbox cheap; Unlocked stays removable):
cd modules/azure/audit-log-archive/examples/basic
terraform init -input=false
terraform apply -auto-approve \
-var "subscription_id=$SNOWOPS_SANDBOX_SUBSCRIPTION_ID" \
-var "tenant_id=$SNOWOPS_SANDBOX_TENANT_ID" \
-var "archive_name=snowopsj6drill$RANDOM"
SA=$(terraform output -raw storage_account_id | awk -F/ '{print $NF}')
echo "archive=$SA"
The example sets
immutability_state = "Unlocked"+ a 365-day period. To keep the drill self-contained you can edit the example toimmutability_period_in_days = 1before this apply.
- Confirm the account-level immutability policy + protected append writes:
az storage account show -n "$SA" -g "$(terraform output -raw storage_account_id | awk -F/ '{print $5}')" \
--query "immutableStorageWithVersioning" -o json
Expected: immutability enabled. Also confirm versioning + TLS:
az storage account blob-service-properties show ... shows isVersioningEnabled: true.
- Write a test blob, then attempt to delete/overwrite it and confirm WORM refuses (use an AAD login; grant yourself Storage Blob Data Contributor on the account first if needed):
CONTAINER=worm-drill
az storage container create --account-name "$SA" --name "$CONTAINER" --auth-mode login
echo "audit-event-001" > /tmp/evt.txt
az storage blob upload --account-name "$SA" -c "$CONTAINER" -n evt.txt -f /tmp/evt.txt --auth-mode login
# Attempt delete within the immutability window — must FAIL.
az storage blob delete --account-name "$SA" -c "$CONTAINER" -n evt.txt --auth-mode login 2>&1 | head -3
Expected: the delete is rejected with an immutability/ImmutabilityPolicy
error. The blob remains readable — that's the WORM guarantee.
-
(Optional) Confirm the Activity Log is landing: after ~10–15 min the platform creates the
insights-activity-logscontainer with append blobs: -
Teardown (Unlocked → removable):
Pass criteria
- Part A — module + example validate;
TestAuditLogArchiveValidatepasses - Part B — full offline Terratest suite passes
- Part C —
TestAuditLogArchiveModuleintegration test passes end-to-end - Archive account is StorageV2, RA-GZRS, TLS 1.2, versioning on, no public blobs
- Activity Log diagnostic setting present, targeting the archive account
- (Part D) account-level immutability (WORM) enabled with protected append writes
- (Part D) blob delete/overwrite is refused within the retention window
- All
Destroycalls complete without error (immutability left Unlocked) - No orphaned RGs / storage accounts remain (
az group list -o table) - All test resources tagged
ephemeral = true(X7 cleanup safety net)
Teardown
The integration test runs terraform destroy automatically. For the Part D
drill, destroy the example as shown in step 11. If a Locked policy was ever set
(it should not be in sandbox), the account cannot be deleted until retention
elapses — there is no override.
Sign-off
- Tester: _ | Date: _ | Result: PASS / FAIL / N/A
- Notes: