pulumi/pulumi
Secrets
Active contributors: Justin Van Patten, Thomas Gummerer, Ian Wahbe
Purpose
Pulumi treats secret values as a first-class data type. A value marked secret stays encrypted in the snapshot, in the cloud history, and in all logs (rendered as [secret]). The secrets system controls how those values are encrypted at rest.
Where it lives
pkg/secrets/
├── manager.go # secrets.Manager interface
├── provider.go # Manager constructor abstraction
├── mock.go # In-memory mock
├── b64/ # Base64 (no encryption — opt-in for testing)
├── passphrase/ # Local passphrase-derived AES-256-GCM
├── cloud/ # Cloud KMS providers (AWS KMS, Azure Key Vault, GCP KMS, HashiCorp Vault)
└── service/ # Pulumi Cloud service-managed encryptionThe Manager interface
From pkg/secrets/manager.go:
type Manager interface {
Type() string
State() interface{}
Encrypter() Encrypter
Decrypter() Decrypter
}Each backend (DIY, Pulumi Cloud) selects a default manager when a stack is created. The CLI lets you override per-stack via pulumi stack init --secrets-provider=<scheme>.
Supported providers
| Scheme | Manager | Where the key lives |
|---|---|---|
default (DIY) |
passphrase/ |
Derived from PULUMI_CONFIG_PASSPHRASE (or prompted) |
default (Cloud) |
service/ |
Pulumi Cloud-managed |
passphrase |
passphrase/ |
Same as DIY default |
awskms://... |
cloud/aws_kms.go |
AWS KMS |
azurekeyvault://... |
cloud/azure_keyvault.go |
Azure Key Vault |
gcpkms://... |
cloud/gcp_kms.go |
GCP KMS |
hashivault://... |
cloud/hashivault.go |
HashiCorp Vault |
b64 |
b64/ |
No encryption (testing only) |
The cloud-KMS providers use gocloud.dev/secrets, which is also why URL syntax is consistent.
How secrets flow
graph LR
Prog[User program] -->|RegisterResource<br/>with secret input| Engine
Engine -->|provider Configure<br/>+ Check + Diff| Prov[Provider]
Engine -->|persist| Snap[Snapshot]
Snap -->|Encrypter.EncryptValue| Encrypted[Ciphertext blob]
Encrypted -->|on next read| Snap2[Snapshot]
Snap2 -->|Decrypter.DecryptValue| Plaintext[Plaintext]
Plaintext --> EngineThe secret bit is sticky: once a property has been marked secret, it stays secret as it flows through outputs, dependencies, and stack references. AdditionalSecretOutputs on a resource state lets the user tag outputs that provider authors didn't already mark.
Snapshot format
Secrets in the snapshot look like:
{
"4dabf18193072939515e22adb298388d": "1b47061264138c4ac30d75fd1265ec24",
"ciphertext": "v1:abc123...:base64ciphertext"
}The magic constant is the secret marker. Decrypting requires the corresponding Manager. The manager state is itself stored at the top of the snapshot, so the snapshot is self-describing for which provider it needs.
Backend integration
pkg/backend/secrets/ is the bridge between the chosen backend and the secrets system. The DIY backend persists the manager state in the stack file; Pulumi Cloud handles it server-side.
Security properties
- No secret values transit through engine logs. The diagnostic stream sanitizes them.
- Secret outputs are encrypted before being written to disk. A crashed update never leaves plaintext in the snapshot.
- Cross-stack references (
StackReference) preserve the secret bit — reading a secret output from another stack returns it as a secret. - Plaintext appears only in the user program's process. Provider plugins and language hosts may see it, but the engine itself encrypts it before persisting.
The b64 provider is not encryption — it's intentionally weak so you don't accidentally use it in production. The CLI prints a warning when b64 is selected.
Entry points for modification
- Adding a new provider — add a subdirectory under
pkg/secrets/cloud/(or top-level if it's substantively different), implementManager, register the URL scheme. - Tightening the redaction — the diagnostic-side scrubbing lives in
sdk/go/common/diag/. Changes there affect every CLI command. - Changing the snapshot format — must be backwards compatible. New providers should be additive; old snapshots with old providers must keep decrypting.
See also
- Backends
- Resource graph & step model
Pulumi.yaml'sencryptionsaltandsecretsprovider(user-facing docs).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.