Terraform and OpenTofu
The Updawg provider manages an organization’s configuration from Terraform or
OpenTofu: groups, policies, enrollment tokens, notification channels and rules.
It is published as pez-solutions/updawg, and its full reference (every
argument of every resource and data source) is on the
Terraform Registry.
It needs an API token, so the Business or Enterprise plan.
Setting it up
Section titled “Setting it up”terraform { required_providers { updawg = { source = "pez-solutions/updawg" version = "~> 0.1" } }}
provider "updawg" { org = "acme" # or UPDAWG_ORG # The token comes from UPDAWG_API_TOKEN. Keep it out of .tf files.}| Setting | Environment | Default |
|---|---|---|
api_token |
UPDAWG_API_TOKEN |
none: required |
org |
UPDAWG_ORG |
none: here or per block |
api_url |
UPDAWG_API_URL |
https://api.updawg.net |
The token acts as the person who issued it, within its scopes. Give it read,
plus groups, policy, enrollment and integrations for the resources you
manage. A token belongs to one organization, so managing several means one
aliased provider block, and one token, for each.
What it manages
Section titled “What it manages”| Resource | Scope |
|---|---|
updawg_group |
groups |
updawg_policy |
policy |
updawg_enrollment_token |
enrollment |
updawg_notification_channel |
integrations |
updawg_notification_rule |
integrations |
Data sources, read-only, with read: updawg_organization, updawg_hosts,
updawg_group and updawg_policy.
resource "updawg_group" "web" { name = "web" label_selector = { tier = "web" }}
resource "updawg_policy" "nightly" { yaml = file("${path.module}/policies/nightly.yaml")}A policy’s YAML is sent to the validator during plan, so a document that
doesn’t compile fails the plan with its line and column. An edit made in the
portal shows up as a change to yaml, and applying puts your text back.
Enrollment tokens are stored in state
Section titled “Enrollment tokens are stored in state”An enrollment token is shown once, when it is made, and Updawg keeps only a hash of it. So Terraform state is the only place the provider can keep the value to pass on, to cloud-init user data for example. The token’s value is in your state file.
We chose this over the alternatives on purpose:
- Write-only attributes are for values you send in, like a password. The token is a value that comes back from the API, so there is nothing to make write-only.
- An ephemeral resource would never be stored, but it would issue a new token on every plan, and it can only be passed to other ephemeral or write-only arguments. Instance user data and metadata are ordinary arguments, so the token would land in state anyway, just in a different resource.
So treat state as a secret: keep it in an encrypted backend with access control. Limit what a leaked value is worth, too:
resource "updawg_enrollment_token" "web" { name = "web tier" labels = { tier = "web" } max_uses = 20 expires_at = "2027-01-01T00:00:00Z"}
resource "aws_instance" "web" { # ... user_data = <<-EOT #cloud-config runcmd: - curl -fsSL https://get.updawg.net | UPDAWG_TOKEN=${updawg_enrollment_token.web.token} sh EOT}The API can’t change a token, so changing any of its arguments issues a new one and revokes the old. Hosts already enrolled are unaffected. A token you revoke in the portal is planned for re-issue.
There is no updawg_api_token resource. An API token can’t issue tokens, so a
provider authenticated by one couldn’t create them.
Notification secrets
Section titled “Notification secrets”A channel’s configuration (a webhook URL, a Slack webhook) is stored encrypted
and never returned. Pass it as config_wo with a config_wo_version and it
is never written to state (Terraform or OpenTofu 1.11 or later); raise the
version to send a new one. config = jsonencode({...}) works on older
versions, but the value is then kept in state.
resource "updawg_notification_channel" "ops" { name = "ops" kind = "slack" config_wo = jsonencode({ webhook_url = var.slack_webhook }) config_wo_version = 1}Importing
Section titled “Importing”Every resource imports with org/id, or a bare id for the provider’s
organization:
terraform import updawg_group.web acme/grp_…An imported enrollment token has no value, since the API showed it only once.