From 1eff76de4198198aed02ad41ac7b52a4a6ed1f81 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Fri, 20 Sep 2024 13:49:43 +0200 Subject: [PATCH 01/14] chore: New environment variable obfuscation functionality Signed-off-by: Matthias Glastra --- attestation/environment/environment.go | 18 +++++- attestation/environment/environment_test.go | 32 ++++++++++ attestation/environment/obfuscate.go | 66 +++++++++++++++++++++ 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 attestation/environment/obfuscate.go 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) + } +} From 662c6e66e2cee48f5bbcc2f96debf8d2929e7c30 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Wed, 25 Sep 2024 11:45:41 +0200 Subject: [PATCH 02/14] Update attestation/environment/obfuscate.go Co-authored-by: Kairo Araujo Signed-off-by: Matthias Glastra --- attestation/environment/obfuscate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/attestation/environment/obfuscate.go b/attestation/environment/obfuscate.go index 5e681438..6898cb00 100644 --- a/attestation/environment/obfuscate.go +++ b/attestation/environment/obfuscate.go @@ -1,4 +1,4 @@ -// Copyright 2021 The Witness Contributors +// Copyright 2024 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. From c9c477f4cc0df7a8f012d26b6f34d7beb4d98898 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Fri, 27 Sep 2024 10:14:55 +0200 Subject: [PATCH 03/14] feat: Change to default obfuscate and add cli flags. Adding flags to behave blocking or obfuscating and adding new keys. Signed-off-by: Matthias Glastra --- attestation/environment/blocklist.go | 36 +++++- attestation/environment/environment.go | 110 +++++++++++++---- attestation/environment/obfuscate.go | 17 +-- attestation/environment/sensitive_env_vars.go | 112 ++++++++++++++++++ 4 files changed, 239 insertions(+), 36 deletions(-) create mode 100644 attestation/environment/sensitive_env_vars.go diff --git a/attestation/environment/blocklist.go b/attestation/environment/blocklist.go index 0bb20e47..df8a98ce 100644 --- a/attestation/environment/blocklist.go +++ b/attestation/environment/blocklist.go @@ -14,6 +14,13 @@ 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 DefaultBlockList() map[string]struct{} { return map[string]struct{}{ @@ -103,12 +110,37 @@ func DefaultBlockList() map[string]struct{} { // 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 FilterEnvironmentArray(variables []string, blockList map[string]struct{}, onAllowed func(key, val, orig string)) { + filterGlobList := []glob.Glob{} + + for k := range blockList { + if strings.Contains(k, "*") { + filterGlobCompiled, err := glob.Compile(k) + if err != nil { + log.Errorf("obfuscate glob pattern could not be interpreted: %w", err) + } + + filterGlobList = append(filterGlobList, filterGlobCompiled) + } + } + for _, v := range variables { key, val := splitVariable(v) + filterOut := false + if _, inBlockList := blockList[key]; inBlockList { - continue + filterOut = true } - onAllowed(key, val, v) + + for _, glob := range filterGlobList { + if glob.Match(key) { + filterOut = true + break + } + } + + if ! filterOut { + onAllowed(key, val, v) + } } } diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index 48db70a4..be1d5a30 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -15,12 +15,14 @@ package environment import ( + "fmt" "os" "os/user" "runtime" "strings" "github.com/in-toto/go-witness/attestation" + "github.com/in-toto/go-witness/registry" "github.com/invopop/jsonschema" ) @@ -33,8 +35,10 @@ const ( // This is a hacky way to create a compile time error in case the attestor // doesn't implement the expected interfaces. var ( - _ attestation.Attestor = &Attestor{} - _ EnvironmentAttestor = &Attestor{} + _ attestation.Attestor = &Attestor{} + _ EnvironmentAttestor = &Attestor{} + defaultBlockSensitiveVarsEnabled = false + defaultDisableSensitiveVarsDefault = false ) type EnvironmentAttestor interface { @@ -47,9 +51,50 @@ type EnvironmentAttestor interface { } func init() { - attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { - return New() - }) + attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }, + registry.BoolConfigOption( + "block-sensitive-vars", + "Switch from obfuscate to blocking variables which removes them from the output completely.", + defaultBlockSensitiveVarsEnabled, + func(a attestation.Attestor, blockSensitiveVarsEnabled bool) (attestation.Attestor, error) { + envAttestor, ok := a.(*Attestor) + if !ok { + return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + } + + WithBlockVarsEnabled(blockSensitiveVarsEnabled)(envAttestor) + return envAttestor, nil + }, + ), + registry.BoolConfigOption( + "disable-default-sensitive-vars", + "Disable the default list of sensitive vars and only use the items mentioned by --attestor-environment-sensitive-key.", + defaultDisableSensitiveVarsDefault, + func(a attestation.Attestor, disableSensitiveVarsDefault bool) (attestation.Attestor, error) { + envAttestor, ok := a.(*Attestor) + if !ok { + return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + } + + WithDisableDefaultSensitiveList(disableSensitiveVarsDefault)(envAttestor) + return envAttestor, nil + }, + ), + registry.StringSliceConfigOption( + "sensitive-key", + "Add keys to the list of sensitive environment keys.", + []string{}, + func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { + envAttestor, ok := a.(*Attestor) + if !ok { + return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + } + + WithAdditionalKeys(additionalKeys)(envAttestor) + return envAttestor, nil + }, + ), + ) } type Attestor struct { @@ -58,30 +103,42 @@ type Attestor struct { Username string `json:"username"` Variables map[string]string `json:"variables,omitempty"` - blockList map[string]struct{} - obfuscateList map[string]struct{} + sensitiveVarsList map[string]struct{} + addSensitiveVarsList map[string]struct{} + blockVarsEnabled bool + disableSensitiveVarsDefault bool } type Option func(*Attestor) -func WithBlockList(blockList map[string]struct{}) Option { +// WithBlockVarsEnabled will make the blocking (removing) of vars the acting behavior. +// The default behavior is obfuscation of variables. +func WithBlockVarsEnabled(blockVarsEnabled bool) Option { return func(a *Attestor) { - a.blockList = blockList + a.blockVarsEnabled = blockVarsEnabled } } -func WithObfuscateList(obfuscateList map[string]struct{}) Option { +// WithAdditionalKeys add additional keys to final list that is checked for sensitive variables. +func WithAdditionalKeys(additionalKeys []string) Option { return func(a *Attestor) { - for key, value := range obfuscateList { - a.obfuscateList[key] = value + for _, value := range additionalKeys { + a.addSensitiveVarsList[value] = struct{}{} } } } +// WithDisableDefaultSensitiveList will disable the default list and only use the additional keys. +func WithDisableDefaultSensitiveList(disableSensitiveVarsDefault bool) Option { + return func(a *Attestor) { + a.disableSensitiveVarsDefault = disableSensitiveVarsDefault + } +} + func New(opts ...Option) *Attestor { attestor := &Attestor{ - blockList: DefaultBlockList(), - obfuscateList: DefaultObfuscateList(), + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, } for _, opt := range opts { @@ -119,13 +176,26 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { a.Username = user.Username } - FilterEnvironmentArray(os.Environ(), a.blockList, func(key, val, _ string) { - a.Variables[key] = val - }) + // Prepare sensitive keys list. + var finalSensitiveKeysList map[string]struct{} + if a.disableSensitiveVarsDefault { + a.sensitiveVarsList = map[string]struct{}{} + } + finalSensitiveKeysList = a.sensitiveVarsList + for k, v := range a.addSensitiveVarsList { + finalSensitiveKeysList[k] = v + } - ObfuscateEnvironmentArray(a.Variables, a.obfuscateList, func(key, val, _ string) { - a.Variables[key] = val - }) + // Block or obfuscate + if a.blockVarsEnabled { + FilterEnvironmentArray(os.Environ(), finalSensitiveKeysList, func(key, val, _ string) { + a.Variables[key] = val + }) + } else { + ObfuscateEnvironmentArray(os.Environ(), finalSensitiveKeysList, func(key, val, _ string) { + a.Variables[key] = val + }) + } return nil } diff --git a/attestation/environment/obfuscate.go b/attestation/environment/obfuscate.go index 6898cb00..e010431c 100644 --- a/attestation/environment/obfuscate.go +++ b/attestation/environment/obfuscate.go @@ -21,20 +21,9 @@ import ( "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)) { +func ObfuscateEnvironmentArray(variables []string, obfuscateList map[string]struct{}, onAllowed func(key, val, orig string)) { obfuscateGlobList := []glob.Glob{} for k := range obfuscateList { @@ -48,8 +37,8 @@ func ObfuscateEnvironmentArray(variables map[string]string, obfuscateList map[st } } - for key, v := range variables { - val := v + for _, v := range variables { + key, val := splitVariable(v) if _, inObfuscateList := obfuscateList[key]; inObfuscateList { val = "******" diff --git a/attestation/environment/sensitive_env_vars.go b/attestation/environment/sensitive_env_vars.go new file mode 100644 index 00000000..df816b10 --- /dev/null +++ b/attestation/environment/sensitive_env_vars.go @@ -0,0 +1,112 @@ +// Copyright 2024 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 + +// DefaultSensitiveEnvList return a list of known sensitive environment keys. +// +// Eplicit list sourced from https://github.com/Puliczek/awesome-list-of-secrets-in-environment-variables/blob/main/raw_list.txt +func DefaultSensitiveEnvList() map[string]struct{} { + return map[string]struct{}{ + + // Glob pattern list + "*_TOKEN": {}, + "SECRET_*": {}, + "*_API_KEY": {}, + "*_PASSWORD": {}, + "*_JWT": {}, + + // Explicit list + "AWS_ACCESS_KEY_ID": {}, + "AWS_SECRET_ACCESS_KEY": {}, + "AMAZON_AWS_ACCESS_KEY_ID": {}, + "AMAZON_AWS_SECRET_ACCESS_KEY": {}, + "ALGOLIA_API_KEY": {}, + "AZURE_CLIENT_ID": {}, + "AZURE_CLIENT_SECRET": {}, + "AZURE_USERNAME": {}, + "AZURE_PASSWORD": {}, + "MSI_ENDPOINT": {}, + "MSI_SECRET": {}, + "binance_api": {}, + "binance_secret": {}, + "BITTREX_API_KEY": {}, + "BITTREX_API_SECRET": {}, + "CF_PASSWORD": {}, + "CF_USERNAME": {}, + "CODECLIMATE_REPO_TOKEN": {}, + "COVERALLS_REPO_TOKEN": {}, + "CIRCLE_TOKEN": {}, + "DIGITALOCEAN_ACCESS_TOKEN": {}, + "DOCKER_EMAIL": {}, + "DOCKER_PASSWORD": {}, + "DOCKER_USERNAME": {}, + "DOCKERHUB_PASSWORD": {}, + "FACEBOOK_APP_ID": {}, + "FACEBOOK_APP_SECRET": {}, + "FACEBOOK_ACCESS_TOKEN": {}, + "FIREBASE_TOKEN": {}, + "FOSSA_API_KEY": {}, + "GH_TOKEN": {}, + "GH_ENTERPRISE_TOKEN": {}, + "GOOGLE_APPLICATION_CREDENTIALS": {}, + "GOOGLE_API_KEY": {}, + "CI_DEPLOY_USER": {}, + "CI_DEPLOY_PASSWORD": {}, + "GITLAB_USER_LOGIN": {}, + "CI_JOB_JWT": {}, + "CI_JOB_JWT_V2": {}, + "CI_JOB_TOKEN": {}, + "HEROKU_API_KEY": {}, + "HEROKU_API_USER": {}, + "MAILGUN_API_KEY": {}, + "MCLI_PRIVATE_API_KEY": {}, + "MCLI_PUBLIC_API_KEY": {}, + "NGROK_TOKEN": {}, + "NGROK_AUTH_TOKEN": {}, + "NPM_AUTH_TOKEN": {}, + "OKTA_CLIENT_ORGURL": {}, + "OKTA_CLIENT_TOKEN": {}, + "OKTA_OAUTH2_CLIENTSECRET": {}, + "OKTA_OAUTH2_CLIENTID": {}, + "OKTA_AUTHN_GROUPID": {}, + "OS_USERNAME": {}, + "OS_PASSWORD": {}, + "PERCY_TOKEN": {}, + "SAUCE_ACCESS_KEY": {}, + "SAUCE_USERNAME": {}, + "SENTRY_AUTH_TOKEN": {}, + "SLACK_TOKEN": {}, + "SNYK_TOKEN": {}, + "square_access_token": {}, + "square_oauth_secret": {}, + "STRIPE_API_KEY": {}, + "STRIPE_DEVICE_NAME": {}, + "SURGE_TOKEN": {}, + "SURGE_LOGIN": {}, + "TWILIO_ACCOUNT_SID": {}, + "CONSUMER_KEY": {}, + "CONSUMER_SECRET": {}, + "TRAVIS_SUDO": {}, + "TRAVIS_OS_NAME": {}, + "TRAVIS_SECURE_ENV_VARS": {}, + "VAULT_TOKEN": {}, + "VAULT_CLIENT_KEY": {}, + "TOKEN": {}, + "VULTR_ACCESS": {}, + "VULTR_SECRET": {}, + "ACTIONS_RUNTIME_TOKEN": {}, + "ACTIONS_ID_TOKEN_REQUEST_TOKEN": {}, + } +} From 90836fbadfef3f16568fbd0030681ee21a67eb42 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Mon, 30 Sep 2024 10:27:15 +0200 Subject: [PATCH 04/14] chore: Adjust naming to filter envs. Fix tests. Signed-off-by: Matthias Glastra --- attestation/environment/environment.go | 26 +++---- attestation/environment/environment_test.go | 74 ++++++++++++++++++- .../environment/{blocklist.go => filter.go} | 5 +- attestation/environment/sensitive_env_vars.go | 10 +-- 4 files changed, 91 insertions(+), 24 deletions(-) rename attestation/environment/{blocklist.go => filter.go} (99%) diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index be1d5a30..2448b531 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -37,7 +37,7 @@ const ( var ( _ attestation.Attestor = &Attestor{} _ EnvironmentAttestor = &Attestor{} - defaultBlockSensitiveVarsEnabled = false + defaultFilterSensitiveVarsEnabled = false defaultDisableSensitiveVarsDefault = false ) @@ -53,16 +53,16 @@ type EnvironmentAttestor interface { func init() { attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }, registry.BoolConfigOption( - "block-sensitive-vars", - "Switch from obfuscate to blocking variables which removes them from the output completely.", - defaultBlockSensitiveVarsEnabled, - func(a attestation.Attestor, blockSensitiveVarsEnabled bool) (attestation.Attestor, error) { + "filter-sensitive-vars", + "Switch from obfuscate to filtering variables which removes them from the output completely.", + defaultFilterSensitiveVarsEnabled, + func(a attestation.Attestor, filterSensitiveVarsEnabled bool) (attestation.Attestor, error) { envAttestor, ok := a.(*Attestor) if !ok { return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) } - WithBlockVarsEnabled(blockSensitiveVarsEnabled)(envAttestor) + WithFilterVarsEnabled(filterSensitiveVarsEnabled)(envAttestor) return envAttestor, nil }, ), @@ -105,17 +105,17 @@ type Attestor struct { sensitiveVarsList map[string]struct{} addSensitiveVarsList map[string]struct{} - blockVarsEnabled bool + filterVarsEnabled bool disableSensitiveVarsDefault bool } type Option func(*Attestor) -// WithBlockVarsEnabled will make the blocking (removing) of vars the acting behavior. +// WithFilterVarsEnabled will make the filter (removing) of vars the acting behavior. // The default behavior is obfuscation of variables. -func WithBlockVarsEnabled(blockVarsEnabled bool) Option { +func WithFilterVarsEnabled(filterVarsEnabled bool) Option { return func(a *Attestor) { - a.blockVarsEnabled = blockVarsEnabled + a.filterVarsEnabled = filterVarsEnabled } } @@ -137,7 +137,7 @@ func WithDisableDefaultSensitiveList(disableSensitiveVarsDefault bool) Option { func New(opts ...Option) *Attestor { attestor := &Attestor{ - sensitiveVarsList: DefaultSensitiveEnvList(), + sensitiveVarsList: DefaultSensitiveEnvList(), addSensitiveVarsList: map[string]struct{}{}, } @@ -186,8 +186,8 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { finalSensitiveKeysList[k] = v } - // Block or obfuscate - if a.blockVarsEnabled { + // Filter or obfuscate + if a.filterVarsEnabled { FilterEnvironmentArray(os.Environ(), finalSensitiveKeysList, func(key, val, _ string) { a.Variables[key] = val }) diff --git a/attestation/environment/environment_test.go b/attestation/environment/environment_test.go index 692b8b5f..dd1f4336 100644 --- a/attestation/environment/environment_test.go +++ b/attestation/environment/environment_test.go @@ -22,8 +22,10 @@ import ( "github.com/stretchr/testify/require" ) -func TestEnvironment(t *testing.T) { - attestor := New() +// TestFilterVarsEnvironment tests if enabling filter behavior works correctly. +func TestFilterVarsEnvironment(t *testing.T) { + + attestor := New(WithFilterVarsEnabled(true)) ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) require.NoError(t, err) @@ -32,7 +34,7 @@ func TestEnvironment(t *testing.T) { require.NoError(t, attestor.Attest(ctx)) for _, env := range origVars { origKey, _ := splitVariable(env) - if _, inBlockList := attestor.blockList[origKey]; inBlockList { + if _, inBlockList := attestor.sensitiveVarsList[origKey]; inBlockList { require.NotContains(t, attestor.Variables, origKey) } else { require.Contains(t, attestor.Variables, origKey) @@ -40,6 +42,7 @@ func TestEnvironment(t *testing.T) { } } +// TestEnvironmentObfuscate tests if obfuscate normal behavior works correctly. func TestEnvironmentObfuscate(t *testing.T) { attestor := New() ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) @@ -71,3 +74,68 @@ func TestEnvironmentObfuscate(t *testing.T) { } } } + +// TestEnvironmentObfuscateAdditional tests if the default obfuscate with additional keys works correctly. +func TestEnvironmentObfuscateAdditional(t *testing.T) { + attestor := New(WithAdditionalKeys([]string{"MYNAME"})) + ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) + require.NoError(t, err) + + obfuscateEnvs := map[string]struct{}{"API_TOKEN": {}, "MYNAME": {}} + 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) + } + } +} + +// TestEnvironmentFilterAdditional tests if enabling filter and adding additional keys works correctly. +func TestEnvironmentFilterAdditional(t *testing.T) { + attestor := New(WithFilterVarsEnabled(true), WithAdditionalKeys([]string{"MYNAME"})) + ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) + require.NoError(t, err) + + filterEnvs := map[string]struct{}{"API_TOKEN": {}, "MYNAME": {}} + secretVarValue := "secret var" + publicVarValue := "public var" + for k := range filterEnvs { + t.Setenv(k, secretVarValue) + } + + notFilterEnvs := map[string]struct{}{"VAR_FOO": {}, "VAR_BAR": {}} + for k := range notFilterEnvs { + t.Setenv(k, publicVarValue) + } + + origVars := os.Environ() + require.NoError(t, attestor.Attest(ctx)) + for _, env := range origVars { + origKey, _ := splitVariable(env) + if _, inFilterList := filterEnvs[origKey]; inFilterList { + require.NotContains(t, attestor.Variables, origKey) + } + + if _, inNotObfuscateList := notFilterEnvs[origKey]; inNotObfuscateList { + require.Equal(t, attestor.Variables[origKey], publicVarValue) + } + } +} diff --git a/attestation/environment/blocklist.go b/attestation/environment/filter.go similarity index 99% rename from attestation/environment/blocklist.go rename to attestation/environment/filter.go index df8a98ce..349cf5de 100644 --- a/attestation/environment/blocklist.go +++ b/attestation/environment/filter.go @@ -111,7 +111,7 @@ func DefaultBlockList() map[string]struct{} { // 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 FilterEnvironmentArray(variables []string, blockList map[string]struct{}, onAllowed func(key, val, orig string)) { filterGlobList := []glob.Glob{} - + for k := range blockList { if strings.Contains(k, "*") { filterGlobCompiled, err := glob.Compile(k) @@ -131,7 +131,6 @@ func FilterEnvironmentArray(variables []string, blockList map[string]struct{}, o filterOut = true } - for _, glob := range filterGlobList { if glob.Match(key) { filterOut = true @@ -139,7 +138,7 @@ func FilterEnvironmentArray(variables []string, blockList map[string]struct{}, o } } - if ! filterOut { + if !filterOut { onAllowed(key, val, v) } } diff --git a/attestation/environment/sensitive_env_vars.go b/attestation/environment/sensitive_env_vars.go index df816b10..50f6dd61 100644 --- a/attestation/environment/sensitive_env_vars.go +++ b/attestation/environment/sensitive_env_vars.go @@ -21,11 +21,11 @@ func DefaultSensitiveEnvList() map[string]struct{} { return map[string]struct{}{ // Glob pattern list - "*_TOKEN": {}, - "SECRET_*": {}, - "*_API_KEY": {}, - "*_PASSWORD": {}, - "*_JWT": {}, + "*_TOKEN": {}, + "SECRET_*": {}, + "*_API_KEY": {}, + "*_PASSWORD": {}, + "*_JWT": {}, // Explicit list "AWS_ACCESS_KEY_ID": {}, From 15ab22d81a48178994ba3c68741b93db312dec6f Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Mon, 30 Sep 2024 14:27:42 +0200 Subject: [PATCH 05/14] chore: Making the environment test cases more robust. Signed-off-by: Matthias Glastra --- attestation/environment/environment.go | 26 ++++++++---- attestation/environment/environment_test.go | 45 +++++++++++++++++++-- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index 2448b531..ede7efcb 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -62,7 +62,7 @@ func init() { return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) } - WithFilterVarsEnabled(filterSensitiveVarsEnabled)(envAttestor) + WithFilterVarsEnabled()(envAttestor) return envAttestor, nil }, ), @@ -76,7 +76,7 @@ func init() { return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) } - WithDisableDefaultSensitiveList(disableSensitiveVarsDefault)(envAttestor) + WithDisableDefaultSensitiveList()(envAttestor) return envAttestor, nil }, ), @@ -103,6 +103,7 @@ type Attestor struct { Username string `json:"username"` Variables map[string]string `json:"variables,omitempty"` + osEnviron func() []string sensitiveVarsList map[string]struct{} addSensitiveVarsList map[string]struct{} filterVarsEnabled bool @@ -113,9 +114,9 @@ type Option func(*Attestor) // WithFilterVarsEnabled will make the filter (removing) of vars the acting behavior. // The default behavior is obfuscation of variables. -func WithFilterVarsEnabled(filterVarsEnabled bool) Option { +func WithFilterVarsEnabled() Option { return func(a *Attestor) { - a.filterVarsEnabled = filterVarsEnabled + a.filterVarsEnabled = true } } @@ -129,9 +130,16 @@ func WithAdditionalKeys(additionalKeys []string) Option { } // WithDisableDefaultSensitiveList will disable the default list and only use the additional keys. -func WithDisableDefaultSensitiveList(disableSensitiveVarsDefault bool) Option { +func WithDisableDefaultSensitiveList() Option { return func(a *Attestor) { - a.disableSensitiveVarsDefault = disableSensitiveVarsDefault + a.disableSensitiveVarsDefault = true + } +} + +// WithCustomEnv will override the default os.Environ() method. This could be used to mock. +func WithCustomEnv(osEnviron func() []string) Option { + return func(a *Attestor) { + a.osEnviron = osEnviron } } @@ -141,6 +149,8 @@ func New(opts ...Option) *Attestor { addSensitiveVarsList: map[string]struct{}{}, } + attestor.osEnviron = os.Environ + for _, opt := range opts { opt(attestor) } @@ -188,11 +198,11 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { // Filter or obfuscate if a.filterVarsEnabled { - FilterEnvironmentArray(os.Environ(), finalSensitiveKeysList, func(key, val, _ string) { + FilterEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, func(key, val, _ string) { a.Variables[key] = val }) } else { - ObfuscateEnvironmentArray(os.Environ(), finalSensitiveKeysList, func(key, val, _ string) { + ObfuscateEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, func(key, val, _ string) { a.Variables[key] = val }) } diff --git a/attestation/environment/environment_test.go b/attestation/environment/environment_test.go index dd1f4336..f1288f5a 100644 --- a/attestation/environment/environment_test.go +++ b/attestation/environment/environment_test.go @@ -25,12 +25,16 @@ import ( // TestFilterVarsEnvironment tests if enabling filter behavior works correctly. func TestFilterVarsEnvironment(t *testing.T) { - attestor := New(WithFilterVarsEnabled(true)) + customEnv := func() []string { + return []string{"AWS_ACCESS_KEY_ID=super secret"} + } + + attestor := New(WithFilterVarsEnabled(), WithCustomEnv(customEnv)) + ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) require.NoError(t, err) - t.Setenv("AWS_ACCESS_KEY_ID", "super secret") - origVars := os.Environ() + origVars := customEnv() require.NoError(t, attestor.Attest(ctx)) for _, env := range origVars { origKey, _ := splitVariable(env) @@ -108,9 +112,42 @@ func TestEnvironmentObfuscateAdditional(t *testing.T) { } } +// TestEnvironmentCustomKeysAdditional tests if the default list is disabled the additional keys works correctly. +func TestEnvironmentCustomKeysAdditional(t *testing.T) { + attestor := New(WithDisableDefaultSensitiveList(), WithAdditionalKeys([]string{"MYNAME"})) + ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) + require.NoError(t, err) + + obfuscateEnvs := map[string]struct{}{"MYNAME": {}} + secretVarValue := "secret var" + publicVarValue := "public var" + for k := range obfuscateEnvs { + t.Setenv(k, secretVarValue) + } + + notObfuscateEnvs := map[string]struct{}{"API_TOKEN": {}} + 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) + } + } +} + // TestEnvironmentFilterAdditional tests if enabling filter and adding additional keys works correctly. func TestEnvironmentFilterAdditional(t *testing.T) { - attestor := New(WithFilterVarsEnabled(true), WithAdditionalKeys([]string{"MYNAME"})) + attestor := New(WithFilterVarsEnabled(), WithAdditionalKeys([]string{"MYNAME"})) ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) require.NoError(t, err) From ff6f17f634093b0d1877204b4bd287c6bddcc20d Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Wed, 2 Oct 2024 12:31:08 +0200 Subject: [PATCH 06/14] feat: Add exclude-sensitive-key flag. Signed-off-by: Matthias Glastra --- attestation/environment/environment.go | 37 +++++-- attestation/environment/environment_test.go | 32 +++++- attestation/environment/filter.go | 104 ++------------------ attestation/environment/obfuscate.go | 16 +-- 4 files changed, 81 insertions(+), 108 deletions(-) diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index ede7efcb..f0dd1b09 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -81,8 +81,8 @@ func init() { }, ), registry.StringSliceConfigOption( - "sensitive-key", - "Add keys to the list of sensitive environment keys.", + "add-sensitive-key", + "Add keys or globs (e.g. '*TEXT') to the list of sensitive environment keys.", []string{}, func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { envAttestor, ok := a.(*Attestor) @@ -94,6 +94,20 @@ func init() { return envAttestor, nil }, ), + registry.StringSliceConfigOption( + "exclude-sensitive-key", + "Exclude specific keys from the list of sensitive environment keys. Note: This does not support globs.", + []string{}, + func(a attestation.Attestor, excludeKeys []string) (attestation.Attestor, error) { + envAttestor, ok := a.(*Attestor) + if !ok { + return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + } + + WithExcludeKeys(excludeKeys)(envAttestor) + return envAttestor, nil + }, + ), ) } @@ -106,6 +120,7 @@ type Attestor struct { osEnviron func() []string sensitiveVarsList map[string]struct{} addSensitiveVarsList map[string]struct{} + excludeSensitiveVarsList map[string]struct{} filterVarsEnabled bool disableSensitiveVarsDefault bool } @@ -129,6 +144,15 @@ func WithAdditionalKeys(additionalKeys []string) Option { } } +// WithExcludeKeys add additional keys to final list that is checked for sensitive variables. +func WithExcludeKeys(excludeKeys []string) Option { + return func(a *Attestor) { + for _, value := range excludeKeys { + a.excludeSensitiveVarsList[value] = struct{}{} + } + } +} + // WithDisableDefaultSensitiveList will disable the default list and only use the additional keys. func WithDisableDefaultSensitiveList() Option { return func(a *Attestor) { @@ -145,8 +169,9 @@ func WithCustomEnv(osEnviron func() []string) Option { func New(opts ...Option) *Attestor { attestor := &Attestor{ - sensitiveVarsList: DefaultSensitiveEnvList(), - addSensitiveVarsList: map[string]struct{}{}, + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, } attestor.osEnviron = os.Environ @@ -198,11 +223,11 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { // Filter or obfuscate if a.filterVarsEnabled { - FilterEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, func(key, val, _ string) { + FilterEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, a.excludeSensitiveVarsList, func(key, val, _ string) { a.Variables[key] = val }) } else { - ObfuscateEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, func(key, val, _ string) { + ObfuscateEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, a.excludeSensitiveVarsList, func(key, val, _ string) { a.Variables[key] = val }) } diff --git a/attestation/environment/environment_test.go b/attestation/environment/environment_test.go index f1288f5a..e8e0a7c8 100644 --- a/attestation/environment/environment_test.go +++ b/attestation/environment/environment_test.go @@ -29,7 +29,10 @@ func TestFilterVarsEnvironment(t *testing.T) { return []string{"AWS_ACCESS_KEY_ID=super secret"} } - attestor := New(WithFilterVarsEnabled(), WithCustomEnv(customEnv)) + attestor := New( + WithFilterVarsEnabled(), + WithCustomEnv(customEnv), + ) ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) require.NoError(t, err) @@ -46,6 +49,33 @@ func TestFilterVarsEnvironment(t *testing.T) { } } +// TestExcludeVarsEnvironment tests if enabling filter behavior works correctly. +func TestExcludeVarsEnvironment(t *testing.T) { + + customEnv := func() []string { + return []string{"AWS_ACCESS_KEY_ID=super secret"} + } + + attestor := New( + WithExcludeKeys([]string{"AWS_ACCESS_KEY_ID"}), + WithCustomEnv(customEnv), + ) + + ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) + require.NoError(t, err) + + origVars := customEnv() + require.NoError(t, attestor.Attest(ctx)) + for _, env := range origVars { + origKey, _ := splitVariable(env) + if _, inList := attestor.excludeSensitiveVarsList[origKey]; inList { + require.Contains(t, attestor.Variables, origKey) + } else { + require.NotContains(t, attestor.Variables, origKey) + } + } +} + // TestEnvironmentObfuscate tests if obfuscate normal behavior works correctly. func TestEnvironmentObfuscate(t *testing.T) { attestor := New() diff --git a/attestation/environment/filter.go b/attestation/environment/filter.go index 349cf5de..46e09cf0 100644 --- a/attestation/environment/filter.go +++ b/attestation/environment/filter.go @@ -21,95 +21,9 @@ import ( "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 DefaultBlockList() map[string]struct{} { - return map[string]struct{}{ - "AWS_ACCESS_KEY_ID": {}, - "AWS_SECRET_ACCESS_KEY": {}, - "AMAZON_AWS_ACCESS_KEY_ID": {}, - "AMAZON_AWS_SECRET_ACCESS_KEY": {}, - "ALGOLIA_API_KEY": {}, - "AZURE_CLIENT_ID": {}, - "AZURE_CLIENT_SECRET": {}, - "AZURE_USERNAME": {}, - "AZURE_PASSWORD": {}, - "MSI_ENDPOINT": {}, - "MSI_SECRET": {}, - "binance_api": {}, - "binance_secret": {}, - "BITTREX_API_KEY": {}, - "BITTREX_API_SECRET": {}, - "CF_PASSWORD": {}, - "CF_USERNAME": {}, - "CODECLIMATE_REPO_TOKEN": {}, - "COVERALLS_REPO_TOKEN": {}, - "CIRCLE_TOKEN": {}, - "DIGITALOCEAN_ACCESS_TOKEN": {}, - "DOCKER_EMAIL": {}, - "DOCKER_PASSWORD": {}, - "DOCKER_USERNAME": {}, - "DOCKERHUB_PASSWORD": {}, - "FACEBOOK_APP_ID": {}, - "FACEBOOK_APP_SECRET": {}, - "FACEBOOK_ACCESS_TOKEN": {}, - "FIREBASE_TOKEN": {}, - "FOSSA_API_KEY": {}, - "GH_TOKEN": {}, - "GH_ENTERPRISE_TOKEN": {}, - "GOOGLE_APPLICATION_CREDENTIALS": {}, - "GOOGLE_API_KEY": {}, - "CI_DEPLOY_USER": {}, - "CI_DEPLOY_PASSWORD": {}, - "GITLAB_USER_LOGIN": {}, - "CI_JOB_JWT": {}, - "CI_JOB_JWT_V2": {}, - "CI_JOB_TOKEN": {}, - "HEROKU_API_KEY": {}, - "HEROKU_API_USER": {}, - "MAILGUN_API_KEY": {}, - "MCLI_PRIVATE_API_KEY": {}, - "MCLI_PUBLIC_API_KEY": {}, - "NGROK_TOKEN": {}, - "NGROK_AUTH_TOKEN": {}, - "NPM_AUTH_TOKEN": {}, - "OKTA_CLIENT_ORGURL": {}, - "OKTA_CLIENT_TOKEN": {}, - "OKTA_OAUTH2_CLIENTSECRET": {}, - "OKTA_OAUTH2_CLIENTID": {}, - "OKTA_AUTHN_GROUPID": {}, - "OS_USERNAME": {}, - "OS_PASSWORD": {}, - "PERCY_TOKEN": {}, - "SAUCE_ACCESS_KEY": {}, - "SAUCE_USERNAME": {}, - "SENTRY_AUTH_TOKEN": {}, - "SLACK_TOKEN": {}, - "SNYK_TOKEN": {}, - "square_access_token": {}, - "square_oauth_secret": {}, - "STRIPE_API_KEY": {}, - "STRIPE_DEVICE_NAME": {}, - "SURGE_TOKEN": {}, - "SURGE_LOGIN": {}, - "TWILIO_ACCOUNT_SID": {}, - "CONSUMER_KEY": {}, - "CONSUMER_SECRET": {}, - "TRAVIS_SUDO": {}, - "TRAVIS_OS_NAME": {}, - "TRAVIS_SECURE_ENV_VARS": {}, - "VAULT_TOKEN": {}, - "VAULT_CLIENT_KEY": {}, - "TOKEN": {}, - "VULTR_ACCESS": {}, - "VULTR_SECRET": {}, - "ACTIONS_RUNTIME_TOKEN": {}, - "ACTIONS_ID_TOKEN_REQUEST_TOKEN": {}, - } -} - // 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 FilterEnvironmentArray(variables []string, blockList map[string]struct{}, onAllowed func(key, val, orig string)) { +func FilterEnvironmentArray(variables []string, blockList map[string]struct{}, excludeKeys map[string]struct{}, onAllowed func(key, val, orig string)) { filterGlobList := []glob.Glob{} for k := range blockList { @@ -127,14 +41,16 @@ func FilterEnvironmentArray(variables []string, blockList map[string]struct{}, o key, val := splitVariable(v) filterOut := false - if _, inBlockList := blockList[key]; inBlockList { - filterOut = true - } - - for _, glob := range filterGlobList { - if glob.Match(key) { + if _, inExcludKeys := excludeKeys[key]; !inExcludKeys { + if _, inBlockList := blockList[key]; inBlockList { filterOut = true - break + } + + for _, glob := range filterGlobList { + if glob.Match(key) { + filterOut = true + break + } } } diff --git a/attestation/environment/obfuscate.go b/attestation/environment/obfuscate.go index e010431c..978b69d1 100644 --- a/attestation/environment/obfuscate.go +++ b/attestation/environment/obfuscate.go @@ -23,7 +23,7 @@ import ( // 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 []string, obfuscateList map[string]struct{}, onAllowed func(key, val, orig string)) { +func ObfuscateEnvironmentArray(variables []string, obfuscateList map[string]struct{}, excludeKeys map[string]struct{}, onAllowed func(key, val, orig string)) { obfuscateGlobList := []glob.Glob{} for k := range obfuscateList { @@ -40,14 +40,16 @@ func ObfuscateEnvironmentArray(variables []string, obfuscateList map[string]stru for _, v := range variables { key, val := splitVariable(v) - if _, inObfuscateList := obfuscateList[key]; inObfuscateList { - val = "******" - } - - for _, glob := range obfuscateGlobList { - if glob.Match(key) { + if _, inExcludKeys := excludeKeys[key]; !inExcludKeys { + if _, inObfuscateList := obfuscateList[key]; inObfuscateList { val = "******" } + + for _, glob := range obfuscateGlobList { + if glob.Match(key) { + val = "******" + } + } } onAllowed(key, val, v) From eca8f62169b9362c8729514ced27536d26da4753 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Wed, 2 Oct 2024 14:11:27 +0200 Subject: [PATCH 07/14] Update attestation/environment/sensitive_env_vars.go Co-authored-by: Kairo Araujo Signed-off-by: Matthias Glastra --- attestation/environment/sensitive_env_vars.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/attestation/environment/sensitive_env_vars.go b/attestation/environment/sensitive_env_vars.go index 50f6dd61..64f1ba24 100644 --- a/attestation/environment/sensitive_env_vars.go +++ b/attestation/environment/sensitive_env_vars.go @@ -21,11 +21,11 @@ func DefaultSensitiveEnvList() map[string]struct{} { return map[string]struct{}{ // Glob pattern list - "*_TOKEN": {}, - "SECRET_*": {}, - "*_API_KEY": {}, - "*_PASSWORD": {}, - "*_JWT": {}, + "*TOKEN*": {}, + "*SECRET*": {}, + "*API_KEY*": {}, + "*PASSWORD*": {}, + "*JWT*": {}, // Explicit list "AWS_ACCESS_KEY_ID": {}, From 51df1d2fcd0b47ce03325d643c772bcf3886c6ea Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Wed, 2 Oct 2024 14:21:11 +0200 Subject: [PATCH 08/14] chore: Fix tests and command run. Signed-off-by: Matthias Glastra --- attestation/commandrun/commandrun.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/attestation/commandrun/commandrun.go b/attestation/commandrun/commandrun.go index 431d9ca7..9b58a340 100644 --- a/attestation/commandrun/commandrun.go +++ b/attestation/commandrun/commandrun.go @@ -82,13 +82,13 @@ func WithSilent(silent bool) Option { func WithEnvironmentBlockList(blockList map[string]struct{}) Option { return func(cr *CommandRun) { - cr.environmentBlockList = blockList + cr.sensitiveEnvList = blockList } } func New(opts ...Option) *CommandRun { cr := &CommandRun{ - environmentBlockList: environment.DefaultBlockList(), + sensitiveEnvList: environment.DefaultSensitiveEnvList(), } for _, opt := range opts { @@ -118,10 +118,10 @@ type CommandRun struct { ExitCode int `json:"exitcode"` Processes []ProcessInfo `json:"processes,omitempty"` - silent bool - materials map[string]cryptoutil.DigestSet - enableTracing bool - environmentBlockList map[string]struct{} + silent bool + materials map[string]cryptoutil.DigestSet + enableTracing bool + sensitiveEnvList map[string]struct{} } func (a *CommandRun) Schema() *jsonschema.Schema { From cb158c2502d591efc72d5b7c5d77b20859e01143 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Wed, 2 Oct 2024 14:31:18 +0200 Subject: [PATCH 09/14] chore: Fix linux tracing in commandrun. Signed-off-by: Matthias Glastra --- attestation/commandrun/tracing_linux.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/attestation/commandrun/tracing_linux.go b/attestation/commandrun/tracing_linux.go index 90eb9c24..34c21b85 100644 --- a/attestation/commandrun/tracing_linux.go +++ b/attestation/commandrun/tracing_linux.go @@ -37,12 +37,12 @@ const ( ) type ptraceContext struct { - parentPid int - mainProgram string - processes map[int]*ProcessInfo - exitCode int - hash []cryptoutil.DigestValue - environmentBlockList map[string]struct{} + parentPid int + mainProgram string + processes map[int]*ProcessInfo + exitCode int + hash []cryptoutil.DigestValue + sensitiveEnvList map[string]struct{} } func enableTracing(c *exec.Cmd) { @@ -53,11 +53,11 @@ func enableTracing(c *exec.Cmd) { func (r *CommandRun) trace(c *exec.Cmd, actx *attestation.AttestationContext) ([]ProcessInfo, error) { pctx := &ptraceContext{ - parentPid: c.Process.Pid, - mainProgram: c.Path, - processes: make(map[int]*ProcessInfo), - hash: actx.Hashes(), - environmentBlockList: r.environmentBlockList, + parentPid: c.Process.Pid, + mainProgram: c.Path, + processes: make(map[int]*ProcessInfo), + hash: actx.Hashes(), + sensitiveEnvList: r.sensitiveEnvList, } if err := pctx.runTrace(); err != nil { @@ -201,7 +201,7 @@ func (p *ptraceContext) handleSyscall(pid int, regs unix.PtraceRegs) error { if err == nil { allVars := strings.Split(string(environ), "\x00") filteredEnviron := make([]string, 0) - environment.FilterEnvironmentArray(allVars, p.environmentBlockList, func(_, _, varStr string) { + environment.FilterEnvironmentArray(allVars, p.sensitiveEnvList, map[string]struct{}{}, func(_, _, varStr string) { filteredEnviron = append(filteredEnviron, varStr) }) From 9bea20806baffcd4ef9555a4302e813fbf6dd191 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Thu, 10 Oct 2024 15:51:38 +0200 Subject: [PATCH 10/14] Refactor environment. Signed-off-by: Matthias Glastra --- attestation/commandrun/commandrun.go | 2 +- attestation/context.go | 4 + attestation/context_env.go | 52 +++++ attestation/environment/environment.go | 198 +++++------------ attestation/environment/environment_test.go | 208 ------------------ environment/environment.go | 115 ++++++++++ environment/environment_test.go | 208 ++++++++++++++++++ .../environment => environment}/filter.go | 2 +- .../environment => environment}/obfuscate.go | 0 .../sensitive_env_vars.go | 12 +- 10 files changed, 449 insertions(+), 352 deletions(-) create mode 100644 attestation/context_env.go delete mode 100644 attestation/environment/environment_test.go create mode 100644 environment/environment.go create mode 100644 environment/environment_test.go rename {attestation/environment => environment}/filter.go (97%) rename {attestation/environment => environment}/obfuscate.go (100%) rename {attestation/environment => environment}/sensitive_env_vars.go (96%) diff --git a/attestation/commandrun/commandrun.go b/attestation/commandrun/commandrun.go index 9b58a340..2495501f 100644 --- a/attestation/commandrun/commandrun.go +++ b/attestation/commandrun/commandrun.go @@ -21,7 +21,7 @@ import ( "os/exec" "github.com/in-toto/go-witness/attestation" - "github.com/in-toto/go-witness/attestation/environment" + "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/cryptoutil" "github.com/invopop/jsonschema" ) diff --git a/attestation/context.go b/attestation/context.go index 4f81086b..ae201ddf 100644 --- a/attestation/context.go +++ b/attestation/context.go @@ -24,6 +24,7 @@ import ( "github.com/gobwas/glob" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/log" ) @@ -117,6 +118,7 @@ type AttestationContext struct { materials map[string]cryptoutil.DigestSet stepName string mutex sync.RWMutex + environmentCapturer *environment.Capture } type Product struct { @@ -229,6 +231,8 @@ func (ctx *AttestationContext) DirHashGlob() []glob.Glob { return ctx.dirHashGlobCompiled } + + func (ctx *AttestationContext) CompletedAttestors() []CompletedAttestor { ctx.mutex.RLock() out := make([]CompletedAttestor, len(ctx.completedAttestors)) diff --git a/attestation/context_env.go b/attestation/context_env.go new file mode 100644 index 00000000..fa8936f4 --- /dev/null +++ b/attestation/context_env.go @@ -0,0 +1,52 @@ +// Copyright 2024 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 attestation + +import ( + env "github.com/in-toto/go-witness/environment" +) + +func (ctx *AttestationContext) EnvironmentCapturer() *env.Capture { + return ctx.environmentCapturer +} + +// WithEnvFilterVarsEnabled will make the filter (removing) of vars the acting behavior. +// The default behavior is obfuscation of variables. +func WithEnvFilterVarsEnabled() AttestationContextOption { + return func(a *AttestationContext) { + env.WithFilterVarsEnabled()(a.environmentCapturer) + } +} + +// WithEnvAdditionalKeys add additional keys to final list that is checked for sensitive variables. +func WithEnvAdditionalKeys(additionalKeys []string) AttestationContextOption { + return func(a *AttestationContext) { + env.WithAdditionalKeys(additionalKeys)(a.environmentCapturer) + } +} + +// WithEnvExcludeKeys add additional keys to final list that is checked for sensitive variables. +func WithEnvExcludeKeys(excludeKeys []string) AttestationContextOption { + return func(a *AttestationContext) { + env.WithExcludeKeys(excludeKeys)(a.environmentCapturer) + } +} + +// WithEnvDisableDefaultSensitiveList will disable the default list and only use the additional keys. +func WithEnvDisableDefaultSensitiveList() AttestationContextOption { + return func(a *AttestationContext) { + env.WithDisableDefaultSensitiveList()(a.environmentCapturer) + } +} diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index f0dd1b09..ec954162 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -15,14 +15,11 @@ package environment import ( - "fmt" "os" "os/user" "runtime" - "strings" "github.com/in-toto/go-witness/attestation" - "github.com/in-toto/go-witness/registry" "github.com/invopop/jsonschema" ) @@ -51,64 +48,64 @@ type EnvironmentAttestor interface { } func init() { - attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }, - registry.BoolConfigOption( - "filter-sensitive-vars", - "Switch from obfuscate to filtering variables which removes them from the output completely.", - defaultFilterSensitiveVarsEnabled, - func(a attestation.Attestor, filterSensitiveVarsEnabled bool) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithFilterVarsEnabled()(envAttestor) - return envAttestor, nil - }, - ), - registry.BoolConfigOption( - "disable-default-sensitive-vars", - "Disable the default list of sensitive vars and only use the items mentioned by --attestor-environment-sensitive-key.", - defaultDisableSensitiveVarsDefault, - func(a attestation.Attestor, disableSensitiveVarsDefault bool) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithDisableDefaultSensitiveList()(envAttestor) - return envAttestor, nil - }, - ), - registry.StringSliceConfigOption( - "add-sensitive-key", - "Add keys or globs (e.g. '*TEXT') to the list of sensitive environment keys.", - []string{}, - func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithAdditionalKeys(additionalKeys)(envAttestor) - return envAttestor, nil - }, - ), - registry.StringSliceConfigOption( - "exclude-sensitive-key", - "Exclude specific keys from the list of sensitive environment keys. Note: This does not support globs.", - []string{}, - func(a attestation.Attestor, excludeKeys []string) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithExcludeKeys(excludeKeys)(envAttestor) - return envAttestor, nil - }, - ), - ) + // attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }, + // registry.BoolConfigOption( + // "filter-sensitive-vars", + // "Switch from obfuscate to filtering variables which removes them from the output completely.", + // defaultFilterSensitiveVarsEnabled, + // func(a attestation.Attestor, filterSensitiveVarsEnabled bool) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithFilterVarsEnabled()(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.BoolConfigOption( + // "disable-default-sensitive-vars", + // "Disable the default list of sensitive vars and only use the items mentioned by --attestor-environment-sensitive-key.", + // defaultDisableSensitiveVarsDefault, + // func(a attestation.Attestor, disableSensitiveVarsDefault bool) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithDisableDefaultSensitiveList()(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.StringSliceConfigOption( + // "add-sensitive-key", + // "Add keys or globs (e.g. '*TEXT') to the list of sensitive environment keys.", + // []string{}, + // func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithAdditionalKeys(additionalKeys)(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.StringSliceConfigOption( + // "exclude-sensitive-key", + // "Exclude specific keys from the list of sensitive environment keys. Note: This does not support globs.", + // []string{}, + // func(a attestation.Attestor, excludeKeys []string) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithExcludeKeys(excludeKeys)(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // ) } type Attestor struct { @@ -117,49 +114,11 @@ type Attestor struct { Username string `json:"username"` Variables map[string]string `json:"variables,omitempty"` - osEnviron func() []string - sensitiveVarsList map[string]struct{} - addSensitiveVarsList map[string]struct{} - excludeSensitiveVarsList map[string]struct{} - filterVarsEnabled bool - disableSensitiveVarsDefault bool + osEnviron func() []string } type Option func(*Attestor) -// WithFilterVarsEnabled will make the filter (removing) of vars the acting behavior. -// The default behavior is obfuscation of variables. -func WithFilterVarsEnabled() Option { - return func(a *Attestor) { - a.filterVarsEnabled = true - } -} - -// WithAdditionalKeys add additional keys to final list that is checked for sensitive variables. -func WithAdditionalKeys(additionalKeys []string) Option { - return func(a *Attestor) { - for _, value := range additionalKeys { - a.addSensitiveVarsList[value] = struct{}{} - } - } -} - -// WithExcludeKeys add additional keys to final list that is checked for sensitive variables. -func WithExcludeKeys(excludeKeys []string) Option { - return func(a *Attestor) { - for _, value := range excludeKeys { - a.excludeSensitiveVarsList[value] = struct{}{} - } - } -} - -// WithDisableDefaultSensitiveList will disable the default list and only use the additional keys. -func WithDisableDefaultSensitiveList() Option { - return func(a *Attestor) { - a.disableSensitiveVarsDefault = true - } -} - // WithCustomEnv will override the default os.Environ() method. This could be used to mock. func WithCustomEnv(osEnviron func() []string) Option { return func(a *Attestor) { @@ -168,11 +127,7 @@ func WithCustomEnv(osEnviron func() []string) Option { } func New(opts ...Option) *Attestor { - attestor := &Attestor{ - sensitiveVarsList: DefaultSensitiveEnvList(), - addSensitiveVarsList: map[string]struct{}{}, - excludeSensitiveVarsList: map[string]struct{}{}, - } + attestor := &Attestor{} attestor.osEnviron = os.Environ @@ -211,26 +166,7 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { a.Username = user.Username } - // Prepare sensitive keys list. - var finalSensitiveKeysList map[string]struct{} - if a.disableSensitiveVarsDefault { - a.sensitiveVarsList = map[string]struct{}{} - } - finalSensitiveKeysList = a.sensitiveVarsList - for k, v := range a.addSensitiveVarsList { - finalSensitiveKeysList[k] = v - } - - // Filter or obfuscate - if a.filterVarsEnabled { - FilterEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, a.excludeSensitiveVarsList, func(key, val, _ string) { - a.Variables[key] = val - }) - } else { - ObfuscateEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, a.excludeSensitiveVarsList, func(key, val, _ string) { - a.Variables[key] = val - }) - } + a.Variables = ctx.EnvironmentCapturer().Capture(a.osEnviron()) return nil } @@ -238,15 +174,3 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { func (a *Attestor) Data() *Attestor { return a } - -// splitVariable splits a string representing an environment variable in the format of -// "KEY=VAL" and returns the key and val separately. -func splitVariable(v string) (key, val string) { - parts := strings.SplitN(v, "=", 2) - key = parts[0] - if len(parts) > 1 { - val = parts[1] - } - - return -} diff --git a/attestation/environment/environment_test.go b/attestation/environment/environment_test.go deleted file mode 100644 index e8e0a7c8..00000000 --- a/attestation/environment/environment_test.go +++ /dev/null @@ -1,208 +0,0 @@ -// 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 ( - "os" - "testing" - - "github.com/in-toto/go-witness/attestation" - "github.com/stretchr/testify/require" -) - -// TestFilterVarsEnvironment tests if enabling filter behavior works correctly. -func TestFilterVarsEnvironment(t *testing.T) { - - customEnv := func() []string { - return []string{"AWS_ACCESS_KEY_ID=super secret"} - } - - attestor := New( - WithFilterVarsEnabled(), - WithCustomEnv(customEnv), - ) - - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - origVars := customEnv() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inBlockList := attestor.sensitiveVarsList[origKey]; inBlockList { - require.NotContains(t, attestor.Variables, origKey) - } else { - require.Contains(t, attestor.Variables, origKey) - } - } -} - -// TestExcludeVarsEnvironment tests if enabling filter behavior works correctly. -func TestExcludeVarsEnvironment(t *testing.T) { - - customEnv := func() []string { - return []string{"AWS_ACCESS_KEY_ID=super secret"} - } - - attestor := New( - WithExcludeKeys([]string{"AWS_ACCESS_KEY_ID"}), - WithCustomEnv(customEnv), - ) - - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - origVars := customEnv() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inList := attestor.excludeSensitiveVarsList[origKey]; inList { - require.Contains(t, attestor.Variables, origKey) - } else { - require.NotContains(t, attestor.Variables, origKey) - } - } -} - -// TestEnvironmentObfuscate tests if obfuscate normal behavior works correctly. -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) - } - } -} - -// TestEnvironmentObfuscateAdditional tests if the default obfuscate with additional keys works correctly. -func TestEnvironmentObfuscateAdditional(t *testing.T) { - attestor := New(WithAdditionalKeys([]string{"MYNAME"})) - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - obfuscateEnvs := map[string]struct{}{"API_TOKEN": {}, "MYNAME": {}} - 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) - } - } -} - -// TestEnvironmentCustomKeysAdditional tests if the default list is disabled the additional keys works correctly. -func TestEnvironmentCustomKeysAdditional(t *testing.T) { - attestor := New(WithDisableDefaultSensitiveList(), WithAdditionalKeys([]string{"MYNAME"})) - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - obfuscateEnvs := map[string]struct{}{"MYNAME": {}} - secretVarValue := "secret var" - publicVarValue := "public var" - for k := range obfuscateEnvs { - t.Setenv(k, secretVarValue) - } - - notObfuscateEnvs := map[string]struct{}{"API_TOKEN": {}} - 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) - } - } -} - -// TestEnvironmentFilterAdditional tests if enabling filter and adding additional keys works correctly. -func TestEnvironmentFilterAdditional(t *testing.T) { - attestor := New(WithFilterVarsEnabled(), WithAdditionalKeys([]string{"MYNAME"})) - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - filterEnvs := map[string]struct{}{"API_TOKEN": {}, "MYNAME": {}} - secretVarValue := "secret var" - publicVarValue := "public var" - for k := range filterEnvs { - t.Setenv(k, secretVarValue) - } - - notFilterEnvs := map[string]struct{}{"VAR_FOO": {}, "VAR_BAR": {}} - for k := range notFilterEnvs { - t.Setenv(k, publicVarValue) - } - - origVars := os.Environ() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inFilterList := filterEnvs[origKey]; inFilterList { - require.NotContains(t, attestor.Variables, origKey) - } - - if _, inNotObfuscateList := notFilterEnvs[origKey]; inNotObfuscateList { - require.Equal(t, attestor.Variables[origKey], publicVarValue) - } - } -} diff --git a/environment/environment.go b/environment/environment.go new file mode 100644 index 00000000..4a23ce22 --- /dev/null +++ b/environment/environment.go @@ -0,0 +1,115 @@ +// Copyright 2024 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" +) + +type Capture struct { + sensitiveVarsList map[string]struct{} + addSensitiveVarsList map[string]struct{} + excludeSensitiveVarsList map[string]struct{} + filterVarsEnabled bool + disableSensitiveVarsDefault bool +} + +type CaptureOption func(*Capture) + +// WithFilterVarsEnabled will make the filter (removing) of vars the acting behavior. +// The default behavior is obfuscation of variables. +func WithFilterVarsEnabled() CaptureOption { + return func(c *Capture) { + c.filterVarsEnabled = true + } +} + +// WithAdditionalKeys add additional keys to final list that is checked for sensitive variables. +func WithAdditionalKeys(additionalKeys []string) CaptureOption { + return func(c *Capture) { + for _, value := range additionalKeys { + c.addSensitiveVarsList[value] = struct{}{} + } + } +} + +// WithExcludeKeys add additional keys to final list that is checked for sensitive variables. +func WithExcludeKeys(excludeKeys []string) CaptureOption { + return func(c *Capture) { + for _, value := range excludeKeys { + c.excludeSensitiveVarsList[value] = struct{}{} + } + } +} + +// WithDisableDefaultSensitiveList will disable the default list and only use the additional keys. +func WithDisableDefaultSensitiveList() CaptureOption { + return func(c *Capture) { + c.disableSensitiveVarsDefault = true + } +} + +func New(opts ...CaptureOption) *Capture { + capture := &Capture{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + } + + for _, opt := range opts { + opt(capture) + } + + return capture +} + +func (c *Capture) Capture(env []string) map[string]string { + variables := make(map[string]string) + + // Prepare sensitive keys list. + var finalSensitiveKeysList map[string]struct{} + if c.disableSensitiveVarsDefault { + c.sensitiveVarsList = map[string]struct{}{} + } + finalSensitiveKeysList = c.sensitiveVarsList + for k, v := range c.addSensitiveVarsList { + finalSensitiveKeysList[k] = v + } + + // Filter or obfuscate + if c.filterVarsEnabled { + FilterEnvironmentArray(env, finalSensitiveKeysList, c.excludeSensitiveVarsList, func(key, val, _ string) { + variables[key] = val + }) + } else { + ObfuscateEnvironmentArray(env, finalSensitiveKeysList, c.excludeSensitiveVarsList, func(key, val, _ string) { + variables[key] = val + }) + } + + return variables +} + +// splitVariable splits a string representing an environment variable in the format of +// "KEY=VAL" and returns the key and val separately. +func splitVariable(v string) (key, val string) { + parts := strings.SplitN(v, "=", 2) + key = parts[0] + if len(parts) > 1 { + val = parts[1] + } + + return +} diff --git a/environment/environment_test.go b/environment/environment_test.go new file mode 100644 index 00000000..d9e9c93a --- /dev/null +++ b/environment/environment_test.go @@ -0,0 +1,208 @@ +package environment + +import ( + "reflect" + "testing" +) + +func Test_splitVariable(t *testing.T) { + type args struct { + v string + } + tests := []struct { + name string + args args + wantKey string + wantVal string + }{ + { + name: "KEY=VALUE", + args: args{ + v: "KEY=VALUE", + }, + wantKey: "KEY", + wantVal: "VALUE", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotKey, gotVal := splitVariable(tt.args.v) + if gotKey != tt.wantKey { + t.Errorf("splitVariable() gotKey = %v, want %v", gotKey, tt.wantKey) + } + if gotVal != tt.wantVal { + t.Errorf("splitVariable() gotVal = %v, want %v", gotVal, tt.wantVal) + } + }) + } +} + +func TestCapture_Capture(t *testing.T) { + type fields struct { + sensitiveVarsList map[string]struct{} + addSensitiveVarsList map[string]struct{} + excludeSensitiveVarsList map[string]struct{} + filterVarsEnabled bool + disableSensitiveVarsDefault bool + } + type args struct { + env []string + } + tests := []struct { + name string + fields fields + args args + want map[string]string + }{ + { + name: "Obfuscate *_TOKEN", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: false, + disableSensitiveVarsDefault: false, + }, + args: args{ + env: []string{ + "TEST_TOKEN=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TOKEN": "******", + "TEST_TEXT": "value", + }, + }, + { + name: "Filter *_TOKEN", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: true, + disableSensitiveVarsDefault: false, + }, + args: args{ + env: []string{ + "TEST_TOKEN=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TEXT": "value", + }, + }, + { + name: "Disable sensitive vars", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: true, + disableSensitiveVarsDefault: true, + }, + args: args{ + env: []string{ + "TEST_TOKEN=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TOKEN": "password", + "TEST_TEXT": "value", + }, + }, + { + name: "Obfuscate custom sensitive vars", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{ + "*_BLA": {}, + }, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: false, + disableSensitiveVarsDefault: true, + }, + args: args{ + env: []string{ + "TEST_BLA=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_BLA": "******", + "TEST_TEXT": "value", + }, + }, + { + name: "Filter custom sensitive vars", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{ + "*_BLA": {}, + }, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: true, + disableSensitiveVarsDefault: true, + }, + args: args{ + env: []string{ + "TEST_BLA=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TEXT": "value", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Capture{ + sensitiveVarsList: tt.fields.sensitiveVarsList, + addSensitiveVarsList: tt.fields.addSensitiveVarsList, + excludeSensitiveVarsList: tt.fields.excludeSensitiveVarsList, + filterVarsEnabled: tt.fields.filterVarsEnabled, + disableSensitiveVarsDefault: tt.fields.disableSensitiveVarsDefault, + } + if got := c.Capture(tt.args.env); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Capture.Capture() = %v, want %v", got, tt.want) + } + }) + } +} + +func _TestWith() CaptureOption { + return func(c *Capture) { + c.filterVarsEnabled = true + } +} + +func TestNew(t *testing.T) { + type args struct { + opts []CaptureOption + } + tests := []struct { + name string + args args + want *Capture + }{ + { + name: "With", + args: args{ + opts: []CaptureOption{_TestWith()}, + }, + want: &Capture{ + filterVarsEnabled: true, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := New(tt.args.opts...); got.filterVarsEnabled != tt.want.filterVarsEnabled { + t.Errorf("New() = %v, want %v", got.filterVarsEnabled, tt.want.filterVarsEnabled) + } + }) + } +} diff --git a/attestation/environment/filter.go b/environment/filter.go similarity index 97% rename from attestation/environment/filter.go rename to environment/filter.go index 46e09cf0..e2682c17 100644 --- a/attestation/environment/filter.go +++ b/environment/filter.go @@ -1,4 +1,4 @@ -// Copyright 2021 The Witness Contributors +// Copyright 2024 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. diff --git a/attestation/environment/obfuscate.go b/environment/obfuscate.go similarity index 100% rename from attestation/environment/obfuscate.go rename to environment/obfuscate.go diff --git a/attestation/environment/sensitive_env_vars.go b/environment/sensitive_env_vars.go similarity index 96% rename from attestation/environment/sensitive_env_vars.go rename to environment/sensitive_env_vars.go index 64f1ba24..f7282c34 100644 --- a/attestation/environment/sensitive_env_vars.go +++ b/environment/sensitive_env_vars.go @@ -21,11 +21,13 @@ func DefaultSensitiveEnvList() map[string]struct{} { return map[string]struct{}{ // Glob pattern list - "*TOKEN*": {}, - "*SECRET*": {}, - "*API_KEY*": {}, - "*PASSWORD*": {}, - "*JWT*": {}, + "*TOKEN*": {}, + "*SECRET*": {}, + "*API_KEY*": {}, + "*PASSWORD*": {}, + "*JWT*": {}, + "*sshKey*": {}, + "*passphrase*": {}, // Explicit list "AWS_ACCESS_KEY_ID": {}, From 7b01c064c191e049e5019ed24802d85ef434ab95 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Mon, 14 Oct 2024 11:18:23 +0200 Subject: [PATCH 11/14] Add new environment to commandrun Signed-off-by: Matthias Glastra --- attestation/commandrun/commandrun.go | 8 -------- attestation/commandrun/tracing_linux.go | 9 +++------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/attestation/commandrun/commandrun.go b/attestation/commandrun/commandrun.go index 2495501f..e04767e7 100644 --- a/attestation/commandrun/commandrun.go +++ b/attestation/commandrun/commandrun.go @@ -80,15 +80,8 @@ func WithSilent(silent bool) Option { } } -func WithEnvironmentBlockList(blockList map[string]struct{}) Option { - return func(cr *CommandRun) { - cr.sensitiveEnvList = blockList - } -} - func New(opts ...Option) *CommandRun { cr := &CommandRun{ - sensitiveEnvList: environment.DefaultSensitiveEnvList(), } for _, opt := range opts { @@ -121,7 +114,6 @@ type CommandRun struct { silent bool materials map[string]cryptoutil.DigestSet enableTracing bool - sensitiveEnvList map[string]struct{} } func (a *CommandRun) Schema() *jsonschema.Schema { diff --git a/attestation/commandrun/tracing_linux.go b/attestation/commandrun/tracing_linux.go index 34c21b85..d214b35d 100644 --- a/attestation/commandrun/tracing_linux.go +++ b/attestation/commandrun/tracing_linux.go @@ -42,7 +42,7 @@ type ptraceContext struct { processes map[int]*ProcessInfo exitCode int hash []cryptoutil.DigestValue - sensitiveEnvList map[string]struct{} + environmentCapturer *environment.Capture } func enableTracing(c *exec.Cmd) { @@ -57,7 +57,7 @@ func (r *CommandRun) trace(c *exec.Cmd, actx *attestation.AttestationContext) ([ mainProgram: c.Path, processes: make(map[int]*ProcessInfo), hash: actx.Hashes(), - sensitiveEnvList: r.sensitiveEnvList, + environmentCapturer: actx.EnvironmentCapturer(), } if err := pctx.runTrace(); err != nil { @@ -200,10 +200,7 @@ func (p *ptraceContext) handleSyscall(pid int, regs unix.PtraceRegs) error { environ, err := os.ReadFile(envinLocation) if err == nil { allVars := strings.Split(string(environ), "\x00") - filteredEnviron := make([]string, 0) - environment.FilterEnvironmentArray(allVars, p.sensitiveEnvList, map[string]struct{}{}, func(_, _, varStr string) { - filteredEnviron = append(filteredEnviron, varStr) - }) + filteredEnviron := p.environmentCapturer.Capture(allVars) procInfo.Environ = strings.Join(filteredEnviron, " ") } From c96959306ead0d75eb3c43c823cadb43d5e9abc5 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Mon, 14 Oct 2024 11:20:56 +0200 Subject: [PATCH 12/14] Add license headers Signed-off-by: Matthias Glastra --- environment/environment_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/environment/environment_test.go b/environment/environment_test.go index d9e9c93a..6de1f0a3 100644 --- a/environment/environment_test.go +++ b/environment/environment_test.go @@ -1,3 +1,17 @@ +// Copyright 2024 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 ( From 38ba44c573bb026bfa8e308fc79f5ddbc9a0915e Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Mon, 14 Oct 2024 11:38:23 +0200 Subject: [PATCH 13/14] Fix lint errors Signed-off-by: Matthias Glastra --- attestation/commandrun/commandrun.go | 1 - attestation/commandrun/tracing_linux.go | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/attestation/commandrun/commandrun.go b/attestation/commandrun/commandrun.go index e04767e7..007d4e6e 100644 --- a/attestation/commandrun/commandrun.go +++ b/attestation/commandrun/commandrun.go @@ -21,7 +21,6 @@ import ( "os/exec" "github.com/in-toto/go-witness/attestation" - "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/cryptoutil" "github.com/invopop/jsonschema" ) diff --git a/attestation/commandrun/tracing_linux.go b/attestation/commandrun/tracing_linux.go index d214b35d..40fb3180 100644 --- a/attestation/commandrun/tracing_linux.go +++ b/attestation/commandrun/tracing_linux.go @@ -26,7 +26,7 @@ import ( "strings" "github.com/in-toto/go-witness/attestation" - "github.com/in-toto/go-witness/attestation/environment" + "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/cryptoutil" "github.com/in-toto/go-witness/log" "golang.org/x/sys/unix" @@ -37,11 +37,11 @@ const ( ) type ptraceContext struct { - parentPid int - mainProgram string - processes map[int]*ProcessInfo - exitCode int - hash []cryptoutil.DigestValue + parentPid int + mainProgram string + processes map[int]*ProcessInfo + exitCode int + hash []cryptoutil.DigestValue environmentCapturer *environment.Capture } @@ -53,10 +53,10 @@ func enableTracing(c *exec.Cmd) { func (r *CommandRun) trace(c *exec.Cmd, actx *attestation.AttestationContext) ([]ProcessInfo, error) { pctx := &ptraceContext{ - parentPid: c.Process.Pid, - mainProgram: c.Path, - processes: make(map[int]*ProcessInfo), - hash: actx.Hashes(), + parentPid: c.Process.Pid, + mainProgram: c.Path, + processes: make(map[int]*ProcessInfo), + hash: actx.Hashes(), environmentCapturer: actx.EnvironmentCapturer(), } From 2d91073e40142e519947261da1584947b9e5bf16 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Mon, 14 Oct 2024 13:03:47 +0200 Subject: [PATCH 14/14] WIP Linux tracing fix Signed-off-by: Matthias Glastra --- attestation/commandrun/commandrun.go | 9 +- attestation/commandrun/tracing_linux.go | 11 ++- attestation/context.go | 2 - attestation/environment/environment.go | 125 ++++++++++++------------ 4 files changed, 75 insertions(+), 72 deletions(-) diff --git a/attestation/commandrun/commandrun.go b/attestation/commandrun/commandrun.go index 007d4e6e..e237db8f 100644 --- a/attestation/commandrun/commandrun.go +++ b/attestation/commandrun/commandrun.go @@ -80,8 +80,7 @@ func WithSilent(silent bool) Option { } func New(opts ...Option) *CommandRun { - cr := &CommandRun{ - } + cr := &CommandRun{} for _, opt := range opts { opt(cr) @@ -110,9 +109,9 @@ type CommandRun struct { ExitCode int `json:"exitcode"` Processes []ProcessInfo `json:"processes,omitempty"` - silent bool - materials map[string]cryptoutil.DigestSet - enableTracing bool + silent bool + materials map[string]cryptoutil.DigestSet + enableTracing bool } func (a *CommandRun) Schema() *jsonschema.Schema { diff --git a/attestation/commandrun/tracing_linux.go b/attestation/commandrun/tracing_linux.go index 40fb3180..c76825a6 100644 --- a/attestation/commandrun/tracing_linux.go +++ b/attestation/commandrun/tracing_linux.go @@ -26,8 +26,8 @@ import ( "strings" "github.com/in-toto/go-witness/attestation" - "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/log" "golang.org/x/sys/unix" ) @@ -200,9 +200,14 @@ func (p *ptraceContext) handleSyscall(pid int, regs unix.PtraceRegs) error { environ, err := os.ReadFile(envinLocation) if err == nil { allVars := strings.Split(string(environ), "\x00") - filteredEnviron := p.environmentCapturer.Capture(allVars) - procInfo.Environ = strings.Join(filteredEnviron, " ") + env := make([]string, 0) + var capturedEnv map[string]string = p.environmentCapturer.Capture(allVars) + for k, v := range capturedEnv { + env = append(env, fmt.Sprintf("%s=%s", k, v)) + } + + procInfo.Environ = strings.Join(env, " ") } cmdline, err := os.ReadFile(cmdlineLocation) diff --git a/attestation/context.go b/attestation/context.go index ae201ddf..e57e792d 100644 --- a/attestation/context.go +++ b/attestation/context.go @@ -231,8 +231,6 @@ func (ctx *AttestationContext) DirHashGlob() []glob.Glob { return ctx.dirHashGlobCompiled } - - func (ctx *AttestationContext) CompletedAttestors() []CompletedAttestor { ctx.mutex.RLock() out := make([]CompletedAttestor, len(ctx.completedAttestors)) diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index ec954162..a62f20f6 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -32,10 +32,10 @@ const ( // This is a hacky way to create a compile time error in case the attestor // doesn't implement the expected interfaces. var ( - _ attestation.Attestor = &Attestor{} - _ EnvironmentAttestor = &Attestor{} - defaultFilterSensitiveVarsEnabled = false - defaultDisableSensitiveVarsDefault = false + _ attestation.Attestor = &Attestor{} + _ EnvironmentAttestor = &Attestor{} + // defaultFilterSensitiveVarsEnabled = false + // defaultDisableSensitiveVarsDefault = false ) type EnvironmentAttestor interface { @@ -48,64 +48,65 @@ type EnvironmentAttestor interface { } func init() { - // attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }, - // registry.BoolConfigOption( - // "filter-sensitive-vars", - // "Switch from obfuscate to filtering variables which removes them from the output completely.", - // defaultFilterSensitiveVarsEnabled, - // func(a attestation.Attestor, filterSensitiveVarsEnabled bool) (attestation.Attestor, error) { - // envAttestor, ok := a.(*Attestor) - // if !ok { - // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - // } - - // envCapture.WithFilterVarsEnabled()(envAttestor.capture) - // return envAttestor, nil - // }, - // ), - // registry.BoolConfigOption( - // "disable-default-sensitive-vars", - // "Disable the default list of sensitive vars and only use the items mentioned by --attestor-environment-sensitive-key.", - // defaultDisableSensitiveVarsDefault, - // func(a attestation.Attestor, disableSensitiveVarsDefault bool) (attestation.Attestor, error) { - // envAttestor, ok := a.(*Attestor) - // if !ok { - // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - // } - - // envCapture.WithDisableDefaultSensitiveList()(envAttestor.capture) - // return envAttestor, nil - // }, - // ), - // registry.StringSliceConfigOption( - // "add-sensitive-key", - // "Add keys or globs (e.g. '*TEXT') to the list of sensitive environment keys.", - // []string{}, - // func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { - // envAttestor, ok := a.(*Attestor) - // if !ok { - // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - // } - - // envCapture.WithAdditionalKeys(additionalKeys)(envAttestor.capture) - // return envAttestor, nil - // }, - // ), - // registry.StringSliceConfigOption( - // "exclude-sensitive-key", - // "Exclude specific keys from the list of sensitive environment keys. Note: This does not support globs.", - // []string{}, - // func(a attestation.Attestor, excludeKeys []string) (attestation.Attestor, error) { - // envAttestor, ok := a.(*Attestor) - // if !ok { - // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - // } - - // envCapture.WithExcludeKeys(excludeKeys)(envAttestor.capture) - // return envAttestor, nil - // }, - // ), - // ) + attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }) + + // registry.BoolConfigOption( + // "filter-sensitive-vars", + // "Switch from obfuscate to filtering variables which removes them from the output completely.", + // defaultFilterSensitiveVarsEnabled, + // func(a attestation.Attestor, filterSensitiveVarsEnabled bool) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithFilterVarsEnabled()(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.BoolConfigOption( + // "disable-default-sensitive-vars", + // "Disable the default list of sensitive vars and only use the items mentioned by --attestor-environment-sensitive-key.", + // defaultDisableSensitiveVarsDefault, + // func(a attestation.Attestor, disableSensitiveVarsDefault bool) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithDisableDefaultSensitiveList()(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.StringSliceConfigOption( + // "add-sensitive-key", + // "Add keys or globs (e.g. '*TEXT') to the list of sensitive environment keys.", + // []string{}, + // func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithAdditionalKeys(additionalKeys)(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.StringSliceConfigOption( + // "exclude-sensitive-key", + // "Exclude specific keys from the list of sensitive environment keys. Note: This does not support globs.", + // []string{}, + // func(a attestation.Attestor, excludeKeys []string) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithExcludeKeys(excludeKeys)(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + } type Attestor struct {