Skip to content

Production readiness pass

Your POC passed review; now a security checklist stands between it and the wider rollout. Every control on that list has its own docs page, but the pages do not tell you the order, and two of the classic mistakes here are one-way doors: locking every admin out by enabling SSO without a tested break-glass login, and going live with no proven backup. This tutorial sequences the hardening pass so the irreversible steps are protected first.

The deployment already scopes the management ports (8443, 8080) to the adminAddressPrefix parameter; it just defaults to the whole VNet. This step is tightening that value to your admin subnet or jumpbox CIDR, not authoring rules from scratch. Leave 53 open to your client subnets and 7946 between the DTM nodes only, per the port table and the operator responsibilities.

Verify both directions:

Terminal window
az network nsg rule list -g rg-dtm-poc --nsg-name nsg-dtm -o table
# From a NON-admin subnet, this should now time out:
curl -sk --max-time 5 https://10.0.250.4:8443/readyz || echo "blocked (good)"

2. Replace shared logins with named accounts

Section titled “2. Replace shared logins with named accounts”

Create the account baseline that users and access recommends: named admin accounts for the people who need them, editor for engineers and automation that manage DNS data, readonly for dashboards and auditors, and one break-glass local admin with a strong password stored in your vault. The three roles are admin, editor, and readonly.

Verify a role boundary, not just a login. As a readonly user:

Terminal window
curl -sk -X POST https://10.0.250.4:8443/api/v1/zones \
-H "Authorization: Bearer $READONLY_TOKEN" \
-H "X-DTM-CSRF: 1" -H "Content-Type: application/json" \
-d '{"name": "should-fail.internal."}'
# 403

Follow Entra ID SSO: register the app, assign App Roles, and apply the configuration (PUT /api/v1/auth/entra/config, admin role). People now sign in with their Microsoft identity, and their DTM role comes from the Entra app role.

Verify: one SSO login with the expected role, one break-glass local login, both witnessed in separate private windows.

Monitors, automation, and the Terraform provider should verify TLS rather than skip it, and by default the API listener self-signs a fresh certificate at every service start. Follow the stable API certificate procedure (listen.tls.cert_file / key_file, restart one node at a time, gating each restart on /readyz).

If you plan to serve DoT or DoH soon, you can fold this into that rollout instead: the encrypted DNS tutorial starts with this same step.

Verify: curl without -k:

Terminal window
curl --cacert corp-ca.pem https://10.0.250.4:8443/readyz
# 200: ready

Enable the built-in scheduler on each node, with an off-node copy to a versioned, soft-delete-enabled Storage Account via the node’s managed identity (grant it Storage Blob Data Contributor on the container; no SAS tokens or keys):

backup:
schedule_enabled: true
interval_minutes: 360
blob_container_url: https://<account>.blob.core.windows.net/dtm-backups

The backup and restore page covers the full key set, the local-first upload behavior, and the cron alternative if you prefer an external trigger. Either way, wire the dead-pipeline alert on dtm_backup_last_success_timestamp_seconds from that page; a scheduler nobody watches is the old cron problem wearing a new hat.

Verify the first snapshot like you mean it:

Terminal window
az storage blob list --account-name <account> --container-name dtm-backups \
--auth-mode login -o table # snapshot landed

A backup you have never listed, and a backup alert that has never been checked, are hopes, not controls. The full proof is a restore drill, which deserves its own session; put it on the calendar now.

6. Treat snapshots and the cluster key as secrets

Section titled “6. Treat snapshots and the cluster key as secrets”

A snapshot contains all DNS data, users, and configuration, readable as-is; the stored secrets inside it are additionally protected by the cluster encryption key. So both the snapshot store and the key are production secrets: scope Storage Account access tightly, and guard the deployment’s Key Vault per rotating secrets.

7. Assign the Azure Policy governance pack

Section titled “7. Assign the Azure Policy governance pack”

Deploy the shipped policy pack: 8 definitions (7 audit-by-default; encryption-at-host ships disabled, opt-in) plus one initiative, one az deployment sub create against its deploy.json, with assignments defaulting to enforcementMode: DoNotEnforce. Details and the per-control table are in Azure Policy governance.

Verify: the initiative shows assigned in Azure Policy, and after the next evaluation cycle its compliance view lists your DTM resources.

Run the checklist as a gate, not a memory:

Control Proven by
NSG scoped to admin CIDR blocked curl from a non-admin subnet
Named accounts, least role 403 probe as readonly
SSO on, break-glass tested two private-window logins
Stable API certificate curl --cacert with no -k
Backup scheduled and verified listed blob, fresh success timestamp
Policy pack assigned, DoNotEnforce initiative visible in Azure Policy

Close with an audit spot check, run as your named admin account (the audit log is readable by editor and admin):

Terminal window
curl -sk "https://10.0.250.4:8443/api/v1/audit?limit=100" \
-H "Authorization: Bearer $DTM_TOKEN"

Every change you made above should be in that list, attributed to a person. If it is, your accountability story works; go live.

Need a hand? Email [email protected].

Last validated: 2026-07-26