diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index e0d6c6af..48db70a4 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -58,7 +58,8 @@ type Attestor struct { Username string `json:"username"` Variables map[string]string `json:"variables,omitempty"` - blockList map[string]struct{} + blockList map[string]struct{} + obfuscateList map[string]struct{} } type Option func(*Attestor) @@ -69,9 +70,18 @@ func WithBlockList(blockList map[string]struct{}) Option { } } +func WithObfuscateList(obfuscateList map[string]struct{}) Option { + return func(a *Attestor) { + for key, value := range obfuscateList { + a.obfuscateList[key] = value + } + } +} + func New(opts ...Option) *Attestor { attestor := &Attestor{ - blockList: DefaultBlockList(), + blockList: DefaultBlockList(), + obfuscateList: DefaultObfuscateList(), } for _, opt := range opts { @@ -113,6 +123,10 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { a.Variables[key] = val }) + ObfuscateEnvironmentArray(a.Variables, a.obfuscateList, func(key, val, _ string) { + a.Variables[key] = val + }) + return nil } diff --git a/attestation/environment/environment_test.go b/attestation/environment/environment_test.go index 8a4eddc8..692b8b5f 100644 --- a/attestation/environment/environment_test.go +++ b/attestation/environment/environment_test.go @@ -39,3 +39,35 @@ func TestEnvironment(t *testing.T) { } } } + +func TestEnvironmentObfuscate(t *testing.T) { + attestor := New() + ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) + require.NoError(t, err) + + obfuscateEnvs := map[string]struct{}{"API_TOKEN": {}, "SECRET_TEXT": {}} + secretVarValue := "secret var" + publicVarValue := "public var" + for k := range obfuscateEnvs { + t.Setenv(k, secretVarValue) + } + + notObfuscateEnvs := map[string]struct{}{"VAR_FOO": {}, "VAR_BAR": {}} + for k := range notObfuscateEnvs { + t.Setenv(k, publicVarValue) + } + + origVars := os.Environ() + require.NoError(t, attestor.Attest(ctx)) + for _, env := range origVars { + origKey, _ := splitVariable(env) + if _, inObfuscateList := obfuscateEnvs[origKey]; inObfuscateList { + require.NotEqual(t, attestor.Variables[origKey], secretVarValue) + require.Equal(t, attestor.Variables[origKey], "******") + } + + if _, inNotObfuscateList := notObfuscateEnvs[origKey]; inNotObfuscateList { + require.Equal(t, attestor.Variables[origKey], publicVarValue) + } + } +} diff --git a/attestation/environment/obfuscate.go b/attestation/environment/obfuscate.go new file mode 100644 index 00000000..5e681438 --- /dev/null +++ b/attestation/environment/obfuscate.go @@ -0,0 +1,66 @@ +// Copyright 2021 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package environment + +import ( + "strings" + + "github.com/gobwas/glob" + "github.com/in-toto/go-witness/log" +) + +// sourced from https://github.com/Puliczek/awesome-list-of-secrets-in-environment-variables/blob/main/raw_list.txt +func DefaultObfuscateList() map[string]struct{} { + return map[string]struct{}{ + "*_TOKEN": {}, + "SECRET_*": {}, + "*_API_KEY": {}, + "*_PASSWORD": {}, + "*_JWT": {}, + } +} + +// FilterEnvironmentArray expects an array of strings representing environment variables. Each element of the array is expected to be in the format of "KEY=VALUE". +// blockList is the list of elements to filter from variables, and for each element of variables that does not appear in the blockList onAllowed will be called. +func ObfuscateEnvironmentArray(variables map[string]string, obfuscateList map[string]struct{}, onAllowed func(key, val, orig string)) { + obfuscateGlobList := []glob.Glob{} + + for k := range obfuscateList { + if strings.Contains(k, "*") { + obfuscateGlobCompiled, err := glob.Compile(k) + if err != nil { + log.Errorf("obfuscate glob pattern could not be interpreted: %w", err) + } + + obfuscateGlobList = append(obfuscateGlobList, obfuscateGlobCompiled) + } + } + + for key, v := range variables { + val := v + + if _, inObfuscateList := obfuscateList[key]; inObfuscateList { + val = "******" + } + + for _, glob := range obfuscateGlobList { + if glob.Match(key) { + val = "******" + } + } + + onAllowed(key, val, v) + } +}