Skip to content

Commit

Permalink
feat: New environment variable obfuscation functionality (#355)
Browse files Browse the repository at this point in the history
* chore: New environment variable obfuscation functionality

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Update attestation/environment/obfuscate.go

Co-authored-by: Kairo Araujo <kairo@kairo.eti.br>
Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* 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 <matglas.git@gmail.com>

* chore: Adjust naming to filter envs. Fix tests.

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* chore: Making the environment test cases more robust.

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* feat: Add exclude-sensitive-key flag.

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Update attestation/environment/sensitive_env_vars.go

Co-authored-by: Kairo Araujo <kairo@kairo.eti.br>
Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* chore: Fix tests and command run.

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* chore: Fix linux tracing in commandrun.

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Refactor environment.

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Add new environment to commandrun

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Add license headers

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Fix lint errors

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* WIP Linux tracing fix

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Update environment/sensitive_env_vars.go

Co-authored-by: Tom Meadows <tom@tmlabs.co.uk>
Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Add AttestationContextOption for Environment Caputurer.

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

* Fix format

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>

---------

Signed-off-by: Matthias Glastra <matglas.git@gmail.com>
Co-authored-by: Kairo Araujo <kairo@kairo.eti.br>
Co-authored-by: Tom Meadows <tom@tmlabs.co.uk>
Co-authored-by: Cole Kennedy <colek42@gmail.com>
  • Loading branch information
4 people authored Jan 18, 2025
1 parent 6756567 commit 4f862d4
Show file tree
Hide file tree
Showing 11 changed files with 579 additions and 113 deletions.
18 changes: 4 additions & 14 deletions attestation/commandrun/commandrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"os/exec"

"github.com/in-toto/go-witness/attestation"
"github.com/in-toto/go-witness/attestation/environment"
"github.com/in-toto/go-witness/cryptoutil"
"github.com/invopop/jsonschema"
)
Expand Down Expand Up @@ -80,16 +79,8 @@ func WithSilent(silent bool) Option {
}
}

func WithEnvironmentBlockList(blockList map[string]struct{}) Option {
return func(cr *CommandRun) {
cr.environmentBlockList = blockList
}
}

func New(opts ...Option) *CommandRun {
cr := &CommandRun{
environmentBlockList: environment.DefaultBlockList(),
}
cr := &CommandRun{}

for _, opt := range opts {
opt(cr)
Expand Down Expand Up @@ -118,10 +109,9 @@ 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
}

func (a *CommandRun) Schema() *jsonschema.Schema {
Expand Down
36 changes: 19 additions & 17 deletions attestation/commandrun/tracing_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
"strings"

"github.com/in-toto/go-witness/attestation"
"github.com/in-toto/go-witness/attestation/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"
)
Expand All @@ -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
environmentCapturer *environment.Capture
}

func enableTracing(c *exec.Cmd) {
Expand All @@ -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(),
environmentCapturer: actx.EnvironmentCapturer(),
}

if err := pctx.runTrace(); err != nil {
Expand Down Expand Up @@ -200,12 +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 := make([]string, 0)
environment.FilterEnvironmentArray(allVars, p.environmentBlockList, func(_, _, varStr string) {
filteredEnviron = append(filteredEnviron, varStr)
})

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)
Expand Down
22 changes: 22 additions & 0 deletions attestation/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -98,13 +99,32 @@ func WithDirHashGlob(dirHashGlob []string) AttestationContextOption {
}
}

// WithEnvCapturer sets the configuration for the environment.Capturer inside the AttestationContext.
func WithEnvCapturer(additionalKeys []string, excludeKeys []string, disableDefaultSensitiveVars bool, filterVarsEnabled bool) AttestationContextOption {
return func(ctx *AttestationContext) {
opts := []environment.CaptureOption{
environment.WithAdditionalKeys(additionalKeys),
environment.WithExcludeKeys(excludeKeys),
}
if disableDefaultSensitiveVars {
opts = append(opts, environment.WithDisableDefaultSensitiveList())
}
if filterVarsEnabled {
opts = append(opts, environment.WithFilterVarsEnabled())
}

ctx.environmentCapturer = environment.New(opts...)
}
}

type CompletedAttestor struct {
Attestor Attestor
StartTime time.Time
EndTime time.Time
Error error
}

// AttestationContext is a struct that hold configuration that can be used across all attestors.
type AttestationContext struct {
ctx context.Context
attestors []Attestor
Expand All @@ -117,13 +137,15 @@ type AttestationContext struct {
materials map[string]cryptoutil.DigestSet
stepName string
mutex sync.RWMutex
environmentCapturer *environment.Capture
}

type Product struct {
MimeType string `json:"mime_type"`
Digest cryptoutil.DigestSet `json:"digest"`
}

// NewContext creates a new AttestationContext.
func NewContext(stepName string, attestors []Attestor, opts ...AttestationContextOption) (*AttestationContext, error) {
wd, err := os.Getwd()
if err != nil {
Expand Down
52 changes: 52 additions & 0 deletions attestation/context_env.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
36 changes: 11 additions & 25 deletions attestation/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"os"
"os/user"
"runtime"
"strings"

"github.com/in-toto/go-witness/attestation"
"github.com/invopop/jsonschema"
Expand All @@ -35,6 +34,8 @@ const (
var (
_ attestation.Attestor = &Attestor{}
_ EnvironmentAttestor = &Attestor{}
// defaultFilterSensitiveVarsEnabled = false
// defaultDisableSensitiveVarsDefault = false
)

type EnvironmentAttestor interface {
Expand All @@ -47,9 +48,7 @@ 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() })
}

type Attestor struct {
Expand All @@ -58,21 +57,22 @@ type Attestor struct {
Username string `json:"username"`
Variables map[string]string `json:"variables,omitempty"`

blockList map[string]struct{}
osEnviron func() []string
}

type Option func(*Attestor)

func WithBlockList(blockList map[string]struct{}) Option {
// 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.blockList = blockList
a.osEnviron = osEnviron
}
}

func New(opts ...Option) *Attestor {
attestor := &Attestor{
blockList: DefaultBlockList(),
}
attestor := &Attestor{}

attestor.osEnviron = os.Environ

for _, opt := range opts {
opt(attestor)
Expand Down Expand Up @@ -109,25 +109,11 @@ 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
})
a.Variables = ctx.EnvironmentCapturer().Capture(a.osEnviron())

return nil
}

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
}
41 changes: 0 additions & 41 deletions attestation/environment/environment_test.go

This file was deleted.

Loading

0 comments on commit 4f862d4

Please sign in to comment.