> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ubiquex.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Backend Encryption with KMS

> Encrypt Pulumi state secrets at rest using AWS KMS or a passphrase.

Pulumi state files contain resource attributes — including the values of sensitive outputs marked `pulumi.secret()`. By default, these sensitive values are encrypted with a Pulumi-managed key when using Pulumi Cloud, but when using a self-managed backend like S3, the encryption is your responsibility. Without the `encryption` sub-block, sensitive values in state are stored as base64-encoded strings that anyone with S3 access can decode. The `encryption` sub-block inside `backend` tells ubx which secrets provider to use when initialising the Pulumi stack — either an AWS KMS key (rotatable, access-controlled, audited via CloudTrail) or a passphrase (simpler, portable, but requires secure distribution). One backend block, one encryption configuration, and your state secrets are protected at rest.

## What you'll learn

* How `encryption { provider = "awskms" }` encrypts state secrets with a KMS key
* How `encryption { provider = "passphrase" }` uses an environment variable passphrase
* Why only one `backend` block is allowed per compile unit

***

## Why this matters

<Info>
  State encryption matters because state contains secrets. An RDS password marked `pulumi.secret()` is encrypted in state — but only if the stack was initialised with a secrets provider. Without encryption, sensitive state values are base64-encoded, not encrypted. Anyone who can read your S3 bucket can decode them.
</Info>

***

## The source code

<CodeGroup>
  ```hcl main.iac theme={"theme":"css-variables"}
  unit "aws_s3_bucket_v2" "assets" {
    bucket = "myapp-${input.env}-assets"
  }
  ```

  ```hcl inputs.iac theme={"theme":"css-variables"}
  input "stack" {
    type    = "string"
    default = "dev"
  }

  input "env" {
    type    = "string"
    default = "dev"
  }
  ```

  ```hcl outputs.iac theme={"theme":"css-variables"}
  output "bucket_name" {
    value = unit.aws_s3_bucket_v2.assets.bucket
  }
  ```

  ```hcl ubx.iac theme={"theme":"css-variables"}
  ubx {
    name    = "backend-encryption-kms"
    runtime = "typescript"
    stacks  = ["dev", "staging", "prod"]
  }

  # Only one backend block is allowed per compile unit.
  # The encryption sub-block configures the Pulumi secrets provider.
  # awskms: uses an AWS KMS key — rotatable, access-controlled, CloudTrail-audited.
  backend "s3" {
    bucket = "my-ubx-state"
    region = "us-east-1"
    key    = "myapp/${stack}/pulumi.json"

    encryption {
      provider = "awskms"
      key      = "arn:aws:kms:us-east-1:123456789012:key/mrk-abc123"
      region   = "us-east-1"
    }
  }

  # Passphrase variant — cannot be active alongside the awskms block above
  # (one backend block per compile unit). Shown as documentation.
  # To use passphrase encryption instead, replace the backend block above with:
  #
  # backend "s3" {
  #   bucket = "my-ubx-state"
  #   region = "us-east-1"
  #   key    = "myapp/${stack}/pulumi.json"
  #
  #   encryption {
  #     provider = "passphrase"
  #     env      = "PULUMI_CONFIG_PASSPHRASE"
  #   }
  # }
  ```
</CodeGroup>

***

## How it works

<Steps>
  <Step title="encryption configures the Pulumi secrets provider on stack init">
    The `encryption` sub-block translates to a `--secrets-provider` flag on `pulumi stack init`. For KMS: `--secrets-provider=awskms://arn:aws:kms:...`. For passphrase: `--secrets-provider=passphrase` with `PULUMI_CONFIG_PASSPHRASE` set in the environment.
  </Step>

  <Step title="Sensitive state values are encrypted with the specified key">
    Any output or config value wrapped in `pulumi.secret()` (or produced by an `ephemeral = true` input) is encrypted using the configured KMS key before being written to the S3 state file. The KMS key ID is stored in the state file metadata so future reads know which key to use for decryption.
  </Step>

  <Step title="Only one backend block is allowed per compile unit">
    Two `backend` blocks in the same project is a compile error — ubx enforces single-backend semantics. The passphrase variant is documented as a comment to show the alternative syntax without requiring a second block.
  </Step>
</Steps>

***

## What ubx generates

<Note>
  Like the plain `backend` block, `encryption` produces no TypeScript/Python/Go code. It configures the Pulumi CLI before the generated program runs. The secrets provider is set once at stack initialisation and stored in the stack's metadata.
</Note>

```bash theme={"theme":"css-variables"}
# ubx translates the encryption block to this Pulumi CLI invocation:
pulumi stack init --secrets-provider="awskms://arn:aws:kms:us-east-1:123456789012:key/mrk-abc123"

# For passphrase:
PULUMI_CONFIG_PASSPHRASE=secret pulumi stack init --secrets-provider="passphrase"
```

***

## Common mistakes

<Warning>
  Two `backend` blocks in the same project is a hard compile error — `✗ multiple "backend" blocks found — only one is allowed per project`. If you want to show the passphrase variant alongside the KMS variant (as this example does), put the second one in a comment. This is by design: a stack can't have two different backends simultaneously.
</Warning>

<Tip>
  Use KMS Multi-Region Keys (`mrk-` prefix) for stacks that may be recovered or replicated across regions. A single-region KMS key becomes inaccessible if the key's region is unavailable — Multi-Region Keys can be replicated to a second region as a disaster recovery measure.
</Tip>

***

## Run it

```bash theme={"theme":"css-variables"}
ubx validate              # syntax check — no KMS access needed
ubx plan                  # requires AWS credentials
ubx apply                 # initialises stack with KMS encryption on first run
```

***

## What you learned

<Check>`encryption { provider = "awskms" }` encrypts sensitive state values with a KMS key</Check>
<Check>`encryption { provider = "passphrase" }` uses an environment variable as the encryption passphrase</Check>
<Check>Only one `backend` block is allowed per compile unit — a second block is a compile error</Check>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Code hierarchy" href="/v1/tutorials/41-code-hierarchy-root-and-children">
    Share backend and provider config across multiple stacks
  </Card>

  <Card title="backend block reference" href="/v1/language/backend">
    Full backend and encryption sub-block syntax
  </Card>
</CardGroup>

***

<Info>
  Full runnable example: [github.com/ubiquex/ubx-examples/40-backend-encryption-kms](https://github.com/ubiquex/ubx-examples/tree/main/40-backend-encryption-kms)
</Info>
