Skip to content
Lumaft documentation contents
Lumaft documentation

Find your backend details

Work out the bucket, prefix, region, and layout of the state you want Lumaft to observe.

Find your backend details

A backend record needs four facts: the bucket, the prefix (if any), the region, and for Pulumi the layout. Getting the layout or prefix wrong is the most common reason a backend reports a healthy diagnostic but shows no stacks. This page shows how to read each fact off the tools you already use.

Step 1: Find the backend URL

Pulumi stores its backend as a URL of the form s3://<bucket>/<prefix>?<options>. Find it in any of these places:

From a machine that already uses the backend:

pulumi whoami --verbose

The Backend URL line is what you need.

From the project file, if the team pins it there:

# Pulumi.yaml
backend:
  url: s3://acme-pulumi-state/team/platform?region=us-east-1

From your CI pipeline, in the pulumi login step or the PULUMI_BACKEND_URL variable.

Step 2: Read the URL

URL bucket prefix region endpoint forcePathStyle
s3://acme-pulumi-state acme-pulumi-state omit see below omit false
s3://acme-pulumi-state/team/platform?region=eu-west-1 acme-pulumi-state team/platform eu-west-1 omit false
s3://state?endpoint=s3.internal.example&s3ForcePathStyle=true&region=local state omit local https://s3.internal.example true
  • The host part of the URL is the bucket; the path part is the prefix. No leading or trailing slash in the prefix.
  • endpoint in the URL may omit the scheme; in backends.json it must be a full https:// origin with no path.
  • s3ForcePathStyle=true in the URL is "forcePathStyle": true in the record.

If the URL has no region, ask the bucket:

aws s3api get-bucket-location --bucket acme-pulumi-state

A null LocationConstraint means us-east-1.

Step 3: Find the layout

Pulumi has two ways of arranging stack files under the prefix, and Lumaft never guesses between them. List the stacks directory:

aws s3 ls s3://acme-pulumi-state/team/platform/.pulumi/stacks/

(Drop team/platform/ if you have no prefix.)

You see Layout Record value
PRE platform/, PRE networking/ — directories Project-scoped "layout": "project-scoped"
prod.json, dev.json — files directly here Legacy "layout": "legacy"
Both directories and files Both layouts in one prefix One record per layout, with distinct ids
Nothing, or NoSuchKey Wrong prefix Recheck Step 2

Project-scoped is the default for backends created with recent Pulumi versions. Legacy is deprecated by Pulumi and slated for removal; Lumaft still reads it, but treat a legacy backend as something to migrate.

Step 4: Check for KMS encryption

If the bucket encrypts objects with a customer-managed KMS key, the Lumaft identity also needs kms:Decrypt on that key. Check one state object:

aws s3api head-object --bucket acme-pulumi-state \
  --key team/platform/.pulumi/stacks/platform/prod.json \
  --query '{sse: ServerSideEncryption, key: SSEKMSKeyId}'

"sse": "aws:kms" with a key ARN means you need the KMS grant from IAM setup on AWS. "AES256" or null needs nothing extra.

Step 5: Write the record

{
  "kind": "s3",
  "id": "platform",
  "displayName": "Platform (production account)",
  "bucket": "acme-pulumi-state",
  "prefix": "team/platform",
  "layout": "project-scoped",
  "region": "us-east-1",
  "forcePathStyle": false,
  "enabled": true
}
  • id is yours to choose: lowercase, unique, stable. It appears in URLs, filters, and integration-token scopes, so pick something you will not want to rename.
  • displayName is what people see.

Put the record in the backends array of the file described in Connect a backend. Several backends — one per account, per prefix, or per layout — go in the same file.

Terraform and OpenTofu backends

For these engines the facts come from the backend block, and Lumaft expects the state key to be <project>/terraform.tfstate under the default workspace prefix:

backend "s3" {
  bucket = "acme-tf-state"     # bucket
  key    = "platform/terraform.tfstate"   # <project>/terraform.tfstate
  region = "us-east-1"         # region
  # workspace_key_prefix left at its default of "env:"
}

Set the record's prefix to the namespace above the project directories (here there is none, so add one if your keys are nested, for example infra/platform/terraform.tfstateprefix: "infra"). A custom workspace_key_prefix or a key with extra path segments is not observed. The record shape is in Connect a backend.

Engine support bounds. State observation is verified against Terraform 1.15.9 and OpenTofu 1.12.6; other builds are unverified. Terraform and OpenTofu can write native S3 lock files when locking is enabled, but Lumaft does not currently observe them. Backend-native update history remains unavailable for those engines, so lock and update-history observation are Pulumi-only and these backends answer engine-unsupported for both rather than showing empty results.

Verify before you deploy

The identity Lumaft will run as should be able to do exactly this and nothing more:

aws s3 ls s3://acme-pulumi-state/team/platform/.pulumi/stacks/ --recursive | head
aws s3 cp s3://acme-pulumi-state/team/platform/.pulumi/stacks/platform/prod.json - | head -c 200

If both work from the credentials you will give Lumaft, the backend record will work too.