pulumi/sdk/go/common/env
Will Jones 6e065298ad Support falling back to snapshot secret managers
Secrets providers are the means by which Pulumi manages the encryption
and decryption of secrets. Since secrets may be present in both the
state (e.g. sensitive resource outputs) and a stack's configuration (API
keys, etc.), so can secrets providers be persisted/specified in both
these places.

Currently, if a stack configuration does not exist, or does not specify
a secrets provider, a default will be instantiated. This is true even
when there is a state snapshot that *does* specify a provider. Consider
as an example the following sequence of events:

* A new Pulumi stack, `dev`, is created with a cloud backend and a
  passphrase secrets provider. The fact that a passphrase provider is in
  use is persisted to `Pulumi.dev.yaml`.
* `pulumi up -s dev` is run in the new stack. The passphrase provider is
  written to the state.
* `Pulumi.dev.yaml` is deleted.
* `pulumi up -s dev` is run again. Not finding `Pulumi.dev.yaml`, Pulumi
  will generate _a new secrets provider_. The default provider for a
  cloud backend is Pulumi Cloud (which is different to the passphrase
  provider serialised in state). As part of the operation, the
  passphrase provider in state will be used to decrypt state secrets.
  When the operation completes, the secrets will be reencrypted with the
  new cloud provider in configuration, and the cloud provider will be
  written back to state. This is despite the fact that the passphrase
  provider was present in the state prior to the operation taking place.

This might be seen as an edge case -- if `Pulumi.dev.yaml` disappears
between operations, we might assume that this would be due to deliberate
actions by the user. Unfortunately this is not the case.

The Automation API supports "inline programs", whereby the source code
for a Pulumi program can be passed as part of the program using the
Automation API, rather than having to have that source code live
somewhere on disk (as it would in a "normal" Pulumi program). Under the
hood, Pulumi makes things work by emulating a "normal" program, writing
out a stack configuration file to a temporary directory. When these
directories differ across runs of the program using the Automation API,
stack configuration is not persisted between runs, enabling this very
scenario (#16890).

This commit adds support for changing this behaviour if an environment
variable, `PULUMI_FALLBACK_TO_STATE_SECRETS_MANAGER`, is set to a truthy
value. In such cases, a secrets provider persisted to state is always
used in the absence of one in configuration. This functionality is gated
behind an environment variable for a couple of reasons:

* This is technically a change in behaviour. It is possible that users
  could be relying on the ability to change their configuration to
  effect a change of secrets provider. That said, given that this use
  case is a. hard to understand the full implications of and b. already
  better served by `pulumi stack change-secrets-provider`, this is not
  necessarily a huge problem.
* In some cases, we need to load the state snapshot twice -- once in
  order to retrieve the secrets manager at configuration time, and once
  again when we actually perform a deployment operation. For large
  stacks, this could mean a marked difference in performance. An opt-in
  environment variable thus feels like a safer choice to guard against
  performance regressions in large numbers of cases.

To avoid sprinkling checks for a global environment variable throughout
the codebase, this commit refactors secret manager loading behind a
`stackSecretsManagerLoader` struct, whose fallback behaviour can be
configured. We then do so using an environment variable at the top level
of each commands. Tests for the new provider have been added, as well as
a smoke test for the high-level scenario.
2024-09-17 13:10:36 +01:00
..
env.go Support falling back to snapshot secret managers 2024-09-17 13:10:36 +01:00