Cluster and runtime config with Terraform
These singleton resources configure runtime behaviour, and their scope differs:
dtm_transport_config and dtm_query_log_config are cluster-wide, so you
declare each once and it replicates to every node. The observability (OTLP),
rate-limit, cache, and replication-timing singletons are per node: each
configures only the node the provider endpoint targets, so apply them against
every node’s endpoint for cluster-consistent behaviour. All require the
admin role. Applying one never restarts DTM; dtm_replication_config
values persist on apply but only take effect at the endpoint node’s next
restart (noted below).
Observability (OTLP export)
Section titled “Observability (OTLP export)”dtm_otlp_config turns on DTM’s OTLP/HTTP metrics export to a collector you
manage. See observability.
resource "dtm_otlp_config" "this" { enabled = true endpoint = "https://otel-collector.internal:4318" interval_seconds = 30
headers = { "x-api-key" = var.otlp_api_key # sensitive }}| Attribute | Description |
|---|---|
enabled |
Default false. |
endpoint |
Collector URL. Required when enabled = true. |
headers |
Export headers (values are secrets, stored encrypted, redacted on read). |
interval_seconds |
Export interval (0 = exporter default). |
insecure |
Default false. Push metrics over plaintext HTTP with no TLS at all (the OTLP-standard “insecure”). Not a skip-cert-verify switch: a self-signed HTTPS collector still needs a trusted certificate. An explicit false clears the flag on the server. |
Rate limits
Section titled “Rate limits”dtm_rate_limit_config sets per-IP API rate limits (token bucket) for the
auth, write, and read request classes. A value of 0 uses the built-in
default for that class. The limiter’s fourth class, upload (the
restore/compact disk-staging endpoints), is not settable via Terraform, and an
apply of this resource resets any upload values previously set via the API
back to the built-in default; re-apply custom upload tuning with
PUT /api/v1/config/rate-limits afterwards.
resource "dtm_rate_limit_config" "this" { auth_rps = 5 auth_burst = 5 write_rps = 60 write_burst = 20 read_rps = 10 read_burst = 30}Forwarded-response cache
Section titled “Forwarded-response cache”dtm_cache_config controls the cache for forwarded answers.
resource "dtm_cache_config" "this" { enabled = true max_size = 10000 ttl_seconds = 0 # 0 = use each record's own TTL}max_size must be greater than 0 when enabled = true.
Delete guardrails
Section titled “Delete guardrails”dtm_delete_guardrail_config caps how many records one bulk delete may remove,
the same guardrail the bulk-delete API enforces.
resource "dtm_delete_guardrail_config" "this" { bulk_delete_cap = 250}| Attribute | Description |
|---|---|
bulk_delete_cap |
Maximum records one bulk delete may remove. 0 or unset uses the built-in default of 100; a negative value is rejected. The server normalises the read-back to the effective cap. |
Singleton: import with ID delete-guardrails. Removing the resource resets
the cap to the default rather than removing the guardrail.
Transport (DoT and DoH)
Section titled “Transport (DoT and DoH)”dtm_transport_config manages the encrypted inbound DNS listeners, the same
setting as the UI’s Transport Protocols card and
PUT /api/v1/transport-config. Applies live and replicates cluster-wide; see
DNS over TLS and HTTPS for the security caveats before
enabling either.
resource "dtm_transport_config" "this" { dot_enabled = true dot_listen_addr = ":853" doh_enabled = false}Singleton: import with ID transport-config.
Query log
Section titled “Query log”dtm_query_log_config turns per-query logging on and off at runtime,
cluster-wide, without a restart. sample_rate keeps 1-in-N queries, worth
setting on high-QPS nodes.
resource "dtm_query_log_config" "this" { enabled = true sample_rate = 10 # keep 1 in 10 queries}Singleton: import with ID query-log. The
observability.query_log_* file keys are only
the boot seed; once this resource has applied, the persisted value wins over
the YAML at the next boot.
Region-discovery backend
Section titled “Region-discovery backend”The companion singleton dtm_region_discovery_config lives with the other
region resources; see
regions, discovery and subnets.
Replication timing
Section titled “Replication timing”dtm_replication_config tunes how quickly cluster state spreads between
nodes and how often nodes exchange a full sync. Intervals are duration
strings ("30s", "200ms"); the gossip_* attribute names come from the
underlying replication protocol.
resource "dtm_replication_config" "this" { push_pull_interval = "30s" gossip_interval = "200ms" gossip_nodes = 3 probe_interval = "1s" probe_timeout = "500ms"}Users and SSO
Section titled “Users and SSO”Local users and the Entra SSO configuration are also manageable as code (both admin), with the same secrets-never-in-state discipline as everything else: the credential fields are write-only arguments (Terraform 1.11 or newer), sent to the API on apply and never persisted to state or plan.
dtm_user manages a local user and their role:
resource "dtm_user" "alice" { username = "alice" role = "editor" # admin | editor | readonly enabled = true
password_wo = var.alice_password # sensitive variable password_wo_version = "1"}- Rotating the password means changing
password_woand bumpingpassword_wo_versiontogether; a write-only value is invisible to the diff, so changing it alone is a no-op. usernameforces replacement (there is no rename). Import by username (terraform import dtm_user.alice alice), then add the password fields in config to manage the credential.- The server-side guards still apply: you cannot disable or demote the last remaining admin, and a user cannot disable their own account.
- Entra-provisioned users (
source = "entra") are not created here; manage their access through the app registration.
dtm_sso_config manages the Entra ID SSO configuration
of the node the provider endpoint targets (per node today: on a multi-node
cluster, apply it through each node’s endpoint, for example one provider alias
per node, or Sign in with Microsoft works on one node only; a destroy
likewise disables SSO on that node only):
resource "dtm_sso_config" "entra" { enabled = true tenant_id = "00000000-0000-0000-0000-000000000000" client_id = "11111111-1111-1111-1111-111111111111" redirect_uri = "https://dtm.example.internal/api/v1/auth/entra/callback"
client_secret_wo = var.entra_client_secret # sensitive variable client_secret_wo_version = "1"}The client secret follows the same write-only pattern: rotate by changing the value and bumping its version together. Role mapping is app-role based (the app registration’s Admin role maps to DTM admin), so there is no claims-mapping argument here.
Reading cluster state
Section titled “Reading cluster state”Two data sources expose live cluster state:
# All cluster membersdata "dtm_nodes" "all" {}
# One-shot cluster summarydata "dtm_cluster_info" "this" {}
output "alive_nodes" { value = data.dtm_cluster_info.this.alive_count}dtm_nodes returns a nodes list, each with id, name, addr, region_id,
status (alive / suspect / dead / left), and version.
dtm_cluster_info returns version, node_count, alive_count, node_id, and
region_id.