apply: include sensitive metadata when comparing changed input values (#37582)

* apply: include sensitive metadata when comparing changed input values

* correct changelog entry
mend-security/deploy-workflow-psirt_prd0014263
Liam Cervante 7 months ago committed by GitHub
parent 003edcf5a1
commit 00d680d819
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
kind: BUG FIXES
body: 'apply: hide sensitive inputs when values have changed between plan and apply'
time: 2025-09-10T09:54:24.889605+02:00
custom:
Issue: "37582"

@ -17,6 +17,7 @@ import (
"github.com/hashicorp/terraform/internal/backend/backendrun"
"github.com/hashicorp/terraform/internal/command/views"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/lang/marks"
"github.com/hashicorp/terraform/internal/logging"
"github.com/hashicorp/terraform/internal/plans"
"github.com/hashicorp/terraform/internal/states"
@ -345,6 +346,14 @@ func (b *Local) opApply(
Subject: rng,
})
} else {
markedPlannedVar := plannedVar
markedParsedVar := parsedVar.Value
if decl.Sensitive {
markedPlannedVar = markedPlannedVar.Mark(marks.Sensitive)
markedParsedVar = markedParsedVar.Mark(marks.Sensitive)
}
// The user can't override the planned variables, so we
// error when possible to avoid confusion.
if parsedVar.Value.Equals(plannedVar).False() {
@ -361,7 +370,7 @@ func (b *Local) opApply(
"because a saved plan includes the variable values that were set when it was created. "+
"The saved plan specifies %s as the value whereas during apply the value %s was %s. "+
"To declare an ephemeral variable which is not saved in the plan file, use ephemeral = true.",
varName, tfdiags.CompactValueStr(plannedVar), tfdiags.CompactValueStr(parsedVar.Value),
varName, tfdiags.CompactValueStr(markedPlannedVar), tfdiags.CompactValueStr(markedParsedVar),
parsedVar.SourceType.DiagnosticLabel()),
Subject: rng,
})
@ -374,7 +383,7 @@ func (b *Local) opApply(
"set when it was created. The saved plan specifies %s as the value whereas during apply "+
"the value %s was %s. To declare an ephemeral variable which is not saved in the plan "+
"file, use ephemeral = true.",
varName, tfdiags.CompactValueStr(plannedVar), tfdiags.CompactValueStr(parsedVar.Value),
varName, tfdiags.CompactValueStr(markedPlannedVar), tfdiags.CompactValueStr(markedParsedVar),
parsedVar.SourceType.DiagnosticLabel()),
Subject: rng,
})
@ -386,7 +395,7 @@ func (b *Local) opApply(
panic(fmt.Sprintf("Attempted to change variable %s when applying a saved plan. "+
"The saved plan specifies %s as the value whereas during apply the value %s was %s. "+
"This is a bug in Terraform, please report it.",
varName, tfdiags.CompactValueStr(plannedVar), tfdiags.CompactValueStr(parsedVar.Value),
varName, tfdiags.CompactValueStr(markedPlannedVar), tfdiags.CompactValueStr(markedParsedVar),
parsedVar.SourceType.DiagnosticLabel()))
}
}

@ -1053,6 +1053,78 @@ func TestApply_planWithEnvVars(t *testing.T) {
}
}
func TestApply_planWithSensitiveEnvVars(t *testing.T) {
_, snap := testModuleWithSnapshot(t, "apply-sensitive-variable")
plan := testPlan(t)
addr, diags := addrs.ParseAbsOutputValueStr("output.shadow")
if diags.HasErrors() {
t.Fatal(diags.Err())
}
shadowVal := mustNewDynamicValue("noot", cty.DynamicPseudoType)
plan.VariableValues = map[string]plans.DynamicValue{
"shadow": shadowVal,
}
plan.Changes.Outputs = append(plan.Changes.Outputs, &plans.OutputChangeSrc{
Addr: addr,
ChangeSrc: plans.ChangeSrc{
Action: plans.Create,
After: shadowVal,
},
})
planPath := testPlanFileMatchState(
t,
snap,
states.NewState(),
plan,
statemgr.SnapshotMeta{},
)
statePath := testTempFile(t)
p := applyFixtureProvider()
view, done := testView(t)
c := &ApplyCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
View: view,
},
}
t.Setenv("TF_VAR_shadow", "unique")
args := []string{
"-state", statePath,
"-no-color",
planPath,
}
code := c.Run(args)
output := done(t)
if code != 0 {
t.Fatal("unexpected failure: ", output.All())
}
out := output.Stdout()
expectedWarn := "Warning: Ignoring variable when applying a saved plan\n"
if !strings.Contains(out, expectedWarn) {
t.Fatalf("expected warning in output, given: %q", out)
}
if !strings.Contains(out, "(sensitive value)") {
t.Error("should have elided sensitive value")
}
if strings.Contains(out, "noot") {
t.Error("should have elided sensitive input, but contained value")
}
if strings.Contains(out, "unique") {
t.Error("should have elided sensitive input, but contained value")
}
}
// A saved plan includes a list of "apply-time variables", i.e. ephemeral
// input variables that were set during the plan, and must therefore be set
// during apply. No other variables may be set during apply.

@ -0,0 +1,9 @@
variable "shadow" {
type = string
sensitive = true
}
output "foo" {
value = var.shadow
sensitive = true
}
Loading…
Cancel
Save