Skip to content

Users and access (RBAC)

DTM has built-in role-based access control (RBAC). Every user has one of three roles, enforced by the REST API and, through it, the Terraform provider. The web UI is stricter: its write controls are admin-only, so an editor sees every page read-only and makes changes through the API or Terraform.

Role Can do Cannot do
readonly List and read DNS data: zones, records, health status, and cluster state. Make any change, or read restricted data (the audit log is an editor/admin read; the user list and security configuration are admin-only reads).
editor All DNS data-plane writes: zones, records, ALIAS and override records, health checks (except script checks, admin-only to create, change or delete since v1.0.6, and Managed Identity probes, admin-only to create or change), forwarders, stub zones, blocklist, subnet mappings, TSIG keys, and zone import. Read the audit log. These are API and Terraform writes; the web UI’s edit controls are admin-only. Manage users, run cluster operations, or change runtime configuration.
admin Everything, including user management, cluster operations, backup and restore, and all runtime configuration. -

Assign the least role each user or integration needs. In particular, give automation (Terraform, CI) a dedicated user rather than reusing a person’s admin account.

Use the Users page in the UI, or the API (admin role required):

The Users page, listing each user with role, source, enabled state and last login, with add, edit and delete actions and a change-password form that notes the 16 character minimum

Terminal window
# Create an editor user (password must be at least 16 characters)
curl -sk -X POST https://dtm.internal:8443/api/v1/users \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "long-enough-password-1234", "role": "editor"}'
# Change a user's role, enable/disable, or reset password
curl -sk -X PUT https://dtm.internal:8443/api/v1/users/<id> \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"role": "readonly", "enabled": true}'

Passwords must be at least 16 characters. Disabling a user ("enabled": false) blocks sign-in without deleting the account.

Two server-side guards keep an organisation from locking itself out, enforced on the API and reflected in the UI:

  • You cannot delete or disable your own account (400); have another admin do it. The UI simply omits Delete on your own row.
  • The last enabled admin cannot be deleted, disabled, or demoted. The guard counts only enabled admins, so you cannot disable your way to zero either. Add a second admin first.

Teams that manage DTM as code can declare users with the dtm_user Terraform resource instead, with a write-only password that never enters state; see users and SSO as code.

The API and Terraform authenticate with a JWT bearer token from POST /api/v1/auth/login. Tokens are valid for 24 hours; refresh them in long-running automation. See the API overview.

For centrally-managed identities, configure Entra ID single sign-on. With SSO, users sign in with their Microsoft account and their DTM role is derived from an app role you assign in Entra.

Every change is recorded in the audit log, queryable from the Audit Log page or GET /api/v1/audit (readable by editor and admin). Filter by user, resource, action, or a date range (From / Until in the UI; from / to on the API) to review who changed what; the NDJSON export honours the same filters.

The stored audit log is bounded, not permanent: by default it keeps at most 10,000 entries, pruning oldest-first, and it has no time limit. Two server-configuration settings control the window:

observability:
audit_max_entries: 10000 # count cap; oldest entries dropped first (minimum 1000)
audit_retention: '2160h' # optional time cap (Go duration, here 90 days); unset by default, so no time limit

These are per-node configuration settings, read from each node’s configuration file. A backup holds the whole database, the audit log included, so a larger window makes backups larger too.

Change it without a restart. Added in v1.0.7. The Audit Log Retention card on the Settings page, or PUT /api/v1/config/audit-retention (admin only), sets the age limit for the whole cluster. It applies at the next hourly clean-up, with no restart:

Terminal window
curl -sk -X PUT https://<node>:8443/api/v1/config/audit-retention \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{"retention": "4320h"}'
  • Range: seven days to ten years, as a Go duration. audit_retention in the configuration file takes the same range; a value outside it is refused at start, with a log line, and the 90-day default applies.
  • The file is the floor. A saved value can lengthen the limit set by audit_retention in a node’s configuration file, never shorten it below that. To go shorter, edit the file and restart. With nothing saved, the file applies.
  • A shorter limit removes entries. Entries older than the new limit go at the next clean-up, so the console asks for confirmation before it saves one. Every change is recorded in the audit log with its before and after.
  • During a rolling upgrade, a node not yet on v1.0.7 keeps its own limit until it is upgraded.

If your compliance regime needs a defined retention (SOC 2, PCI, internal IR policy), set audit_retention to it and alert when the log approaches its cap: the dtm_audit_entries metric is the live count, so alerting when it exceeds 90% of audit_max_entries gives warning before pruning clips evidence. For retention beyond the stored window, schedule GET /api/v1/audit/export (NDJSON, filterable, same editor/admin readability) to immutable storage; see the audit log API.

With Entra ID SSO enabled, Entra sign-ins appear here as their own accounts (usernames prefixed entra:, no local password), fully separate from local accounts even when the names look alike; see how SSO and local accounts coexist.