State Store

Overview

A State Store provides encrypted, centrally managed Terraform / OpenTofu state via the HTTP backend. Instead of managing remote state in a separate cloud storage bucket (S3, Azure Blob, GCS), you can store state directly in Snap CD alongside the Modules that produce it.

Every Organization is pre-seeded with a default State Store. You can create additional State Stores to isolate state for different environments or teams.

State is encrypted at rest (AES-256-GCM) and access-controlled via role assignments on the State Store.

State Store

FieldDescription
nameUnique name of the State Store within the Organization

You can find the full State Store specification here.

State Files

Each State Store contains one or more State Files. A State File is created automatically the first time a Module writes state to the State Store. Each Module gets its own State File, keyed by the Module’s name.

State Files support locking: when a Module is applying, it holds an exclusive lock on its State File. Concurrent applies to the same State File are blocked until the lock is released. Locks auto-expire after a configurable timeout (default 30 minutes).

Backend Configuration

To configure the HTTP backend for all Modules in a Namespace, you need the following resources:

1. Backend block

A Namespace Extra File that injects the backend "http" {} block:

resource "snapcd_namespace_extra_file" "http_backend" {
  file_name    = "extra_root.tf"
  contents     = <<EOT
terraform {
  backend "http" {}
}
  EOT
  namespace_id = snapcd_namespace.example.id
  overwrite    = false
}

2. Module name as environment variable

A Namespace Input from Definition that injects the current Module’s name as an environment variable, so each Module’s state is stored under its own path:

resource "snapcd_namespace_input_from_definition" "module_name" {
  name            = "SNAPCD_MODULE_NAME"
  definition_name = "ModuleName"
  usage_mode      = "UseByDefault"
  namespace_id    = snapcd_namespace.example.id
  input_kind      = "EnvVar"
}

3. Backend config flags

Namespace Terraform Array Flags that pass the backend configuration to terraform init:

data "snapcd_state_store" "default" {
  name = "default"
}

resource "snapcd_namespace_terraform_array_flag" "http_backend" {
  for_each = {
    address        = "${var.snapcd_server_url}/api/state/${data.snapcd_state_store.default.id}/$${SNAPCD_MODULE_NAME}"
    lock_address   = "${var.snapcd_server_url}/api/state/${data.snapcd_state_store.default.id}/$${SNAPCD_MODULE_NAME}/lock"
    unlock_address = "${var.snapcd_server_url}/api/state/${data.snapcd_state_store.default.id}/$${SNAPCD_MODULE_NAME}/unlock"
    lock_method    = "POST"
    unlock_method  = "POST"
    username       = "${var.organization_id}:$${SNAPCD_CLIENT_ID}"
    password       = "$${SNAPCD_CLIENT_SECRET}"
  }
  namespace_id = snapcd_namespace.example.id
  task         = "Init"
  flag         = "BackendConfig"
  value        = "${each.key}=${each.value}"
}

$${SNAPCD_MODULE_NAME} is resolved from the Namespace Input above. $${SNAPCD_CLIENT_ID} and $${SNAPCD_CLIENT_SECRET} come from the Runner’s RunnerEnvVars configuration. The double-dollar ($$) escapes Terraform interpolation so the literal ${...} is preserved for the Runner to resolve at deploy time.

Authentication

The HTTP backend authenticates via HTTP Basic auth. The username is {organizationId}:{clientId} and the password is the Service Principal’s client secret. The SNAPCD_CLIENT_ID and SNAPCD_CLIENT_SECRET environment variables are configured on the Runner and made available to the engine process.

Access Control

Access to a State Store is controlled via role assignments, following the same pattern as Stacks:

RolePermissions
OwnerFull access including delete and force-unlock
ContributorRead/write state, acquire and release locks
ReaderRead-only access to state
IdentityAccessManagerManage role assignments on the State Store

Role assignment resources:

Last updated on