Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions cmd/containerd-shim-lcow-v2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ func setLogConfiguration() error {
logrus.SetLevel(lvl)
}

if opts.ScrubLogs {
log.SetScrubbing(true)
// Scrubbing is enabled by default (via init() in internal/log/scrub.go).
// Only disable if the option is explicitly set to false.
if opts.ScrubLogs != nil && !*opts.ScrubLogs {
log.SetScrubbing(false)
}
}
_ = os.Stdin.Close()
Expand Down
19 changes: 11 additions & 8 deletions cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions cmd/containerd-shim-runhcs-v1/options/runhcs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ message Options {
// UTC.
bool no_inherit_host_timezone = 19;

// scrub_logs enables removing environment variables and other potentially sensitive information from logs
bool scrub_logs = 20;
// scrub_logs controls removing environment variables and other potentially sensitive information from logs.
// If unset, scrubbing is enabled by default. Set explicitly to false to disable.
optional bool scrub_logs = 20;
}

// ProcessDetails contains additional information about a process. This is the additional
Expand Down
7 changes: 4 additions & 3 deletions cmd/containerd-shim-runhcs-v1/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,10 @@ var serveCommand = cli.Command{

os.Stdin.Close()

// enable scrubbing
if shimOpts.ScrubLogs {
hcslog.SetScrubbing(true)
// Scrubbing is enabled by default (via init() in internal/log/scrub.go).
// Only disable if the option is explicitly set to false.
if shimOpts.ScrubLogs != nil && !*shimOpts.ScrubLogs {
hcslog.SetScrubbing(false)
}

// Force the cli.ErrWriter to be os.Stdout for this. We use stderr for
Expand Down
2 changes: 1 addition & 1 deletion cmd/gcs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func main() {
disableTimeSync := flag.Bool("disable-time-sync",
false,
"If true do not run chronyd time synchronization service inside the UVM")
scrubLogs := flag.Bool("scrub-logs", false, "If true, scrub potentially sensitive information from logging")
scrubLogs := flag.Bool("scrub-logs", true, "If true, scrub potentially sensitive information from logging")
initialPolicyStance := flag.String("initial-policy-stance",
"allow",
"Stance: allow, deny.")
Expand Down
5 changes: 4 additions & 1 deletion internal/builder/vm/lcow/kernel_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,10 @@ func buildGCSCommand(
gcsParts = append(gcsParts, "-disable-time-sync")
}

if opts != nil && opts.ScrubLogs {
// Scrubbing is enabled by default. Only pass -scrub-logs=false if explicitly disabled.
if opts != nil && opts.ScrubLogs != nil && !*opts.ScrubLogs {
gcsParts = append(gcsParts, "-scrub-logs=false")
} else {
gcsParts = append(gcsParts, "-scrub-logs")
}

Expand Down
36 changes: 34 additions & 2 deletions internal/builder/vm/lcow/specs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
vm "github.com/Microsoft/hcsshim/sandbox-spec/vm/v2"

"github.com/opencontainers/runtime-spec/specs-go"
"google.golang.org/protobuf/proto"
)

type specTestCase struct {
Expand Down Expand Up @@ -1638,11 +1639,11 @@ func TestBuildSandboxConfig_BootOptions(t *testing.T) {
},
},
{
name: "scrub logs option",
name: "scrub logs option enabled",
opts: &runhcsoptions.Options{
SandboxPlatform: "linux/amd64",
BootFilesRootPath: vhdOnlyPath,
ScrubLogs: true,
ScrubLogs: proto.Bool(true),
},
validate: func(t *testing.T, doc *hcsschema.ComputeSystem, sandboxOpts *SandboxOptions) {
t.Helper()
Expand All @@ -1651,6 +1652,37 @@ func TestBuildSandboxConfig_BootOptions(t *testing.T) {
}
},
},
{
name: "scrub logs option disabled",
opts: &runhcsoptions.Options{
SandboxPlatform: "linux/amd64",
BootFilesRootPath: vhdOnlyPath,
ScrubLogs: proto.Bool(false),
},
validate: func(t *testing.T, doc *hcsschema.ComputeSystem, sandboxOpts *SandboxOptions) {
t.Helper()
if !strings.Contains(getKernelArgs(doc), "-scrub-logs=false") {
t.Error("expected -scrub-logs=false in kernel args")
}
},
},
{
name: "scrub logs option unset",
opts: &runhcsoptions.Options{
SandboxPlatform: "linux/amd64",
BootFilesRootPath: vhdOnlyPath,
},
validate: func(t *testing.T, doc *hcsschema.ComputeSystem, sandboxOpts *SandboxOptions) {
t.Helper()
args := getKernelArgs(doc)
if !strings.Contains(args, "-scrub-logs") {
t.Error("expected -scrub-logs in kernel args")
}
if strings.Contains(args, "-scrub-logs=false") {
t.Error("did not expect -scrub-logs=false in kernel args")
}
},
},
}

runTestCases(t, ctx, nil, tests)
Expand Down
2 changes: 1 addition & 1 deletion internal/hcsoci/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func initializeCreateOptions(ctx context.Context, createOptions *CreateOptions)
}

log.G(ctx).WithFields(logrus.Fields{
"options": log.Format(ctx, createOptions),
"options": log.FormatScrub(ctx, createOptions, log.ScrubCreateOptions),
"schema": log.Format(ctx, coi.actualSchemaVersion),
}).Debug("hcsshim::initializeCreateOptions")
Comment on lines 131 to 134
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could probably get away with:

Suggested change
log.G(ctx).WithFields(logrus.Fields{
"options": log.Format(ctx, createOptions),
"options": log.FormatScrub(ctx, createOptions, log.ScrubCreateOptions),
"schema": log.Format(ctx, coi.actualSchemaVersion),
}).Debug("hcsshim::initializeCreateOptions")
if logrus.IsLevelEnabled(logrus.DebugLevel) {
if b, err := log.ScrubCreateOptions([]byte(log.Format(ctx, createOptions))); err != nil {
log.G(ctx).WithError(err).Warning("could not scrub CreateOptions")
} else {
log.G(ctx).WithFields(logrus.Fields{
"options": string(b)
"schema": log.Format(ctx, coi.actualSchemaVersion),
}).Debug("hcsshim::initializeCreateOptions")
}
}

this way, we don't need FormatScrub


Expand Down
24 changes: 24 additions & 0 deletions internal/log/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ func Format(ctx context.Context, v interface{}) string {
return string(b)
}

// FormatScrub formats a value as JSON and then applies a scrub function to remove
// potentially sensitive information before logging.
func FormatScrub(ctx context.Context, v interface{}, scrub func([]byte) ([]byte, error)) string {
b, err := encode(v)
if err != nil {
G(ctx).WithFields(logrus.Fields{
logrus.ErrorKey: err,
"type": fmt.Sprintf("%T", v),
}).Debug("could not format value")
return ""
}

b, err = scrub(b)
if err != nil {
G(ctx).WithFields(logrus.Fields{
logrus.ErrorKey: err,
"type": fmt.Sprintf("%T", v),
}).Debug("could not scrub value")
return ""
}

return string(b)
}
Comment on lines +81 to +101
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can just be (though, as mentioned above comment, we can probably get away without this):

Suggested change
func FormatScrub(ctx context.Context, v interface{}, scrub func([]byte) ([]byte, error)) string {
b, err := encode(v)
if err != nil {
G(ctx).WithFields(logrus.Fields{
logrus.ErrorKey: err,
"type": fmt.Sprintf("%T", v),
}).Debug("could not format value")
return ""
}
b, err = scrub(b)
if err != nil {
G(ctx).WithFields(logrus.Fields{
logrus.ErrorKey: err,
"type": fmt.Sprintf("%T", v),
}).Debug("could not scrub value")
return ""
}
return string(b)
}
func FormatScrub(ctx context.Context, v any, scrub func([]byte) ([]byte, error)) string {
s := Format(ctx, v)
if s == "" {
return ""
}
b, err := scrub([]byte(s))
if err != nil {
G(ctx).WithFields(logrus.Fields{
logrus.ErrorKey: err,
"type": fmt.Sprintf("%T", v),
}).Debug("could not scrub value")
}
return string(b)
}


func encode(v interface{}) (_ []byte, err error) {
if m, ok := v.(proto.Message); ok {
// use canonical JSON encoding for protobufs (instead of [encoding/json])
Expand Down
21 changes: 20 additions & 1 deletion internal/log/scrub.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ var (
_scrub atomic.Bool
)

// SetScrubbing enables scrubbing
func init() {
// Scrubbing is enabled by default to prevent sensitive information
// (such as environment variables containing secrets) from leaking to logs.
_scrub.Store(true)
}

// SetScrubbing enables or disables scrubbing of potentially sensitive information from logging.
func SetScrubbing(enable bool) { _scrub.Store(enable) }

// IsScrubbingEnabled checks if scrubbing is enabled
Expand Down Expand Up @@ -174,6 +180,19 @@ func isRequestBase(m genMap) bool {
return a && c
}

// ScrubCreateOptions scrubs a JSON-encoded CreateOptions struct,
// removing sensitive fields (env vars, annotations) from the embedded OCI Spec.
func ScrubCreateOptions(b []byte) ([]byte, error) {
return scrubBytes(b, scrubCreateOptions)
}

func scrubCreateOptions(m genMap) error {
if spec, ok := index(m, "Spec"); ok {
return scrubOCISpec(spec)
}
return nil
}

// combination `m, ok := m[s]` and `m, ok := m.(genMap)`
func index(m genMap, s string) (genMap, bool) {
if m, ok := m[s]; ok {
Expand Down
Loading