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.
  • Loading branch information
matglas committed Sep 27, 2024
1 parent 1844d7e commit 9ec0ae2
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 = nil
}
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 9ec0ae2

Please sign in to comment.