- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| examples | ||
| instructions | ||
| internal/provider | ||
| .gitignore | ||
| .goreleaser.yml | ||
| catalog-info.yaml | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
| README.md | ||
| renovate.json | ||
terraform-provider-dmarcing
Terraform/OpenTofu provider for registering domains and managing DMARC/SPF/DKIM/MTA-STS records on the dmarc.ing platform, backed by service-dmarc-api.
Usage
terraform {
required_providers {
dmarcing = {
source = "tf.stacktonic.au/dmarc-ing/dmarcing"
version = "~> 0.1"
}
}
}
provider "dmarcing" {
endpoint = "https://api.dmarc.ing" # or DMARCING_ENDPOINT env var
api_token = var.dmarcing_api_token # or DMARCING_API_TOKEN env var
}
resource "dmarcing_domain" "example" {
org_id = 1
domain = "example.com"
}
Generate an API token from the dmarc.ing dashboard's API Tokens page (/tokens).
See examples/ for every resource. Full schema docs can be generated with tfplugindocs (tfplugindocs generate), not yet run in this repo.
Resources
| Resource | Purpose | Delete behavior |
|---|---|---|
dmarcing_domain |
Register a domain under an org | Unregisters the domain and cascades to every DNS record stored for it |
dmarcing_domain_verification |
Trigger DNS ownership verification | No-op (no API to unverify); removed from state only |
dmarcing_dmarc_policy |
Set the DMARC TXT record | No-op (no delete API); removed from state only |
dmarcing_spf_policy |
Set the SPF TXT record | No-op (no delete API); removed from state only |
dmarcing_sts_policy |
Set the MTA-STS policy | No-op (no delete API); removed from state only |
dmarcing_dkim_record |
Set a DKIM selector's record | Deletes the selector |
dmarcing_spf_service |
Add a third-party ESP's SPF include | Removes the service |
dmarcing_domain_verification depends on a DNS TXT record (from dmarcing_domain's verification_host/verification_value) already being live — typically created with your DNS provider's own Terraform resource. If it hasn't propagated yet, applying dmarcing_domain_verification fails with a clear error and can simply be retried.
Development
go build ./...
go test ./...
Acceptance tests exercise a full Terraform plan/apply/destroy cycle against a local fake API server and are gated on TF_ACC=1 (requires a terraform or tofu binary on PATH, or network access for terraform-plugin-testing to download one):
TF_ACC=1 go test ./internal/provider/... -v
To try the provider against a real dmarc.ing deployment without publishing anything, point Terraform at the locally built binary with a dev_overrides block:
go build -o terraform-provider-dmarcing .
# ~/.terraformrc or ~/.tofurc
provider_installation {
dev_overrides {
"tf.stacktonic.au/dmarc-ing/dmarcing" = "/path/to/this/repo"
}
direct {}
}
Distribution
This provider is published to our self-hosted boring-registry instance, which implements the real Terraform Provider Registry Protocol (not just a network mirror) against S3-compatible storage. No GitHub, no public Terraform/OpenTofu Registry account.
.forgejo/workflows/release.yml, triggered on a vX.Y.Z tag (auto-created by bump-tag.yaml from commit messages):
- Runs GoReleaser to build checksummed, multi-platform archives into
dist/and GPG-sign the checksums file (release.disable: truein.goreleaser.yml— GoReleaser itself doesn't publish anywhere; only boring-registry's own upload does). - Authenticates to OpenBao via Forgejo OIDC and fetches the S3 credentials for boring-registry's storage backend (see
infra-k8s-vultr/infrastructure/cloud/object-storage.tf/boring-registry.tf— the bucket and its Vultr Object Storage credentials are provisioned there, not in this repo). - Installs the
boring-registryCLI and runsboring-registry upload provider --namespace dmarc-ing --filename-sha256sums dist/..._SHA256SUMSagainst that S3 storage backend.
One-time manual setup (managed in infra-k8s-vultr, not this repo):
- A GPG key (RSA, not ECC) whose public half is registered as
dmarc-ing's signing key — boring-registry expects this as asigning-keys.jsonfile placed directly in the storage backend atproviders/dmarc-ing/signing-keys.json(see boring-registry's publish-providers docs — there's no CLI command for this step, it's provisioned viainfra-k8s-vultr'saws_s3_objectresource instead). - This repo's
GPG_PRIVATE_KEY/GPG_PASSPHRASEsecrets (the private half of that same key) plus theVAULT_ADDRorg variable and theterraform-provider-dmarcing-releaseOpenBao JWT role, which the release workflow uses to fetch the storage credentials at runtime.
Consumers reference this provider with an explicit registry hostname, since it's a real registry (not a mirror substituted in via CLI config) — no provider_installation override needed:
required_providers {
dmarcing = {
source = "tf.stacktonic.au/failurezone/dmarcing"
version = "~> 0.1"
}
}
If boring-registry requires an API token to install from (per its own auth config), add a credentials block for its hostname in ~/.terraformrc/~/.tofurc.
Note: the exact boring-registry upload provider flags in release.yml are written from its published docs and CLI source, which weren't fully consistent with each other at the time — verify against boring-registry upload provider --help for the version actually installed before relying on this in production. This hasn't been exercised against a real boring-registry instance or terraform init/tofu init yet (no network access in the environment this was built in).