Choosing a Pulumi State Backend and Secrets Provider for Production Infrastructure
Choosing where Pulumi stores state and encrypts secrets is a production security decision. Compare Pulumi Cloud, self-managed object storage with KMS, and passphrase options.
27 Mar 2026, 03:09 UTC

The decision you cannot defer
Every Pulumi stack persists state—a JSON record of resource IDs, metadata, and encrypted secrets—to a backend. That backend choice determines who can read the state, how concurrent updates are locked, and whether encryption keys live inside your cloud account or a third-party service. For production infrastructure, treat this as a security boundary decision, not a default setting.
Constraints that drive the choice
Before comparing options, answer three questions:
- Compliance boundary: Must state and keys remain inside your AWS, Azure, or GCP account?
- Team topology: Is this a single team, or do you need role-based access control (RBAC) and audit logs across multiple teams?
- Key management: Do you already operate a key management service (KMS) such as AWS KMS, Azure Key Vault, or GCP Cloud KMS?
Supported options at a glance
Pulumi supports Pulumi Cloud, self-managed cloud object storage (AWS S3, Azure Blob Storage, Google Cloud Storage), and custom backends. Secrets can be encrypted by Pulumi Cloud, a cloud KMS, or a passphrase. The provider is selected per stack.
| Option | State location | Secrets encryption | Access control | Operational overhead |
|---|---|---|---|---|
| Pulumi Cloud | Managed service | Pulumi-managed keys | Pulumi RBAC, audit logs | Low |
| Self-managed storage + KMS | Your S3 / Blob / GCS bucket | Your cloud KMS key | Cloud IAM roles and policies | Moderate |
| Self-managed storage + passphrase | Your bucket | Passphrase-derived key | Cloud IAM + shared secret | Moderate |
Trade-offs explained
Pulumi Cloud
Pulumi Cloud provides managed state, integrated secrets encryption, RBAC, and audit logging. It reduces operational burden for smaller teams. The trade-off is vendor dependency and per-stack pricing. Feature names and tiers have evolved, so verify current capabilities before committing.
Self-managed storage with cloud KMS
Storing state in your own S3 bucket, Azure container, or GCS bucket keeps data inside your compliance boundary. Secrets are encrypted with a key you control in AWS KMS, Azure Key Vault, or GCP Cloud KMS. Access is governed by native IAM. The cost is configuration: you must enable object versioning, write least-privilege bucket policies, and explicitly configure locking. Without versioning, an accidental overwrite or deletion can destroy history.
Passphrase-based encryption
A passphrase provider derives an encryption key from a shared string. It is simple and requires no external service, but the passphrase becomes a shared liability. There is no per-user audit trail, rotation is manual, and it is generally unsuitable for multi-team production.
Concrete implementation: S3 backend with AWS KMS
The following example initializes a stack that stores state in an S3 bucket and encrypts secrets with an AWS KMS key. Run these commands on a workstation or CI/CD runner that has the Pulumi CLI installed and AWS credentials with permissions for S3 and KMS. These examples assume a recent Pulumi CLI (3.x); older versions may differ in flags or provider URI formats.
# Authenticate to the self-managed backend
pulumi login s3://<bucket-name>
# Initialize the stack and select the KMS secrets provider
# Replace <stack-name> and <kms-key-id> with your values.
# The exact URI format for the key may vary by CLI version;
# confirm it against the Pulumi documentation.
pulumi stack init <stack-name> --secrets-provider="awskms:///<kms-key-id>"
Expected checks: If login succeeds, the CLI writes a local credentials file. If stack init succeeds, the backend creates a state entry for the stack. Any failure here usually indicates missing IAM permissions or an incorrect KMS identifier.
Risks: The state file contains sensitive metadata. Never commit it to version control. Ensure the S3 bucket blocks public access and that only the CI/CD role and named engineers can read or write objects.
Validating the setup
After initialization, verify the active backend and stack before deploying resources.
# Confirm the backend URL and CLI version
pulumi whoami -v
# List stacks visible to the current credentials
pulumi stack ls
# Inspect configuration; secret values should appear as ciphertext
pulumi config
In the pulumi config output, a secret set with --secret should show ciphertext—the encrypted form of the value—not plaintext. If plaintext appears, the secrets provider was not applied correctly.
To test access controls, attempt a pulumi preview from a principal with restricted IAM permissions. The command should fail with an authorization error if the policy is correct.
Limitations and migration warnings
- Changing the state backend or secrets provider after stack creation is a breaking change. It requires exporting state, re-initializing, and re-encrypting secrets.
- Self-managed backends do not provide automatic locking unless you configure the mechanism supported by your storage provider. Verify locking behavior for your chosen backend before running concurrent updates.
- Pulumi Cloud pricing tiers and feature names change over time. Validate current capabilities against your requirements.
Practical checklist
- Decide whether state must remain in your cloud account.
- If using self-managed storage, enable versioning and least-privilege policies before the first
pulumi up. - Select a secrets provider that matches your key management strategy.
- Run
pulumi whoami -vandpulumi stack lsto confirm the backend. - Verify secrets render as ciphertext in
pulumi config.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.