# Psono Terraform Provider

The Psono Terraform Provider (opens new window) manages individual keys inside pre-created Psono Environment Variables entries. It can:

  • Preserve and adopt an existing key.
  • Generate a value when a key does not exist.
  • Write a value without storing it in Terraform state.
  • Rotate provider-generated or externally supplied values.
  • Read a value through an ephemeral resource without persisting it in plan or state.
  • Retain or explicitly delete a key when its Terraform resource is destroyed.

The provider uses a restricted Psono API key. Encryption and decryption happen locally in the provider; an unrestricted API key is not required. The provider does not create Psono entries, folders, or datastores.

# Requirements

Before using the provider, ensure that you have:

  • Terraform 1.11 or newer.
  • Network access from Terraform to your Psono server.
  • A pre-created Psono Environment Variables entry.
  • A dedicated restricted API key with that entry assigned.
  • Read permission for every operation.
  • Write permission for creating, updating, rotating, or deleting keys.

# Prepare Psono

# Create an Environment Variables entry

Create or select an Environment Variables entry in Psono. The provider manages individual keys in this entry, such as DB_PASSWORD or API_TOKEN.

The entry itself must already exist. Terraform only manages the selected keys inside it.

# Create a restricted API key

Follow the API key creation guide and apply these provider-specific settings:

  1. Create a dedicated restricted API key for Terraform.
  2. Assign the Environment Variables entries that Terraform may access.
  3. Grant read permission.
  4. Grant write permission if Terraform will create, change, rotate, or delete keys.
  5. Leave "Allow insecure usage" disabled.
  6. Record the API key ID and API secret key.
  7. Record the SECRET_ID displayed for each assigned entry.

The provider needs the API key ID and API secret key. It does not need the API private key or server signature.

WARNING

Use a dedicated API key and assign only the entries Terraform needs. Anyone who can access the API secret key can read the assigned Psono entries and, when write permission is enabled, modify them.

# Install the provider

Declare the provider in your Terraform configuration:

terraform {
  required_version = ">= 1.11.0"

  required_providers {
    psono = {
      source  = "psono/psono"
      version = "~> 1.0"
    }
  }
}

provider "psono" {}

Initialize the working directory:

terraform init

Terraform downloads the signed provider release from the public Terraform Registry and verifies its checksum signature.

# Configure authentication

Prefer environment variables so credentials do not appear in Terraform files:

export PSONO_SERVER_URL='https://psono.example.com/server'
export PSONO_API_KEY_ID='REPLACE_WITH_API_KEY_ID'
export PSONO_API_SECRET_KEY='REPLACE_WITH_API_SECRET_KEY'

PSONO_SERVER_URL must include the /server path. The API secret key is the 64-character hexadecimal secret shown in the restricted API key details.

For a Psono server that uses a private certificate authority, provide the PEM CA certificate bundle contents:

export PSONO_CA_BUNDLE="$(cat company-ca.pem)"

TLS certificate verification cannot be disabled. The additional certificates are appended to the system trust store.

The equivalent provider arguments are server_url, api_key_id, api_secret_key, and ca_bundle. Environment variables are recommended to avoid placing credentials directly in configuration.

# Generate a value

The following resource preserves DB_PASSWORD if it already exists. Otherwise, the provider generates a 32-character value and stores it in Psono:

resource "psono_environment_variable" "database_password" {
  secret_id = var.psono_environment_variables_secret_id
  name      = "DB_PASSWORD"

  length      = 32
  min_lower   = 4
  min_upper   = 4
  min_numeric = 4
  min_special = 4

  rotation_version = 1
}

The generated value is not returned by the managed resource and does not enter Terraform state. Increment rotation_version to replace a provider-generated value:

rotation_version = 2

Changing password-generation settings does not rotate an existing value by itself. Increment rotation_version when the new settings should take effect.

WARNING

Incrementing rotation_version replaces the current key value even when the resource originally adopted or imported that key. Terraform cannot distinguish an adopted value from a value it previously generated.

# Supply a write-only value

Use value_wo to write an externally supplied value without storing it in Terraform plan or state. This example writes an ephemeral random password:

ephemeral "random_password" "database" {
  length = 32
}

resource "psono_environment_variable" "database_password" {
  secret_id        = var.psono_environment_variables_secret_id
  name             = "DB_PASSWORD"
  value_wo         = ephemeral.random_password.database.result
  value_wo_version = 1
}

value_wo_version is required when value_wo is configured. Increment it when Terraform should write a replacement value. Changing value_wo without also changing value_wo_version does not update Psono.

# Read a value without state

The ephemeral resource reads one key without persisting its value in Terraform plan or state:

ephemeral "psono_environment_variable" "database_password" {
  secret_id = var.psono_environment_variables_secret_id
  name      = "DB_PASSWORD"
}

Its sensitive value attribute can only be passed to another ephemeral context, such as a write-only argument. It cannot be exposed as a normal Terraform output.

For continuous synchronization into Kubernetes Secrets, use the Psono Kubernetes Operator instead. Terraform only reads or writes values while a Terraform operation is running.

# Deletion behavior

The default deletion policy is Retain. Destroying the Terraform resource removes it from Terraform state but leaves the key in Psono. This prevents an adopted value from being deleted unexpectedly.

Set deletion_policy to Delete only when Terraform should remove the Psono key during destroy:

resource "psono_environment_variable" "temporary_token" {
  secret_id       = var.psono_environment_variables_secret_id
  name            = "TEMPORARY_TOKEN"
  deletion_policy = "Delete"
}

Changing secret_id or name replaces the Terraform resource. The deletion policy also applies to the old key during replacement: Retain leaves it in Psono, while Delete removes it.

# Import an existing key

Import an existing key with <SECRET_ID>:<KEY_NAME>:

terraform import psono_environment_variable.database_password \
  '25070c66-8950-4264-9b39-11e6d83312e3:DB_PASSWORD'

Importing never reads the secret value into Terraform state.

# Changes outside Terraform

Terraform checks whether the managed key exists but does not store or compare its secret value. A value changed directly in Psono is therefore accepted as the current value. Terraform only writes another value when rotation_version or value_wo_version changes.

# Security considerations

  • Keep provider credentials outside Terraform configuration and state.
  • Treat Terraform process environments and CI variables as sensitive.
  • Use a dedicated restricted API key for each Terraform trust boundary.
  • Assign only required Psono entries and grant only required permissions.
  • Keep "Allow insecure usage" disabled to prevent other clients from requesting server-side decryption.
  • Review deletion_policy = "Delete" carefully before applying or destroying.
  • Do not expose ephemeral values through logs, provisioners, or non-write-only arguments.

# Reference

The Terraform Registry contains additional provider and resource reference documentation: