pulumi/pulumi
Security
How pulumi/pulumi handles trust, authentication, and secrets.
Active contributors
Active contributors: Justin Van Patten, Thomas Gummerer, Ian Wahbe, Fraser Waters
Trust boundaries
graph TD
User[User shell] -->|local| CLI[pulumi CLI]
CLI -->|spawns| LangHost[Language host]
CLI -->|spawns| Provider[Provider plugin]
LangHost -->|spawns| UserProg[User program]
CLI -->|HTTPS| Cloud[Pulumi Cloud / DIY backend]
Provider -->|HTTPS| CloudAPI[AWS/Azure/GCP/...]
UserProg -->|gRPC: localhost only| CLI
classDef trusted fill:#dfd
classDef external fill:#fdd
class User,CLI,LangHost,UserProg,Provider trusted
class Cloud,CloudAPI externalBoundaries:
- User shell ↔ CLI — the CLI runs with the user's privileges.
- CLI ↔ plugins — language hosts and providers are trusted — they're spawned by the CLI from the user's own plugin cache. Plugin tampering = full compromise.
- CLI ↔ Pulumi Cloud (
httpstate) — HTTPS, OAuth bearer tokens. - Provider ↔ cloud APIs — the provider authenticates as the user (their AWS creds, etc.).
- gRPC between processes — bound to localhost (
127.0.0.1:<random>); not authenticated. Anyone on the same machine could connect, which is not a defended-against threat model.
Authentication
Pulumi Cloud (httpstate)
pkg/cmd/pulumi/auth/ and pkg/backend/httpstate/token_source.go handle authentication:
pulumi logininitiates OAuth (browser flow) or accepts aPULUMI_ACCESS_TOKEN.- Tokens are stored in
~/.pulumi/credentials.json(mode 0600). - The token source supports refresh.
- Per-org tokens are scoped to that org.
DIY backend
No authentication at the Pulumi layer. The blob bucket itself enforces access (S3/GCS/Azure Blob IAM); Pulumi just reads/writes via gocloud.dev/blob.
Secrets at rest
Already detailed under systems/secrets. Brief recap:
- Every secret in the snapshot is encrypted with the configured
secrets.Manager. - Default: passphrase-derived AES for DIY, service-managed for Cloud.
- KMS providers (AWS, Azure, GCP, Vault) are first-class.
- The "secret" bit is sticky through
Outputtransformations.
Secrets in transit
- Engine ↔ Pulumi Cloud: HTTPS only, hard-coded.
- Engine ↔ provider: gRPC over localhost loopback (no TLS).
- Engine ↔ language host: gRPC over localhost loopback (no TLS).
Pluging integrity
Plugins are downloaded via HTTPS from GitHub Releases (or the Pulumi Cloud registry). Integrity:
- HTTPS prevents in-transit tampering.
pulumi plugin installvalidates the SHA256 against the published manifest where available.- Once installed, plugins live in
~/.pulumi/plugins/and are not re-verified at run time.
There is no signature verification chain from the plugin author to the user's machine — installing a malicious plugin would be a full compromise.
Provider credentials
Pulumi providers authenticate with the cloud they manage. They typically read environment variables (AWS_ACCESS_KEY_ID, AZURE_CLIENT_ID, etc.) or files (~/.aws/credentials). The engine does not inspect these.
Because providers run as separate processes spawned by the engine, they inherit the engine's environment. Don't put secrets in Pulumi.<stack>.yaml config except as encrypted secrets.
Encrypted log streams
Diagnostic events that the engine streams back to Pulumi Cloud are encrypted in transit (HTTPS). Log payloads sanitize secret values before serialization (see sdk/go/common/diag/).
pkg/engine/encryptedlog/ handles end-to-end encrypted log streaming for sensitive scenarios where TLS alone isn't sufficient.
Policy enforcement
Policy packs (proto/pulumi/analyzer.proto) run as plugins. They can:
- Mandatory policies — block an op (the engine refuses to proceed).
- Advisory policies — print a warning.
- Remediation policies — propose a transformation that the engine can apply.
The CLI pulumi policy (pkg/cmd/pulumi/policy/) is the management surface.
What about the user program?
User programs run in the language host's sandbox, which is not a security sandbox in any meaningful sense — the program has access to the network, the filesystem, the env, etc. Pulumi treats user code as trusted: a malicious user program could read secrets, exfiltrate, etc.
The design philosophy is "Pulumi is your code". If you don't trust the program, don't run it.
Recent security work
Notable security-relevant areas in recent history:
- Snapshot integrity (
validating_persister.go,analyze_snapshot.go) — every snapshot save is round-tripped through structural validation. - Token rotation (
pkg/backend/httpstate/token_source.go) — automatic refresh. - Cloud registry (
pkg/backend/httpstate/cloud_registry.go) — alternate plugin source allowing org-scoped trust. - ESC integration (
pkg/cmd/pulumi/env/) — short-lived credentials per stack via Pulumi Environments.
Known limitations
- Plugin caches are not re-verified post-install.
~/.pulumi/plugins/should be treated as part of the trusted base. - No package signing chain.
- gRPC sockets between engine and plugins are unauthenticated localhost — multi-tenant servers should not run multiple users' Pulumi at once on the same host.
See also
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.