secret() is an expression-level built-in that reads a sensitive value from an external secret store when Pulumi runs pulumi up. The value is never written to source code or to the Pulumi state file in plain text.
Syntax
Backends
ubx supports five backends. The backend name is the first argument tosecret().
env — environment variable
env backend is Resolved<T> — the value is read inline via os.environ.get() and does not involve any async Pulumi Output. Use it for values that are present in the deployment environment but should not appear in source code.
aws_secrets_manager — AWS Secrets Manager
pulumi.Output.secret(), which instructs Pulumi to encrypt it in the state file. The boto3 client uses ambient AWS credentials (environment variables, EC2 instance profile, or AWS SSO).
vault — HashiCorp Vault
mount/path#field — the # separator selects a specific field from the secret’s key-value map. When #field is omitted, the first value in the map is returned. The helper reads from the KV v2 engine and uses VAULT_ADDR and VAULT_TOKEN from the environment.
gcp_secret_manager — GCP Secret Manager
azure_key_vault — Azure Key Vault
AZURE_VAULT_URL to your vault’s endpoint (e.g., https://myvault.vault.azure.net). DefaultAzureCredential tries environment variables, managed identity, and Azure CLI in order.
Pending<T> propagation
env is Resolved<T> — the value is a plain string at runtime. All other backends are Pending<T> — the value is a pulumi.Output[str], because it is fetched asynchronously and wrapped in pulumi.Output.secret().
Pending values propagate through the expression tree. Passing a non-env secret directly to a resource property is always valid — Pulumi accepts Input[T] (which includes Output[T]) for all resource properties. But including a Pending secret in a sync context (such as values {} inside a sync argocd block) will trigger .apply() wrapping automatically.
Helper deduplication
Helper functions are emitted once per file, before the stack code. If multiplesecret() calls use the same backend, the helper is only emitted once regardless of how many times it is called:
Unknown backend
An unrecognized backend name produces a warning at compile time and is treated as Pending<T>. The generated code will call a helper function matching the pattern__ubx_<backend>_secret(path), which you must define yourself:
When to use secret() vs ephemeral vs from = "..."
| Scenario | Recommended approach |
|---|---|
| Value is in an env var at deploy time | secret("env", "VAR_NAME") or ephemeral input |
| Value is in AWS Secrets Manager, Vault, GCP, or Azure | secret("backend", "path") in a locals block |
| Input should always come from a secret store (no manual config set) | from = "scheme:path" on an input field |
| Input should be encrypted in Pulumi state | ephemeral modifier |
| Input from secret store AND encrypted in state | ephemeral + from = "scheme:path" |
from = "..." attribute and ephemeral inputs for the ephemeral modifier.
