Skip to content

Commit c6c4298

Browse files
committed
don't log terraform environment variables we don't know are safe
Signed-off-by: Spike Curtis <spike@coder.com>
1 parent 9223a77 commit c6c4298

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

provisioner/terraform/provision.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,38 @@ func provisionEnv(start *proto.Provision_Start) ([]string, error) {
181181
return env, nil
182182
}
183183

184+
var (
185+
// tfEnvSafeToPrint is the set of terraform environment variables that we are quite sure won't contain secrets,
186+
// and therefore it's ok to log their values
187+
tfEnvSafeToPrint = map[string]bool{
188+
"TF_LOG": true,
189+
"TF_LOG_PATH": true,
190+
"TF_INPUT": true,
191+
"TF_DATA_DIR": true,
192+
"TF_WORKSPACE": true,
193+
"TF_IN_AUTOMATION": true,
194+
"TF_REGISTRY_DISCOVERY_RETRY": true,
195+
"TF_REGISTRY_CLIENT_TIMEOUT": true,
196+
"TF_CLI_CONFIG_FILE": true,
197+
"TF_IGNORE": true,
198+
}
199+
)
200+
184201
func logTerraformEnvVars(logger provisionersdk.Logger) error {
185202
env := os.Environ()
186203
for _, e := range env {
187204
if strings.HasPrefix(e, "TF_") {
188-
err := logger.Log(&proto.Log{Level: proto.LogLevel_WARN, Output: "terraform environment variable: " + e})
205+
parts := strings.SplitN(e, "=", 2)
206+
if len(parts) != 2 {
207+
panic("os.Environ() returned vars not in key=value form")
208+
}
209+
if !tfEnvSafeToPrint[parts[0]] {
210+
parts[1] = "<value redacted>"
211+
}
212+
err := logger.Log(&proto.Log{
213+
Level: proto.LogLevel_WARN,
214+
Output: fmt.Sprintf("terraform environment variable: %s=%s", parts[0], parts[1]),
215+
})
189216
if err != nil {
190217
return err
191218
}

provisioner/terraform/provision_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"github.com/coder/coder/provisionersdk/proto"
2323
)
2424

25-
func testProvisioner(t *testing.T) (context.Context, proto.DRPCProvisionerClient) {
25+
func setupProvisioner(t *testing.T) (context.Context, proto.DRPCProvisionerClient) {
2626
client, server := provisionersdk.TransportPipe()
2727
ctx, cancelFunc := context.WithCancel(context.Background())
2828
t.Cleanup(func() {
@@ -46,7 +46,7 @@ func testProvisioner(t *testing.T) (context.Context, proto.DRPCProvisionerClient
4646
func TestProvision(t *testing.T) {
4747
t.Parallel()
4848

49-
ctx, api := testProvisioner(t)
49+
ctx, api := setupProvisioner(t)
5050

5151
for _, testCase := range []struct {
5252
Name string
@@ -298,9 +298,11 @@ func TestProvision(t *testing.T) {
298298

299299
// nolint:paralleltest
300300
func TestProvision_ExtraEnv(t *testing.T) {
301+
secretValue := "oinae3uinxase"
301302
t.Setenv("TF_LOG", "INFO")
303+
t.Setenv("TF_SUPERSECRET", secretValue)
302304

303-
ctx, api := testProvisioner(t)
305+
ctx, api := setupProvisioner(t)
304306

305307
directory := t.TempDir()
306308
path := filepath.Join(directory, "main.tf")
@@ -330,6 +332,7 @@ func TestProvision_ExtraEnv(t *testing.T) {
330332
if strings.Contains(log.Output, "TF_LOG") {
331333
found = true
332334
}
335+
require.NotContains(t, log.Output, secretValue)
333336
}
334337
if c := msg.GetComplete(); c != nil {
335338
require.Empty(t, c.Error)

0 commit comments

Comments
 (0)