Terraform Provider for MazeVault¶
The MazeVault Terraform Provider lets you manage your entire MazeVault infrastructure as code — projects, secrets, certificates, rotations, access control, and integrations with external systems.
- Registry: registry.terraform.io/providers/MazeVault/mazevault
- Requires: Terraform ≥ 1.11, MazeVault ≥ 1.0.48
- Full API reference: Terraform Registry documentation
Installation¶
terraform {
required_version = ">= 1.11"
required_providers {
mazevault = {
source = "MazeVault/mazevault"
version = "~> 1.0"
}
random = {
source = "hashicorp/random"
}
}
}
Provider Configuration¶
provider "mazevault" {
server_url = "https://vault.example.com"
api_token = var.mazevault_token # or env: MAZEVAULT_API_TOKEN
}
| Argument | Env variable | Description |
|---|---|---|
server_url |
MAZEVAULT_SERVER_URL |
MazeVault server base URL |
api_token |
MAZEVAULT_API_TOKEN |
API token (recommended) |
client_id |
MAZEVAULT_CLIENT_ID |
Service account OAuth2 client ID |
client_secret |
MAZEVAULT_CLIENT_SECRET |
Service account OAuth2 client secret |
timeout |
— | Request timeout, e.g. 30s (default) |
skip_tls_verify |
— | Skip TLS check — development only |
Secret handling
Never put credentials directly in .tf files. Use environment variables or a CI/CD secrets store. Never commit .tfvars files containing tokens or passwords.
Authentication¶
API Token (recommended)¶
export MAZEVAULT_SERVER_URL="https://vault.example.com"
export MAZEVAULT_API_TOKEN="mv_pat_xxxxx"
terraform plan
Generate tokens in Admin → API Tokens or with mazevault_api_token resource.
Service Account (CI/CD pipelines)¶
provider "mazevault" {
server_url = var.server_url
client_id = var.client_id
client_secret = var.client_secret
}
Example: External CA Account Settings¶
Use mazevault_ca_account.settings for non-secret CA provider configuration that MazeVault must reuse later during product sync, renewal polling, and DCV checks. Keep API keys, passwords, and EAB HMAC keys in the dedicated sensitive attributes, not in settings. Set provider_type to the documented lowercase value, such as digicert, letsencrypt, or acme; mixed case and surrounding whitespace are rejected before MazeVault receives the request.
resource "mazevault_ca_account" "digicert" {
organization_id = mazevault_organization.acme.id
name = "DigiCert Production"
provider_type = "digicert"
api_key = var.digicert_api_key
base_url = "https://www.digicert.com"
settings = {
organization_id = var.digicert_organization_id
server_platform_id = "45"
dcv_method = "dns_txt"
certificate_dcv_scope = "base_domain"
}
}
Example: Secrets Management with Azure Key Vault Sync¶
Provision a project, store a database password, and sync it to Azure Key Vault with automatic 30-day rotation.
resource "mazevault_organization" "acme" {
name = "Acme Corp"
}
resource "mazevault_project" "backend" {
organization_id = mazevault_organization.acme.id
name = "Backend Services"
type = "secret"
}
resource "mazevault_integration" "azure_kv" {
project_id = mazevault_project.backend.id
name = "Production Key Vault"
type = "azure_key_vault"
environment = "production"
config = {
vault_url = var.keyvault_url
use_managed_identity = "true"
}
}
ephemeral "random_password" "db" {
length = 40
special = true
override_special = "_-+=@#"
}
resource "mazevault_secret" "db_password" {
project_id = mazevault_project.backend.id
key = "POSTGRES_PASSWORD"
environment = "production"
value_wo = ephemeral.random_password.db.result
value_wo_version = 1
}
resource "mazevault_secret_link" "db_link" {
secret_id = mazevault_secret.db_password.id
integration_id = mazevault_integration.azure_kv.id
link_type = "database"
metadata = {
db_user = "app_user"
db_host = "db.prod.example.com"
db_name = "appdb"
}
}
resource "mazevault_rotation_config" "db" {
secret_id = mazevault_secret.db_password.id
rotation_interval_days = 30
enabled = true
notification_emails = ["ops@example.com"]
}
# Deploy the rotated value to a Kubernetes secret after each rotation.
resource "mazevault_secret_rotation_target" "k8s" {
secret_id = mazevault_secret.db_password.id
target_type = "kubernetes_secret"
priority = 10
enabled = true
config_json = jsonencode({
namespace = "production"
secret_name = "app-db-credentials"
secret_key = "POSTGRES_PASSWORD"
agent_id = "your-agent-uuid" # agent with K8s cluster access
})
}
# Also rotate the password on the database itself.
resource "mazevault_secret_rotation_target" "postgres" {
secret_id = mazevault_secret.db_password.id
target_type = "database_password"
priority = 20
enabled = true
config_json = jsonencode({
db_provider = "postgres"
host = "db.prod.example.com"
port = 5432
database = "appdb"
username = "app_user"
admin_credential_secret_id = "your-admin-secret-uuid"
})
}
State-safe secret values¶
For Terraform-managed secret material, prefer value_wo with Terraform 1.11+
ephemeral resources. The provider reads the value from configuration during
apply, sends it to MazeVault, and does not store it in Terraform plan or state.
Increment value_wo_version when a new write-only value should be sent.
ephemeral "random_password" "api" {
length = 48
special = true
override_special = "_-+=@#"
}
resource "mazevault_secret" "api_password" {
project_id = mazevault_project.backend.id
key = "API_PASSWORD"
environment = "production"
value_wo = ephemeral.random_password.api.result
value_wo_version = 1
}
The legacy value argument remains supported for existing configurations, but
Terraform stores sensitive values in state. Avoid reading secret material back
with the mazevault_secret data source when state must remain free of plaintext.
Server-side secret generation¶
Instead of supplying value, add a generate { ... } block and MazeVault
creates the value for you using cryptographically secure, DB/URL-safe
characters. Exactly one of value, value_wo, or generate must be set. The generated
plaintext is never returned to Terraform (it never enters state); in
Orchestrator Mode it is offloaded directly to the external secret manager.
resource "mazevault_secret" "api_key" {
project_id = mazevault_project.backend.id
key = "API_KEY"
environment = "production"
generate {
length = 48
include_symbols = true
}
}
generate field |
Default | Description |
|---|---|---|
length |
40 |
Length of the generated value |
include_upper |
true |
Include uppercase letters |
include_lower |
true |
Include lowercase letters |
include_digits |
true |
Include digits |
include_symbols |
true |
Include DB/URL-safe symbols |
excluded_chars |
— | Characters to exclude from the result |
Azure Key Vault and Entra integrations¶
Beyond the typed Azure DevOps azure_* fields, mazevault_integration also
accepts a generic non-secret config map and a write-only sensitive_config
map (secret values, never read back from the server), plus
interactive_auth_method. This enables Azure Key Vault and Microsoft Entra
integrations.
resource "mazevault_integration" "kv" {
project_id = mazevault_project.backend.id
name = "prod-keyvault"
type = "azure_key_vault"
provider_name = "azure_keyvault"
environment = "production"
config = {
vault_url = "https://myvault.vault.azure.net/"
auth_method = "client_secret"
tenant_id = var.tenant_id
client_id = var.client_id
}
sensitive_config = {
client_secret = var.client_secret
}
}
Entra ID credential rotation¶
post_rotation_actions is the single source of truth for post-rotation
delivery. If you define no action blocks, nothing is delivered. Key Vault
write-back and Spring Boot refresh are expressed as actions here — not as
separate top-level fields. The kv_integration_ids, secret_name,
spring_endpoints, and webhook_urls attributes are now read-only computed
mirrors of these actions.
resource "mazevault_entra_rotation_config" "app" {
credential_id = var.entra_credential_id
rotation_days_before_expiry = 30
post_rotation_actions {
type = "azure_keyvault"
config = {
integration_id = mazevault_integration.kv.id
secret_name = "app-client-secret"
}
}
post_rotation_actions {
type = "spring_actuator_refresh"
config = { actuator_url = "https://app.example.com/actuator/refresh" }
}
}
Example: Certificate Lifecycle Automation¶
Issue a TLS certificate via a CA account and set up automatic renewal.
A mazevault_certificate_template is a certificate-category Project Template:
it is created at the organization level (resolved from project_id) and appears
in the frontend Project Templates view for certificate-management projects
(type = "certificate").
resource "mazevault_project" "pki" {
organization_id = mazevault_organization.acme.id
name = "PKI"
type = "certificate"
}
resource "mazevault_ca_account" "digicert" {
organization_id = mazevault_organization.acme.id
name = "DigiCert Production"
provider_type = "digicert"
api_key = var.digicert_api_key
base_url = "https://www.digicert.com"
}
Certificate templates are certificate-category Project Templates
mazevault_certificate_template creates a Project Template with category
certificates at the organization level (resolved from project_id), so it
shows up in the Project Templates view. MazeVault automatically creates
the underlying certificate template, exposed as the computed
certificate_template_id. validity_period (e.g. 8760h) is converted to
whole days; type is the certificate subtype (e.g. ssl_tls).
ACME CA accounts (Let's Encrypt / ZeroSSL / custom)¶
ACME providers use email and directory_url (and, when the CA uses External
Account Binding, eab_kid / eab_hmac_key) instead of api_key. Every
non-internal provider must supply credentials — the provider validates this
client-side and returns a clear error before calling the server if they are
missing. directory_url is required for a custom acme provider and is
defaulted automatically for letsencrypt and zerossl. The ACME challenge
policy is set on the certificate template via challenge_type.
resource "mazevault_ca_account" "letsencrypt" {
organization_id = mazevault_organization.acme.id
name = "Let's Encrypt"
provider_type = "letsencrypt"
email = "pki@example.com"
}
resource "mazevault_ca_account" "zerossl" {
organization_id = mazevault_organization.acme.id
name = "ZeroSSL"
provider_type = "zerossl"
email = "pki@example.com"
eab_kid = var.zerossl_eab_kid
eab_hmac_key = var.zerossl_eab_hmac_key
}
resource "mazevault_ca_account" "internal_acme" {
organization_id = mazevault_organization.acme.id
name = "Internal ACME"
provider_type = "acme"
email = "pki@example.com"
directory_url = "https://ca.internal.example.com/acme/acme/directory"
}
resource "mazevault_certificate_template" "acme_web" {
project_id = mazevault_project.pki.id
name = "ACME Web TLS"
type = "tls_server"
validity_period = "2160h"
# auto (default) | dns-01 | http-01 | tls-alpn-01
challenge_type = "dns-01"
}
For external commercial CAs that require domain control validation (for
example SSLMarket), the per-template validation method is set via dcv_method
(email, dns, or file). An empty value uses the provider/account default.
dcv_method is ignored by internal and ACME issuers.
resource "mazevault_certificate_template" "sslmarket_dv" {
project_id = mazevault_project.pki.id
name = "SSLMarket DV"
type = "ssl_tls"
validity_period = "8760h"
# email | dns | file (empty = provider/account default)
dcv_method = "dns"
}
The organization's internal root CA can be managed with the
mazevault_caresource. Each organization has at most one internal CA; its parameters are immutable (changing them replaces the CA), and destroying the resource soft-deletes it — the delete is rejected while active certificates were issued by it.
resource "mazevault_ca" "org_root" {
organization_id = mazevault_organization.acme.id
name = "ACME Internal CA"
valid_years = 10
key_size = 4096
}
resource "mazevault_renewal_policy" "default" {
organization_id = mazevault_organization.acme.id
name = "30-day lead"
lead_days = 30
auto_approve = true
notify_emails = "ops@example.com"
}
resource "mazevault_certificate_template" "web_tls" {
project_id = mazevault_project.pki.id
name = "Web TLS 1Y"
type = "ssl_tls"
validity_period = "8760h"
key_usage = ["digitalSignature", "keyEncipherment"]
}
resource "mazevault_certificate" "api_tls" {
common_name = "api.example.com"
ttl = "8760h"
key_size = 2048
organization_ca_account_id = mazevault_ca_account.digicert.id
}
output "api_cert_pem" {
value = mazevault_certificate.api_tls.certificate_pem
sensitive = false
}
output "api_key_pem" {
value = mazevault_certificate.api_tls.private_key_pem
sensitive = true
}
Issuing from the organization internal CA and deploying to Key Vault: a certificate can be issued by the organization internal CA (
mazevault_ca), assigned to a project, and delivered into an Azure Key Vault on renewal via apost_rotation_actionsentry. For the complete arguments, attributes and worked examples, see the provider resource docs:mazevault_ca,mazevault_certificateandmazevault_certificate_rotation_config.
Example: RBAC and Service Account Setup¶
Create a CI/CD service account with read-only access to a specific project.
resource "mazevault_role" "ci_readonly" {
name = "ci-readonly"
description = "Read-only access for deployment pipelines"
permissions = ["secrets:read", "certificates:read", "projects:read"]
}
resource "mazevault_service_identity" "github_actions" {
display_name = "GitHub Actions CI"
description = "Read-only service account for production deployments"
owner_email = "platform@example.com"
}
resource "mazevault_api_token" "ci_token" {
name = "github-actions-prod"
scopes = ["secrets:read", "certificates:read"]
}
output "ci_client_id" {
value = mazevault_service_identity.github_actions.client_id
}
output "ci_client_secret" {
value = mazevault_service_identity.github_actions.client_secret
sensitive = true
}
Example: Sync Rules and Rotation Templates¶
Continuously pull secrets from Azure Key Vault into a MazeVault project and apply a shared rotation policy template.
# Reusable rotation policy template
resource "mazevault_rotation_template" "standard_90d" {
name = "standard-90-day"
description = "Standard 90-day rotation with 14-day certificate lead time"
rotation_interval_days = 90
lead_time_days = 14
grace_period_days = 3
max_retry_attempts = 3
timeout_minutes = 30
is_default = true
}
# Pull secrets from Azure KV into production environment
resource "mazevault_sync_rule" "azure_kv_pull" {
name = "azure-kv-production-pull"
project_id = mazevault_project.backend.id
integration_id = mazevault_integration.azure_kv.id
target_environment = "production"
source_path = "secrets/app/"
sync_direction = "pull"
sync_mode = "incremental"
conflict_strategy = "external_wins"
}
# Post-rotation action that targets a specific gateway
resource "mazevault_rotation_workflow" "db_with_gateway" {
secret_id = mazevault_secret.db_password.id
environment = "production"
rotation_interval_days = 90
post_rotation_actions {
type = "azure_keyvault"
order = 1
on_failure = "rollback"
gateway_id = "gateway-eu-west-01"
config = {
vault_url = "https://myvault.vault.azure.net"
secret_name = "db-password"
}
}
post_rotation_actions {
type = "spring_actuator_refresh"
order = 2
on_failure = "continue"
target_environment = "production"
config = {
url = "https://api.example.com/actuator/refresh"
}
}
}
Example: Environment Tiers¶
Define environment tiers for an organization. name and slug are immutable —
changing either forces the environment to be recreated. Only is_production and
incident_auto_escalation can be updated in place.
resource "mazevault_environment" "production" {
organization_id = mazevault_organization.acme.id
name = "production"
slug = "prod"
is_production = true
incident_auto_escalation = true
}
Example: External API Token Management¶
Many external systems (Jira, Signi, …) issue long-lived API tokens that can only be renewed
manually in their own UI. mazevault_token lets you register such a token with a mandatory
expiry date so MazeVault raises an incident before it lapses. The value is stored encrypted
(or offloaded to your secret manager in Orchestrator Mode). This feature requires a
PoC or Enterprise license.
resource "mazevault_token" "jira" {
name = "jira-automation-token"
token_provider = "jira" # free-text label; jira/signi get dedicated icons in the UI
description = "CI automation token for Jira Cloud"
value_wo = var.jira_token # Terraform 1.11+; absent from plan and state
value_wo_version = 1 # incrementing this replaces the token
expires_at = "2027-01-01T00:00:00Z" # mandatory
lead_time_days = 30 # alert 30 days before expiry
}
# Surface tokens that have entered their alert window.
data "mazevault_tokens" "all" {}
output "tokens_needing_renewal" {
value = [for t in data.mazevault_tokens.all.tokens : t.name if t.days_until_expiry <= t.lead_time_days]
}
When the token is renewed in the external system, update its value through the MazeVault UI/API
renew flow (which also re-deploys any configured agent targets). Changing value in Terraform
forces the resource to be recreated.
The deprecated value argument remains available for existing configurations, but Terraform
stores it in state. Do not transparently replace value with value_wo on an existing resource:
the change recreates the token, changes its ID, and deletes its MazeVault deployment targets.
Use value_wo for new tokens. For an intentional migration, inventory and recreate all targets in
a maintenance window. Editing HCL does not remove plaintext from historical remote-state versions;
rotate the external token and follow the state backend's retention and purge procedure.
Resources Reference¶
Full attribute documentation for each resource is available on the Terraform Registry.
| Resource | Description |
|---|---|
mazevault_organization |
Top-level organization |
mazevault_project |
Project (RBAC boundary, groups secrets/certs) |
mazevault_project_settings |
Per-project operational settings (retention, sync, notifications) |
mazevault_secret |
Encrypted secret with optional rotation |
mazevault_secret_link |
Links a secret to an external integration for write-back |
mazevault_shared_secret |
One-time share link for a secret |
mazevault_rotation_config |
Full rotation pipeline configuration for a secret (v2: uses rotation_interval_days instead of legacy ttl_hours/rotation_strategy) |
mazevault_rotation_workflow |
Simple rotation schedule for a secret |
mazevault_rotation_template |
Reusable rotation policy template |
mazevault_secret_rotation_target |
Structured deployment target in a secret's rotation pipeline (K8s, DB, Agent, DevOps, cloud vault) |
mazevault_certificate_rotation_config |
Automatic renewal and rotation configuration for a specific certificate |
mazevault_entra_rotation_config |
Entra ID credential rotation scheduling (days-before-expiry, staged rotation) |
mazevault_sync_rule |
Synchronization rule between MazeVault and an external KV/secrets provider |
mazevault_certificate |
Certificate issued by or tracked in MazeVault |
mazevault_certificate_template |
Reusable certificate issuance policy |
mazevault_ca |
Organization internal root Certificate Authority (singleton) |
mazevault_ca_account |
CA account integration or reference for external providers, self-hosted providers, and internal CA account references |
mazevault_renewal_policy |
Automatic certificate renewal timing policy |
mazevault_integration |
External secrets store / deployment target (Azure KV, AWS SM, K8s, …) |
mazevault_integration_group |
Multi-environment integration routing |
mazevault_consistency_group |
Cross-environment secret parity monitoring |
mazevault_role |
Custom RBAC role |
mazevault_group_mapping |
Maps external IdP group to a MazeVault role |
mazevault_user |
User account |
mazevault_user_role |
Assigns a role to a user in a project |
mazevault_service_identity |
Machine identity (OAuth2 client) |
mazevault_api_token |
Scoped API token |
mazevault_identity_provider |
SAML / OIDC / LDAP SSO provider |
mazevault_environment |
Environment definition |
mazevault_approval_policy |
Approval workflow for sensitive operations |
mazevault_keytab |
Kerberos keytab for agent authentication |
mazevault_token |
External API token (Jira, Signi, …) with mandatory expiry tracking |
mazevault_deployment |
Agent deployment bootstrap package |
mazevault_config_template |
Configuration template for secret injection |
Data Sources Reference¶
| Data Source | Description |
|---|---|
mazevault_organization |
Look up an organization by ID |
mazevault_project |
Look up a project by ID |
mazevault_secret |
Read a secret value (sensitive) |
mazevault_certificate |
Read a certificate by ID |
mazevault_project_certificates |
List certificates in a project |
mazevault_project_cas |
List CA accounts in a project |
mazevault_project_certificate_templates |
List certificate templates in a project |
mazevault_project_csrs |
List pending CSRs in a project |
mazevault_environments |
List environments in an organization |
mazevault_ca_accounts |
List CA accounts in an organization |
mazevault_users |
List all users |
mazevault_roles |
List all RBAC roles |
mazevault_integrations |
List integrations in a project |
mazevault_audit_logs |
Read audit log entries |
mazevault_rotation_executions |
List rotation execution records |
mazevault_renewal_queue |
List certificates pending renewal |
mazevault_consistency_status |
Cross-environment consistency check result |
mazevault_rotation_resources |
List all rotation-managed resources with their status |
mazevault_rotation_resource_history |
Read rotation execution history for a specific resource |
mazevault_project_rotation_configs |
List all rotation configs within a project |
mazevault_tokens |
List managed external API tokens with their expiry status |
Importing Existing Resources¶
Bring existing MazeVault resources under Terraform management with terraform import. Resource UUIDs are visible in the UI URL or via GET /api/v1/....
terraform import mazevault_project.backend <project-uuid>
terraform import mazevault_secret.db_password <secret-uuid>
terraform import mazevault_certificate.tls <certificate-uuid>
terraform import mazevault_integration.azure_kv <integration-uuid>
Known Limitations¶
mazevault_role— Roles cannot be deleted via the MazeVault API. Aterraform destroyremoves the resource from Terraform state only; the role remains in MazeVault.mazevault_ca— Manages the organization's single internal root CA (organization_id). All parameters are immutable; changing any of them replaces the CA. Destroying the resource soft-deletes the internal CA, but the delete is rejected (HTTP 409) while active (non-revoked, non-expired) certificates were issued by it. Theocsp_url/crl_urlattributes are read-only and reflect the URLs published for issued certificates.mazevault_integration— Theenvironmentargument is required and forces resource replacement on change. The backend does not accept environment changes via update; always recreate when changing environment.mazevault_secret_rotation_target— Theconfig_jsonargument must be a valid JSON object. Usejsonencode()in Terraform. Supplying malformed JSON produces a diagnostic error at apply time. Read operations use a list-scan (no direct GET-by-ID endpoint). Destroying a target that has already been deleted externally is idempotent and succeeds silently.mazevault_rotation_config(v2.0 BREAKING) — Theenvironment,rotation_strategy,workflow_steps_json,scope, andgrace_period_minutesarguments have been removed. Replacettl_hourswithrotation_interval_days. Runterraform state rmand re-import when upgrading from v1.x.mazevault_certificate_rotation_config— No hard-delete endpoint exists. Destroying setsenabled = falseand removes from state only.mazevault_entra_rotation_config— No hard-delete endpoint exists. Destroying setsrotation_enabled = falseand removes from state only.mazevault_token— Requires a PoC or Enterprise license (featuretoken_management); the API returns HTTP 403 otherwise. Usetoken_providerfor the provider label. New resources should usevalue_woplusvalue_wo_version; legacyvalueis sensitive but remains in Terraform state. Import manages metadata only. In-place value renewal is done through the MazeVault UI/API.project_idis immutable, and any Terraform replacement also deletes the token's MazeVault deployment targets.
Best Practices¶
- Remote state — use Terraform Cloud, Azure Blob Storage, or S3 with state locking.
- Sensitive outputs — always set
sensitive = trueon outputs exposing secret values or private keys. - Inject credentials via env vars — use
MAZEVAULT_API_TOKENorTF_VAR_prefixed variables; never commit tokens in.tfvars. - Pin provider version —
~> 1.0allows patch updates while blocking unexpected major changes. - Consistency groups — add
mazevault_consistency_groupafter provisioning to detect cross-environment drift before it causes incidents. - Rotation scheduling — use
rotation_interval_daysandschedule(cron) to define rotation cadence (v2:ttl_hours/rotation_strategyremoved). Post-rotation deployment targets are configured viamazevault_rotation_workflowor the more granularmazevault_secret_rotation_target(supports K8s, database password rotation, agent sync, DevOps variables, and cloud vaults). For certificates usemazevault_certificate_rotation_config; for Entra ID credentials usemazevault_entra_rotation_config. - Separate state per environment — use workspaces or separate state backends per environment to prevent accidental cross-environment writes.