From 9fe70f1f3fab28b4f03a226620ac90667d04c0d5 Mon Sep 17 00:00:00 2001 From: Lucas Bremgartner <lucas@bremis.ch> Date: Sat, 1 Jun 2024 23:38:10 +0200 Subject: [PATCH 1/4] Add "forces replacement" note --- format.go | 30 +++++++++++++++++++++++++ testdata/advanced/output.golden | 6 ++--- testdata/resource_replace/output.golden | 2 +- testdata/sensitive/output.golden | 2 +- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/format.go b/format.go index 3926e29..2da35c6 100644 --- a/format.go +++ b/format.go @@ -89,12 +89,42 @@ func (a *App) diff(change *tfjson.Change) string { panic(err) } + replacePaths := make([]string, 0, len(change.ReplacePaths)) + for _, replacePath := range change.ReplacePaths { + rp := replacePath.([]any) + var path string + for _, pathSegment := range rp { + path += "/" + fmt.Sprint(pathSegment) + } + replacePaths = append(replacePaths, path) + } + buf := &strings.Builder{} formatter := jsondiffprinter.NewTerraformFormatter(buf, jsondiffprinter.WithIndentation(" "), jsondiffprinter.WithHideUnchanged(true), jsondiffprinter.WithJSONinJSONCompare(compare), jsondiffprinter.WithColor(!a.noColor), + jsondiffprinter.WithPatchSeriesPostProcess(func(diff jsondiffprinter.Patch) jsondiffprinter.Patch { + colorize := colorstring.Colorize{ + Colors: colorstring.DefaultColors, + Disable: a.noColor, + } + + outerLoop: + for _, path := range replacePaths { + for i := range diff { + if diff[i].Path.String() == path { + if diff[i].Metadata == nil { + diff[i].Metadata = make(map[string]string, 0) + } + diff[i].Metadata["note"] = colorize.Color(" [light_red]# forces replacement[reset]") + continue outerLoop + } + } + } + return diff + }), ) err = formatter.Format(change.Before, patch) if err != nil { diff --git a/testdata/advanced/output.golden b/testdata/advanced/output.golden index 81d536a..86209d9 100644 --- a/testdata/advanced/output.golden +++ b/testdata/advanced/output.golden @@ -58,14 +58,14 @@ Changes to Resources: - string_removed = "removed" # (4 unchanged attribute hidden) } - ) + ) # forces replacement ~ content_base64sha256 = "nIMhVlzPvgCIzeahBGJ/jEJLuCBuwIqx78vltuKjcyw=" -> "(known after apply)" ~ content_base64sha512 = "WDetH1vI/Yy0tu49ZCyW/WySxstlQc3+T7vX0Ei0UaLvLKsd884Djd3raxFJS66NMgFZc1bpSxPKKDXmgz9drA==" -> "(known after apply)" ~ content_md5 = "6f61fcba1ffd2b366fe358450f93b952" -> "(known after apply)" ~ content_sha1 = "4dfb08a62fbd3d8737cd6a11c2360df3953dda51" -> "(known after apply)" ~ content_sha256 = "9c8321565ccfbe0088cde6a104627f8c424bb8206ec08ab1efcbe5b6e2a3732c" -> "(known after apply)" ~ content_sha512 = "5837ad1f5bc8fd8cb4b6ee3d642c96fd6c92c6cb6541cdfe4fbbd7d048b451a2ef2cab1df3ce038dddeb6b11494bae8d3201597356e94b13ca2835e6833f5dac" -> "(known after apply)" - ~ file_permission = "0777" -> "0660" + ~ file_permission = "0777" -> "0660" # forces replacement ~ id = "4dfb08a62fbd3d8737cd6a11c2360df3953dda51" -> "(known after apply)" # (5 unchanged attribute hidden) } @@ -73,7 +73,7 @@ Changes to Resources: # null_resource.cluster must be replaced -/+ null_resource.cluster = { ~ id = "7713440656663291188" -> "(known after apply)" - triggers = { + triggers = { # forces replacement ~ secret = "secure" -> "still secure" } } diff --git a/testdata/resource_replace/output.golden b/testdata/resource_replace/output.golden index 3a0379a..9e6252a 100644 --- a/testdata/resource_replace/output.golden +++ b/testdata/resource_replace/output.golden @@ -5,7 +5,7 @@ Changes to Resources: # null_resource.cluster must be replaced -/+ null_resource.cluster = { ~ id = "5350362168280616586" -> "(known after apply)" - triggers = { + triggers = { # forces replacement ~ secret = "secure" -> "very very secure" } } diff --git a/testdata/sensitive/output.golden b/testdata/sensitive/output.golden index c72b0a6..dbccaa9 100644 --- a/testdata/sensitive/output.golden +++ b/testdata/sensitive/output.golden @@ -5,7 +5,7 @@ Changes to Resources: # null_resource.sensitive must be replaced -/+ null_resource.sensitive = { ~ id = "4190156157480914441" -> "(known after apply)" - triggers = { + triggers = { # forces replacement ~ secret = "some secret value" -> "new secret value" } } From 0485b3432cbe6c80747913d13936203b61a7dbc8 Mon Sep 17 00:00:00 2001 From: Lucas Bremgartner <lucas@bremis.ch> Date: Tue, 4 Jun 2024 22:10:38 +0200 Subject: [PATCH 2/4] chore: remove unnecessary code --- main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/main.go b/main.go index 3b45234..7c233f2 100644 --- a/main.go +++ b/main.go @@ -29,7 +29,6 @@ Resource actions are indicated with the following symbols: [red]-[reset]/[green]+[reset] destroy and then create replacement [green]+[reset]/[red]-[reset] create replacement and then destroy `) - _ = executionPlanLegend cliapp := &cli.App{ Name: "tfreveal", From a9c9a5002200f3915eee11658dd472790a56176f Mon Sep 17 00:00:00 2001 From: Lucas Bremgartner <lucas@bremis.ch> Date: Tue, 4 Jun 2024 22:12:20 +0200 Subject: [PATCH 3/4] Update README --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 253125e..ca90170 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,30 @@ # tfreveal +[](https://github.com/breml/tfreveal/actions?query=workflow%3AMain) + [](https://goreportcard.com/report/github.com/breml/tfreveal) [](LICENSE) + +tfreveal is an open-source tool designed to enhance the visibility of Terraform +plan files by displaying all differences in resources and outputs, including +sensitive values. Unlike Terraform, which hides sensitive data, tfreveal reveals +these values to ensure complete transparency in your infrastructure changes. + +## Motivation + Terraform does mask sensitive values in the output (e.g. from `terraform plan`) -in order to protect them from being revealed to 3rd parties. +in order to protect them from being revealed to unauthorized 3rd parties. -Sometimes it is neccessary to see the exact changes, Terraform will perform to the -infrastructure including all the changes to sensitive values. So far, Terraform -does not provide a feature to forcefully unmask the sensitive values in the +But sometimes it is neccessary to see the exact changes, Terraform will perform +to the infrastructure including all the changes to sensitive values. In +particular, if one observes drift between the Terraform state and the actual +state of the infrastructure, this becomes inevitable. So far, Terraform does not +provide a feature to forcefully unmask the sensitive values in the [concise diff plan outputs](https://www.hashicorp.com/blog/terraform-0-14-adds-a-new-concise-diff-format-to-terraform-plans). + The general advice given by the Terraform maintainers is to use the JSON output in such cases. While the JSON output does provide all the necessary information, it is not perticularely easy to read for humans and to spot small differences. -It gets even more complicated, if the sensitive values contain larger JSON -encoded values. +It gets even more complicated, if the changes are contained in larger JSON +encoded values, that are marked as sensitive. There exists instructions using for example `jq`, but the process stays manual, cumbersome and error prone. @@ -19,6 +32,10 @@ cumbersome and error prone. `tfreveal` is here to fix this and provide an easy way to show the concise diff plan outputs with all sensitive values revealed. +## Installation + +Download the latest release from the [releases page](https://github.com/breml/tfreveal/releases). + ## Usage The plan file generated from Terraform can be directly piped to `tfreveal`: @@ -36,6 +53,24 @@ $ terraform show -json plan.out > plan.json $ tfreveal plan.json ``` +## Development + +The task to update the test data and the golden files is provided in the +`Taskfile.yml` and can be executed by running `task gen-all`. This requires the +`task` tool to be installed. Please refer to the +[official documentation](https://taskfile.dev/installation/). + +Additionally the `terraform` command needs to be present in the `PATH`. Follow +the [official installation instructions](https://developer.hashicorp.com/terraform/install). + +## Author + +Copyright 2024 by Lucas Bremgartner ([breml](https://github.com/breml)) + +## License + +[MIT License](LICENSE) + ## Trademarks All other trademarks referenced herein are the property of their respective owners. From a48bdb5ca301ed43feeb8344ddcf996ebbec2e60 Mon Sep 17 00:00:00 2001 From: Lucas Bremgartner <lucas@bremis.ch> Date: Fri, 7 Jun 2024 09:12:55 +0200 Subject: [PATCH 4/4] Update dependencies --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 458f0c1..9ee115b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/breml/tfreveal go 1.22.3 require ( - github.com/breml/jsondiffprinter v0.0.7 + github.com/breml/jsondiffprinter v0.0.8 github.com/ghetzel/go-stockutil v1.11.4 github.com/hashicorp/terraform-json v0.22.1 github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db diff --git a/go.sum b/go.sum index 8411e3b..b949170 100644 --- a/go.sum +++ b/go.sum @@ -60,8 +60,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/breml/jsondiffprinter v0.0.7 h1:R2DMEYnyn6p7Y+u8tYiGYxiuETgO6qmG0uGHyWKviaQ= -github.com/breml/jsondiffprinter v0.0.7/go.mod h1:XuyU5sGP+XDNFHnhuyOT67mRBUUHtJ8OmjztxNuXgL8= +github.com/breml/jsondiffprinter v0.0.8 h1:+FE3r92haHtqDSfjq1l8JRAKmEARVEeajD4Ud0YqVGQ= +github.com/breml/jsondiffprinter v0.0.8/go.mod h1:XuyU5sGP+XDNFHnhuyOT67mRBUUHtJ8OmjztxNuXgL8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=