Managing Secrets in Pulumi ESC
This guide shows you how to store and retrieve secrets in Pulumi ESC environments. Secrets are encrypted values that ESC stores securely and hides from view by default.
Prerequisites
- ESC CLI installed
- Pulumi account created
- An ESC environment (create one with
esc env init <org>/<project>/<env-name>)
Understanding ESC values
ESC environments store configuration as key-value pairs in YAML format. All values are defined under a top-level values key:
values:
apiEndpoint: https://api.example.com
region: us-west-2
apiKey:
fn::secret: my-secret-value
Values can be:
- Plain text - Regular configuration values (region, endpoint URLs)
- Secrets - Encrypted values marked with
fn::secret - Structured data - Objects and arrays
- Dynamic values - Generated from providers (covered in other guides)
Storing secrets
Via the CLI
Add a secret to your environment using the --secret flag:
esc env set <org>/<project>/<env-name> apiKey my-secret-value --secret
For example:
esc env set my-org/my-project/dev apiKey demo-secret-123 --secret
This encrypts the value before storing it.
Via the Pulumi Cloud console
- Navigate to Pulumi Cloud
- Select Environments in the left navigation
- Select your environment
- In the editor, add your secret using the
fn::secretfunction:
values:
apiKey:
fn::secret: my-secret-value
- Select Save
The console will encrypt the secret and replace the plaintext value with a ciphertext reference:
values:
apiKey:
fn::secret:
ciphertext: ZXNjeAA...
Retrieving secrets
Via the CLI
Open your environment to retrieve all values, including secrets:
esc env open <org>/<project>/<env-name>
This returns all values in JSON format with secrets revealed:
{
"apiKey": "my-secret-value",
"region": "us-west-2"
}
To retrieve a single value:
esc env get <org>/<project>/<env-name> apiKey
Via the Pulumi Cloud console
- Select your environment in Pulumi Cloud
- Select Open to evaluate the environment
- Toggle Show secrets to reveal encrypted values
Organizing secrets
Nested structure
Group related secrets using nested keys:
values:
database:
host: db.example.com
password:
fn::secret: db-password-123
port: 5432
api:
key:
fn::secret: api-key-456
endpoint: https://api.example.com
Access nested values with dot notation:
esc env get my-org/my-project/dev database.password
Multiple environments
Organize secrets by environment (dev, staging, production) using separate ESC environments:
my-org/my-project/dev- Development secretsmy-org/my-project/staging- Staging secretsmy-org/my-project/prod- Production secrets
Each environment can have different RBAC permissions, ensuring production secrets are only accessible to authorized users.
Best practices
Use secrets for sensitive data
Mark these values as secrets:
- API keys and tokens
- Database passwords
- Private keys and certificates
- OAuth client secrets
Use plain text for non-sensitive data
These can be plain text:
- Region names
- Public endpoints
- Feature flags
- Port numbers
Rotate secrets regularly
Update secrets by setting new values:
esc env set my-org/my-project/prod apiKey new-secret-value --secret
ESC versions every change, allowing you to roll back if needed.
Control access with RBAC
Use Role-Based Access Control to limit who can read or write secrets:
- Grant teams read-only access to production secrets
- Allow developers full access to development secrets
- Use service accounts for CI/CD access
Next steps
- Integrate with Pulumi IaC - Use secrets in your infrastructure code
- Dynamic secrets - Pull secrets from AWS, Azure, GCP secret stores
- Running commands with esc run - Inject secrets into any command
- Access control reference - Complete RBAC documentation
Thank you for your feedback!
If you have a question about how to use Pulumi, reach out in Community Slack.
Open an issue on GitHub to report a problem or suggest an improvement.
