Merge pull request #32004 from hashicorp/brandonc/nested_attr_sensitive

fix: don't reveal nested attributes with sensitive schema
This commit is contained in:
Brandon Croft 2022-11-02 16:18:04 -06:00 committed by GitHub
commit be5984d664
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 952 additions and 61 deletions

View File

@ -172,8 +172,8 @@ func TestConsole_variables(t *testing.T) {
commands := map[string]string{
"var.foo\n": "\"bar\"\n",
"var.snack\n": "\"popcorn\"\n",
"var.secret_snack\n": "(sensitive)\n",
"local.snack_bar\n": "[\n \"popcorn\",\n (sensitive),\n]\n",
"var.secret_snack\n": "(sensitive value)\n",
"local.snack_bar\n": "[\n \"popcorn\",\n (sensitive value),\n]\n",
}
args := []string{}

View File

@ -274,7 +274,10 @@ type blockBodyDiffResult struct {
skippedBlocks int
}
const forcesNewResourceCaption = " [red]# forces replacement[reset]"
const (
forcesNewResourceCaption = " [red]# forces replacement[reset]"
sensitiveCaption = "(sensitive value)"
)
// writeBlockBodyDiff writes attribute or block differences
// and returns true if any differences were found and written
@ -398,7 +401,7 @@ func (p *blockBodyDiffPrinter) writeAttrDiff(name string, attrS *configschema.At
}
if attrS.NestedType != nil {
p.writeNestedAttrDiff(name, attrS.NestedType, old, new, nameLen, indent, path, action, showJustNew)
p.writeNestedAttrDiff(name, attrS, old, new, nameLen, indent, path, action, showJustNew)
return false
}
@ -416,7 +419,7 @@ func (p *blockBodyDiffPrinter) writeAttrDiff(name string, attrS *configschema.At
p.buf.WriteString(" = ")
if attrS.Sensitive {
p.buf.WriteString("(sensitive value)")
p.buf.WriteString(sensitiveCaption)
if p.pathForcesNewResource(path) {
p.buf.WriteString(p.color.Color(forcesNewResourceCaption))
}
@ -441,9 +444,11 @@ func (p *blockBodyDiffPrinter) writeAttrDiff(name string, attrS *configschema.At
// writeNestedAttrDiff is responsible for formatting Attributes with NestedTypes
// in the diff.
func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
name string, objS *configschema.Object, old, new cty.Value,
name string, attrWithNestedS *configschema.Attribute, old, new cty.Value,
nameLen, indent int, path cty.Path, action plans.Action, showJustNew bool) {
objS := attrWithNestedS.NestedType
p.buf.WriteString("\n")
p.writeSensitivityWarning(old, new, indent, action, false)
p.buf.WriteString(strings.Repeat(" ", indent))
@ -454,8 +459,12 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
p.buf.WriteString(p.color.Color("[reset]"))
p.buf.WriteString(strings.Repeat(" ", nameLen-len(name)))
if old.HasMark(marks.Sensitive) || new.HasMark(marks.Sensitive) {
p.buf.WriteString(" = (sensitive value)")
// Then schema of the attribute itself can be marked sensitive, or the values assigned
sensitive := attrWithNestedS.Sensitive || old.HasMark(marks.Sensitive) || new.HasMark(marks.Sensitive)
if sensitive {
p.buf.WriteString(" = ")
p.buf.WriteString(sensitiveCaption)
if p.pathForcesNewResource(path) {
p.buf.WriteString(p.color.Color(forcesNewResourceCaption))
}
@ -475,6 +484,12 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
p.buf.WriteString(strings.Repeat(" ", indent+2))
p.buf.WriteString("}")
if !new.IsKnown() {
p.buf.WriteString(" -> (known after apply)")
} else if new.IsNull() {
p.buf.WriteString(p.color.Color("[dark_gray] -> null[reset]"))
}
case configschema.NestingList:
p.buf.WriteString(" = [")
if action != plans.NoOp && (p.pathForcesNewResource(path) || p.pathForcesNewResource(path[:len(path)-1])) {
@ -558,6 +573,8 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
if !new.IsKnown() {
p.buf.WriteString(" -> (known after apply)")
} else if new.IsNull() {
p.buf.WriteString(p.color.Color("[dark_gray] -> null[reset]"))
}
case configschema.NestingSet:
@ -636,6 +653,8 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
if !new.IsKnown() {
p.buf.WriteString(" -> (known after apply)")
} else if new.IsNull() {
p.buf.WriteString(p.color.Color("[dark_gray] -> null[reset]"))
}
case configschema.NestingMap:
@ -711,6 +730,8 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff(
p.buf.WriteString("}")
if !new.IsKnown() {
p.buf.WriteString(" -> (known after apply)")
} else if new.IsNull() {
p.buf.WriteString(p.color.Color("[dark_gray] -> null[reset]"))
}
}
}
@ -725,7 +746,7 @@ func (p *blockBodyDiffPrinter) writeNestedBlockDiffs(name string, blockS *config
// If either the old or the new value is marked,
// Display a special diff because it is irrelevant
// to list all obfuscated attributes as (sensitive)
// to list all obfuscated attributes as (sensitive value)
if old.HasMark(marks.Sensitive) || new.HasMark(marks.Sensitive) {
p.writeSensitiveNestedBlockDiff(name, old, new, indent, blankBefore, path)
return 0
@ -1008,7 +1029,7 @@ func (p *blockBodyDiffPrinter) writeNestedBlockDiff(name string, label *string,
func (p *blockBodyDiffPrinter) writeValue(val cty.Value, action plans.Action, indent int) {
// Could check specifically for the sensitivity marker
if val.HasMark(marks.Sensitive) {
p.buf.WriteString("(sensitive)")
p.buf.WriteString(sensitiveCaption)
return
}
@ -1176,7 +1197,7 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa
// values are known and non-null.
if old.IsKnown() && new.IsKnown() && !old.IsNull() && !new.IsNull() && typesEqual {
if old.HasMark(marks.Sensitive) || new.HasMark(marks.Sensitive) {
p.buf.WriteString("(sensitive)")
p.buf.WriteString(sensitiveCaption)
if p.pathForcesNewResource(path) {
p.buf.WriteString(p.color.Color(forcesNewResourceCaption))
}
@ -1547,7 +1568,7 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa
case plans.Create, plans.NoOp:
v := new.Index(kV)
if v.HasMark(marks.Sensitive) {
p.buf.WriteString("(sensitive)")
p.buf.WriteString(sensitiveCaption)
} else {
p.writeValue(v, action, indent+4)
}
@ -1557,7 +1578,7 @@ func (p *blockBodyDiffPrinter) writeValueDiff(old, new cty.Value, indent int, pa
p.writeValueDiff(oldV, newV, indent+4, path)
default:
if oldV.HasMark(marks.Sensitive) || newV.HasMark(marks.Sensitive) {
p.buf.WriteString("(sensitive)")
p.buf.WriteString(sensitiveCaption)
} else {
p.writeValueDiff(oldV, newV, indent+4, path)
}

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ func FormatValue(v cty.Value, indent int) string {
return "(known after apply)"
}
if v.HasMark(marks.Sensitive) {
return "(sensitive)"
return "(sensitive value)"
}
if v.IsNull() {
ty := v.Type()

View File

@ -171,8 +171,8 @@ EOT_`,
`toset([])`,
},
{
cty.StringVal("sensitive value").Mark(marks.Sensitive),
"(sensitive)",
cty.StringVal("a sensitive value").Mark(marks.Sensitive),
"(sensitive value)",
},
}

View File

@ -63,11 +63,11 @@ the `keys()` function will result in a list that is sensitive:
```shell
> local.baz
{
"a" = (sensitive)
"a" = (sensitive value)
"b" = "dog"
}
> keys(local.baz)
(sensitive)
(sensitive value)
```
## When Terraform Calls Functions

View File

@ -292,7 +292,7 @@ Note that unlike `count`, splat expressions are _not_ directly applicable to res
When defining the schema for a resource type, a provider developer can mark
certain attributes as _sensitive_, in which case Terraform will show a
placeholder marker `(sensitive)` instead of the actual value when rendering
placeholder marker `(sensitive value)` instead of the actual value when rendering
a plan involving that attribute.
A provider attribute marked as sensitive behaves similarly to an

View File

@ -91,11 +91,11 @@ the local value `mixed_content`, with a valid JSON string assigned to
```
> var.mixed_content_json
(sensitive)
(sensitive value)
> local.mixed_content
(sensitive)
(sensitive value)
> local.mixed_content["password"]
(sensitive)
(sensitive value)
> nonsensitive(local.mixed_content["username"])
"zqb"
> nonsensitive("clear")

View File

@ -34,9 +34,9 @@ because they may be exposed in other ways outside of Terraform's control.
```
> sensitive(1)
(sensitive)
(sensitive value)
> sensitive("hello")
(sensitive)
(sensitive value)
> sensitive([])
(sensitive)
(sensitive value)
```

View File

@ -159,7 +159,7 @@ Terraform will perform the following actions:
# test_instance.x will be created
+ resource "test_instance" "x" {
+ some_attribute = (sensitive)
+ some_attribute = (sensitive value)
}
Plan: 1 to add, 0 to change, 0 to destroy.

View File

@ -218,8 +218,8 @@ Terraform will perform the following actions:
# some_resource.a will be created
+ resource "some_resource" "a" {
+ name = (sensitive)
+ address = (sensitive)
+ name = (sensitive value)
+ address = (sensitive value)
}
Plan: 1 to add, 0 to change, 0 to destroy.
@ -262,7 +262,7 @@ If a resource attribute is used as, or part of, the provider-defined resource id
+ resource "random_pet" "animal" {
+ id = (known after apply)
+ length = 2
+ prefix = (sensitive)
+ prefix = (sensitive value)
+ separator = "-"
}