-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
provider rotation #432
base: main
Are you sure you want to change the base?
provider rotation #432
Conversation
be5df41
to
4e22ea2
Compare
|
||
// ApplyPatches applies a set of patches values to an environment definition. | ||
// If patch values contain secret values, they will be wrapped with fn::secret. | ||
func ApplyPatches(source []byte, patches []*Patch) ([]byte, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not blocking just more of a thought - I wonder if we would ever want to have this be generic enough to apply any patch instead of limiting this to just values. I know for our current use case this isn't in scope but if a customer wants to use this to apply a patch for automating a migration of which requires import changes it could be helpful.
If we stick with just values here we may want to capture that in the function name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fair, it could drop the hardcoded assumption of the values
toplevel key.
the name is also a bit of a misnomer since it's not doing a json patch, it's just doing a replacement. Perhaps BulkSetValues
or ApplyReplacements
or something like that? idk
Schema() (inputs, state, outputs *schema.Schema) | ||
|
||
// Open retrieves the provider's secrets. | ||
Open(ctx context.Context, inputs, state map[string]Value, executionContext EnvExecContext) (Value, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
possibly Open should only take state
, not inputs
, because longer term we don't want to necessarily evaluate managing credential inputs during Open, just during Rotate?
eval/eval.go
Outdated
@@ -98,7 +105,28 @@ func CheckEnvironment( | |||
execContext *esc.ExecContext, | |||
showSecrets bool, | |||
) (*esc.Environment, syntax.Diagnostics) { | |||
return evalEnvironment(ctx, true, name, env, decrypter, providers, environments, execContext, showSecrets) | |||
checked, _, diags := evalEnvironment(ctx, true, name, env, decrypter, providers, nil, environments, execContext, showSecrets, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll need to accept a rotatorLoader in CheckEnvironment to pass to the eval
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are totally right.. this is partly why I'm unsure about the Provider and Rotator interfaces diverging for Open() and Schema(), which is why RotatorLoader is even required :(
Schema() (inputs, state, outputs *schema.Schema) | ||
|
||
// Open retrieves the provider's secrets. | ||
Open(ctx context.Context, inputs, state map[string]Value, executionContext EnvExecContext) (Value, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I would drop the inputs from open since we don't really need the inputs to perform the open. Also, it encourages best practice of not having the inputs be considered part of the open permissions
envs EnvironmentLoader, | ||
execContext *esc.ExecContext, | ||
showSecrets bool, | ||
) (*esc.Environment, syntax.Diagnostics) { | ||
rotatePaths map[string]bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pgavlin wdyt about removing this? is there a strong use case for rotating specific paths within an environment?
@@ -165,6 +198,9 @@ type evalContext struct { | |||
root *expr // the root expression | |||
base *value // the base value | |||
|
|||
rotatePaths map[string]bool // when non-nil, specifies providers to rotate. if empty, the full environment is rotated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this might be too overloaded, maybe we should have an explicit rotating
boolean instead of this nil check
} | ||
}() | ||
// wrap secret values | ||
if v.Secret { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this only wrap the top most value as a secret instead of the potentially nested values that are secrets? (I could be wrong about this but adding a test should help determine this)
// Rotators persist internal state by writing back to the environment. | ||
type Rotator interface { | ||
// Schema returns the provider's input, state, and output schemata. | ||
Schema() (inputs, state, outputs *schema.Schema) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We talked about it being confusing that open
doesn't necessarily return the full state, so perhaps this can be simplified so that the output
schema is used for state
schema?
(This would also help heal the divergence of the Rotator and Provider interfaces)
Introduces a new provider type and verb to support rotating static credentials.
Rotator providers have an additional
state
input which is used as a write-back target. The result of invoking Rotate is persisted back into the environment to this key. This provides a stable location to write to without accidentally clobbering interpolations that might be used for other inputs.The new
fn::rotate
function type is used to invoke this new type of provider. It behaves similarly to existing providers during Open, but during rotation the evaluator will invoke the Rotate and collect their outputs, and the caller is expected to persist these updates back into the environment as a new revision.Closes https://github.com/pulumi/pulumi-service/issues/24986