Skip to content

Commit

Permalink
feat: Change to default obfuscate and add cli flags.
Browse files Browse the repository at this point in the history
Adding flags to behave blocking or obfuscating and adding new keys.

Signed-off-by: Matthias Glastra <[email protected]>
  • Loading branch information
matglas committed Sep 27, 2024
1 parent 1844d7e commit 1e45a7b
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 36 deletions.
36 changes: 34 additions & 2 deletions attestation/environment/blocklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}{
Expand Down Expand Up @@ -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)
}
}
}
110 changes: 90 additions & 20 deletions attestation/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down
17 changes: 3 additions & 14 deletions attestation/environment/obfuscate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 = "******"
Expand Down
112 changes: 112 additions & 0 deletions attestation/environment/sensitive_env_vars.go
Original file line number Diff line number Diff line change
@@ -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": {},
}
}

0 comments on commit 1e45a7b

Please sign in to comment.