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{ commands := map[string]string{
"var.foo\n": "\"bar\"\n", "var.foo\n": "\"bar\"\n",
"var.snack\n": "\"popcorn\"\n", "var.snack\n": "\"popcorn\"\n",
"var.secret_snack\n": "(sensitive)\n", "var.secret_snack\n": "(sensitive value)\n",
"local.snack_bar\n": "[\n \"popcorn\",\n (sensitive),\n]\n", "local.snack_bar\n": "[\n \"popcorn\",\n (sensitive value),\n]\n",
} }
args := []string{} args := []string{}

View File

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

View File

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

View File

@ -63,11 +63,11 @@ the `keys()` function will result in a list that is sensitive:
```shell ```shell
> local.baz > local.baz
{ {
"a" = (sensitive) "a" = (sensitive value)
"b" = "dog" "b" = "dog"
} }
> keys(local.baz) > keys(local.baz)
(sensitive) (sensitive value)
``` ```
## When Terraform Calls Functions ## 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 When defining the schema for a resource type, a provider developer can mark
certain attributes as _sensitive_, in which case Terraform will show a 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 plan involving that attribute.
A provider attribute marked as sensitive behaves similarly to an 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 > var.mixed_content_json
(sensitive) (sensitive value)
> local.mixed_content > local.mixed_content
(sensitive) (sensitive value)
> local.mixed_content["password"] > local.mixed_content["password"]
(sensitive) (sensitive value)
> nonsensitive(local.mixed_content["username"]) > nonsensitive(local.mixed_content["username"])
"zqb" "zqb"
> nonsensitive("clear") > nonsensitive("clear")

View File

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

View File

@ -159,7 +159,7 @@ Terraform will perform the following actions:
# test_instance.x will be created # test_instance.x will be created
+ resource "test_instance" "x" { + resource "test_instance" "x" {
+ some_attribute = (sensitive) + some_attribute = (sensitive value)
} }
Plan: 1 to add, 0 to change, 0 to destroy. 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 # some_resource.a will be created
+ resource "some_resource" "a" { + resource "some_resource" "a" {
+ name = (sensitive) + name = (sensitive value)
+ address = (sensitive) + address = (sensitive value)
} }
Plan: 1 to add, 0 to change, 0 to destroy. 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" { + resource "random_pet" "animal" {
+ id = (known after apply) + id = (known after apply)
+ length = 2 + length = 2
+ prefix = (sensitive) + prefix = (sensitive value)
+ separator = "-" + separator = "-"
} }