terraform: Unmark provisioner arguments

If provisioner configuration or connection info includes sensitive
values, we need to unmark them before calling the provisioner. Failing
to do so causes serialization to error.

Unlike resources, we do not need to capture marked paths here, so we
just discard the marks.
pull/26611/head
Alisdair McDiarmid 6 years ago
parent 31033001a8
commit 9c580335e3

@ -12052,3 +12052,58 @@ output "out" {
t.Fatalf("wrong result\ngot: %#v\nwant: %#v", got, want)
}
}
func TestContext2Apply_provisionerSensitive(t *testing.T) {
m := testModule(t, "apply-provisioner-sensitive")
p := testProvider("aws")
pr := testProvisioner()
pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
if req.Config.ContainsMarked() {
t.Fatalf("unexpectedly marked config value: %#v", req.Config)
}
command := req.Config.GetAttr("command")
if command.IsMarked() {
t.Fatalf("unexpectedly marked command argument: %#v", command.Marks())
}
return
}
p.ApplyResourceChangeFn = testApplyFn
p.PlanResourceChangeFn = testDiffFn
ctx := testContext2(t, &ContextOpts{
Config: m,
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
Provisioners: map[string]ProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
},
Variables: InputValues{
"password": &InputValue{
Value: cty.StringVal("secret"),
SourceType: ValueFromCaller,
},
},
})
if _, diags := ctx.Plan(); diags.HasErrors() {
logDiagnostics(t, diags)
t.Fatal("plan failed")
}
state, diags := ctx.Apply()
if diags.HasErrors() {
logDiagnostics(t, diags)
t.Fatal("apply failed")
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testTerraformApplyProvisionerSensitiveStr)
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
}
// Verify apply was invoked
if !pr.ProvisionResourceCalled {
t.Fatalf("provisioner was not called on apply")
}
}

@ -683,10 +683,17 @@ func (n *EvalApplyProvisioners) apply(ctx EvalContext, provs []*configs.Provisio
})
}
// If our config or connection info contains any marked values, ensure
// those are stripped out before sending to the provisioner. Unlike
// resources, we have no need to capture the marked paths and reapply
// later.
unmarkedConfig, _ := config.UnmarkDeep()
unmarkedConnInfo, _ := connInfo.UnmarkDeep()
output := CallbackUIOutput{OutputFn: outputFn}
resp := provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{
Config: config,
Connection: connInfo,
Config: unmarkedConfig,
Connection: unmarkedConnInfo,
UIOutput: &output,
})
applyDiags := resp.Diagnostics.InConfigBody(prov.Config)

@ -866,6 +866,13 @@ aws_instance.bar:
type = aws_instance
`
const testTerraformApplyProvisionerSensitiveStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
type = aws_instance
`
const testTerraformApplyDestroyStr = `
<no state>
`

@ -0,0 +1,18 @@
variable "password" {
type = string
sensitive = true
}
resource "aws_instance" "foo" {
connection {
host = "localhost"
type = "telnet"
user = "superuser"
port = 2222
password = var.password
}
provisioner "shell" {
command = "echo ${var.password} > secrets"
}
}
Loading…
Cancel
Save