Skip to content

Commit

Permalink
Secret rotation docs (#14106)
Browse files Browse the repository at this point in the history
* Secret rotation docs draft

* PR feedback

* Add implicit imports info

* Add AWS IAM Rotator docs (#13992)

* Add AWS IAM Rotator docs

* fixup

* PR feedback

* Update provider docs

* Rotation schedule

* Final touches

* PR feedback

---------

Co-authored-by: Sean Yeh <[email protected]>
  • Loading branch information
komalali and seanyeh authored Feb 19, 2025
1 parent edc9639 commit 85219dd
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 4 deletions.
2 changes: 1 addition & 1 deletion content/docs/esc/environments/access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ meta_desc: Pulumi ESC provides granular access control to manage permissions wit
menu:
esc:
parent: esc-environments
weight: 6
weight: 7
---

Pulumi ESC allows you to enforce least-privileged access across your environments through role-based access controls (RBAC). By assigning precise permissions at the organization and team levels, you ensure that users only have access to the environments they need. All changes, including environment updates and access modifications, are fully logged to provide complete auditing and compliance tracking, helping your organization maintain security best practices.
Expand Down
Binary file added content/docs/esc/environments/button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ menu:
name: Dynamic environment variables
identifier: esc-dynamic-environmeant-variables
parent: esc-environments
weight: 4
weight: 5
---

The Pulumi ESC CLI includes a [`run` command](/docs/esc-cli/commands/esc_run/) that allows you to run commands with Pulumi ESC managed environment variables, without exporting them to your shell.
Expand Down
90 changes: 89 additions & 1 deletion content/docs/esc/environments/imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ menu:
weight: 2
---

Environments can also be composed from other environments.
Environments can be composed from other environments.

Different applications are often configured in similar ways and with common values --- for example, an e-commerce site and order-management system both configured to use the same cloud account, database-connection string, and third-party API key. Managing the duplication of these values across multiple configuration files, however, can be difficult, especially when one of those values changes --- e.g., when an API key is regenerated.

To address these challenges, Pulumi ESC allows you to identify common or closely related configuration settings and define them only once, as individual environments, and then _import_ those environments into other, more specialized environments as needed. Imports also allow you to expose certain environments without having to distribute any concrete values and to delegate responsibility for particular environments to other teams in your organization. Environments can import both static and dynamic values, including secrets, from any number of other environments.

## Explicit imports

Explicit imports are defined in the `imports` section of an environment. The `imports` section is a list of environments that are resolved at runtime. The values from the imported environments are merged into the current environment using a [JSON Merge Patch](https://www.rfc-editor.org/rfc/rfc7396), with the current values overwriting the imported environment's values where keys are redefined.

In the following example, two environments, `aws/dev` and `stripe/dev`, are used to compose a third environment, `myapp/dev`:

```yaml
Expand Down Expand Up @@ -81,3 +85,87 @@ $ echo "'$GREETING'"
```

Notice in the example that the `environmentVariables` were exposed to the `bash` command, but not to the surrounding shell, and that the values marked as secrets with `fn::secret` were protected from exposure.

## Implicit imports

Implicit imports are used to reference values from other environments without having to explicitly import them. This is useful when you want to reference a value from another environment without needing to expose the entire environment.

Implicit imports take the form of a reference to the special `environments` key like `${environments.PROJECT.ENV.VALUEPATH}`.

In the following example, the `aws/dev` environment is implicitly imported into the `myapp/dev` environment:

```yaml
# myorg/aws/dev
values:
aws:
region: us-west-2
login:
fn::open::aws-login:
oidc:
duration: 1h
roleArn: arn:aws:iam::123456789012:role/MyRole
sessionName: pulumi-environments-session
```

```yaml
# myorg/myapp/dev
values:
greeting: Hello from the myapp/dev environment!
environmentVariables:
AWS_REGION: ${environments.aws.dev.aws.region}
GREETING: ${greeting}
```

In this example, the `AWS_REGION` value is implicitly imported from the `aws/dev` environment, but only the `region` value is imported, rather than the entire `aws/dev` environment.

The resolved value of the above environment at `open` time would be:

```json
{
"greeting": "Hello from the myapp/dev environment!",
"environmentVariables": {
"AWS_REGION": "us-west-2",
"GREETING": "Hello from the myapp/dev environment!"
}
}
```

Compare this to the resolved value of the `myapp/dev` environment example from the explicit imports section, where each imported environment is merged into the current environment:

```json
{
"stripe": {
"apiURL": "https://api.stripe.com",
"apiKey": "sk_XemWAl12i4x3hZhp4vBKDEXAMPLE"
},
"aws": {
"region": "us-west-2",
"login": {
"accessKeyId": "AKIAIOSFODNN7EXAMPLE",
"secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLE"
}
},
"greeting": "Hello from the myapp/dev environment!",
"environmentVariables": {
"AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE",
"AWS_SECRET_ACCESS_KEY": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLE",
"STRIPE_API_KEY": "sk_XemWAl12i4x3hZhp4vBKDEXAMPLE",
"STRIPE_API_URL": "https://api.stripe.com",
"GREETING": "Hello from the myapp/dev environment!"
}
}
```

## Evaluation

Note that each distinct reference is evaluated exactly once. Consider the following case:

```yaml
imports:
- default/foo
values:
a: ${environments.default.foo.bar}
```

In the environment definition above, `default/foo` is evaluated only once.
120 changes: 120 additions & 0 deletions content/docs/esc/environments/rotation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
title: Rotating secrets
title_tag: Rotating secrets | Pulumi ESC
h1: Rotating secrets
meta_desc: Pulumi ESC allows you to rotate secrets on a pre-defined schedule.
menu:
esc:
name: Rotating secrets
identifier: esc-rotating-secrets
parent: esc-environments
weight: 4
---

Secret Rotation is a feature in Pulumi ESC that enables the automated periodic updating of sensitive credentials. By defining a schedule, you can specify when and how often a secret should be rotated, ensuring that any long-lived credentials do not remain static over time. This feature is useful for maintaining best practices in security by reducing the risk of credential exposure or misuse.

ESC Rotated secrets use a two-secret strategy in which two secrets are active and valid at any point in time. This is especially useful when multiple instances of an application share a credential but not all instances pull in the latest credential at the same time, allowing you to rotate a secret without worrying about some instances being unavailable due to invalid credentials.

## Usage

### Definition

Secret rotations are defined using a special function, `fn::rotate::`, which is evaluated by the Pulumi ESC runtime during a `rotation` action, which may be executed manually via the CLI or Pulumi Cloud UI, or automatically on a schedule.

```yaml
values:
rotatedCredentials:
fn::rotate::aws-iam:
inputs:
region: us-west-2
login: ${environments.credentials.production.aws.login}
userArn: arn:aws:iam::123456789012:user/username
# If there are existing credentials, it's possible to specify them in the state - but this section is optional
state:
previous:
accessKeyId: AKIA...
secretAccessKey:
fn::secret:
ciphertext: ...
current:
accessKeyId: AKIA...
secretAccessKey:
fn::secret:
ciphertext: ...
```
In the above example, note the `${environments.credentials.production.aws.login}` reference. This is an implicit import of the `credentials/production` environment's aws.login path.

This import is only resolved at `rotate` time, meaning that the value is not available during `open` time, making it possible for a user to access the rotated secret without needing access to the managing credentials.

### Rotation

Once a rotation function is configured within the environment definition, you can manually rotate your secrets by running the `esc env rotate` command, or by clicking the `Rotate secrets` button in the Pulumi Cloud UI.

#### Via the CLI

```bash
esc env rotate rotators/pulumi-ci
Environment 'rotators/pulumi-ci' rotated.
New revision '19' was created.
```

#### Via the Pulumi Cloud UI

![button.png](../button.png)

### Schedule

You can create a schedule for automatic rotation of your secrets in the Pulumi Cloud UI by navigating to the `Rotated secrets` tab of your environment, and clicking the `Create rotation schedule` button.

The rotation schedule can be defined as a [cron expression](https://crontab.cronhub.io/).

![schedule.png](../schedule.png)

## Permissions

- To `rotate` an environment, a user must have `WRITE` permissions on the environment, and `OPEN` permissions on any imported environment.
- To `open` an environment, a user must have `OPEN` permissions on the environment (and does not need any permissions for the implicitly imported environment which provides the rotation credentials).
- To configure a rotation schedule for an environment, the user must have `WRITE` permissions on the environment.

## Best practices

### Least privilege

It is recommended to follow the principle of least privilege when defining the permissions for the user or role that will be used to rotate the secret. The user or role should have only the necessary permissions to perform the rotation action, and no more.

The minimum required permissions for each rotation function are documented in the [Rotated Secret](/docs/esc/integrations/rotated-secrets) provider documentation.

### Separation of concerns

It is recommended that the login credentials required to perform the rotation action are stored in a separate environment, and imported via an [implicit import](/docs/esc/environments/imports#implicit-imports), as shown in the example above. This ensures that the credentials are not exposed to users who are unable to open the managing environment.

### Composition

It is a best practice to define a separate environment for your rotated functions, and import them into the environments that require the rotated credentials. This allows you to manage the rotation logic in a single place, and allows for the rotated environment to be versioned separately from the rest of your configuration. Specifically, since a new revision is created on every rotation, you may want to always import the latest version of the rotated environment to ensure that the latest rotated credentials are always used.

Another reason to keep your rotated functions in a separate environment is that an environment containing a rotation function *cannot be rolled back*, since the rotated secrets have been deactivated. By keeping your rotation functions separate, you can ensure that the rest of your configuration can be rolled back to a previous revision if needed.

### Organization

There are a few options for how you might organize your rotated environments.

You may want to organize your rotated environment by rotation schedule. Since a single environment can only have one rotation schedule, you can group your rotated environments by the frequency at which they need to be rotated. For example, you may have a `daily` environment, a `weekly` environment, and a `monthly` environment, each with their own rotation schedule.

Alternatively, you may want to keep a separate environment for each rotated secret. This avoids the potential for partial failures, described in more detail below.

### Handling partial failures

If multiple rotation functions are defined in a single environment, it is possible that some fail while others succeed. In these cases, a partial failure will be reported.

To handle partial failures, failed keys can be individually retried using the `esc env rotate [envName] [path(s)-to-rotate]` command. This will allow you to retry the rotation of a specific key without affecting the rotation of other keys in the environment.

```bash
esc env rotate rotators/pulumi-ci credentials.bot.aws
Environment 'rotators/pulumi-ci' rotated.
New revision '23' was created.
```

{{% notes type="warning" %}}
**WARNING** Beware of double rotation in the case of partial failures. If a key is rotated twice, the first rotation will be invalidated and the second rotation will be active. This can lead to unexpected behavior if not handled correctly, for example if the rotated secret has not been updated at the consumer.
{{% /notes %}}
Binary file added content/docs/esc/environments/schedule.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion content/docs/esc/environments/webhooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ meta_image: /images/docs/meta-images/docs-meta.png
menu:
esc:
parent: esc-environments
weight: 5
weight: 6
aliases:
- /docs/esc-cli/commands/
- /docs/esc/webhooks/
Expand Down
20 changes: 20 additions & 0 deletions content/docs/esc/integrations/rotated-secrets/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Rotated secrets
title_tag: Rotate credentials in Pulumi ESC with Rotators | Pulumi ESC
h1: Rotate credentials for external services
meta_desc: Pulumi ESC enables credential rotation for various external services.
menu:
esc:
name: Rotated secrets
identifier: esc-rotated-secrets
parent: esc-integrations
weight: 2
---

Pulumi ESC Rotators enable you to rotate credentials both automatically and manually for a number of supported services.

To learn how to set up and use each rotator, follow the links below. To learn how to configure OpenID Connect (OIDC) for the rotators that support it, see [OpenID Connect integration](/docs/pulumi-cloud/oidc/) in the Pulumi Cloud documentation.

| Rotator | Description |
|--------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| [aws-iam](/docs/esc/integrations/rotated-secrets/aws-iam/) | The `aws-iam` rotator enables you rotate access credentials for an AWS IAM User. |
Loading

0 comments on commit 85219dd

Please sign in to comment.