backport of commit ae774b93d3 (#22955)

Co-authored-by: Peter Wilson <peter.wilson@hashicorp.com>
This commit is contained in:
hc-github-team-secure-vault-core
2023-09-11 05:12:00 -04:00
committed by GitHub
parent fc3fb91a40
commit 27491f82e4
8 changed files with 120 additions and 129 deletions

View File

@@ -13,8 +13,9 @@ import (
// getDefaultOptions returns options with their default values. // getDefaultOptions returns options with their default values.
func getDefaultOptions() options { func getDefaultOptions() options {
return options{ return options{
withNow: time.Now(), withNow: time.Now(),
withFormat: JSONFormat, withFormat: JSONFormat,
withHMACAccessor: true,
} }
} }
@@ -108,11 +109,7 @@ func WithFormat(f string) Option {
// WithPrefix provides an Option to represent a prefix for a file sink. // WithPrefix provides an Option to represent a prefix for a file sink.
func WithPrefix(prefix string) Option { func WithPrefix(prefix string) Option {
return func(o *options) error { return func(o *options) error {
prefix = strings.TrimSpace(prefix) o.withPrefix = prefix
if prefix != "" {
o.withPrefix = prefix
}
return nil return nil
} }

View File

@@ -211,9 +211,9 @@ func TestOptions_WithPrefix(t *testing.T) {
ExpectedValue: "", ExpectedValue: "",
}, },
"whitespace": { "whitespace": {
Value: " ", Value: " ",
IsErrorExpected: false, IsErrorExpected: false,
ExpectedErrorMessage: "", ExpectedValue: " ",
}, },
"valid": { "valid": {
Value: "test", Value: "test",

View File

@@ -98,7 +98,7 @@ func TestFormatJSON_formatRequest(t *testing.T) {
for name, tc := range cases { for name, tc := range cases {
var buf bytes.Buffer var buf bytes.Buffer
cfg, err := NewFormatterConfig() cfg, err := NewFormatterConfig(WithHMACAccessor(false))
require.NoError(t, err) require.NoError(t, err)
f, err := NewEntryFormatter(cfg, ss) f, err := NewEntryFormatter(cfg, ss)
require.NoError(t, err) require.NoError(t, err)

View File

@@ -22,6 +22,11 @@ import (
"github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/logical"
) )
const (
stdout = "stdout"
discard = "discard"
)
func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool, headersConfig audit.HeaderFormatter) (audit.Backend, error) { func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool, headersConfig audit.HeaderFormatter) (audit.Backend, error) {
if conf.SaltConfig == nil { if conf.SaltConfig == nil {
return nil, fmt.Errorf("nil salt config") return nil, fmt.Errorf("nil salt config")
@@ -39,53 +44,45 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
} }
// normalize path if configured for stdout // normalize path if configured for stdout
if strings.EqualFold(path, "stdout") { if strings.EqualFold(path, stdout) {
path = "stdout" path = stdout
} }
if strings.EqualFold(path, "discard") { if strings.EqualFold(path, discard) {
path = "discard" path = discard
} }
format, ok := conf.Config["format"] var cfgOpts []audit.Option
if !ok {
format = audit.JSONFormat.String() if format, ok := conf.Config["format"]; ok {
} cfgOpts = append(cfgOpts, audit.WithFormat(format))
switch format {
case audit.JSONFormat.String(), audit.JSONxFormat.String():
default:
return nil, fmt.Errorf("unknown format type %q", format)
} }
// Check if hashing of accessor is disabled // Check if hashing of accessor is disabled
hmacAccessor := true
if hmacAccessorRaw, ok := conf.Config["hmac_accessor"]; ok { if hmacAccessorRaw, ok := conf.Config["hmac_accessor"]; ok {
value, err := strconv.ParseBool(hmacAccessorRaw) v, err := strconv.ParseBool(hmacAccessorRaw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
hmacAccessor = value cfgOpts = append(cfgOpts, audit.WithHMACAccessor(v))
} }
// Check if raw logging is enabled // Check if raw logging is enabled
logRaw := false
if raw, ok := conf.Config["log_raw"]; ok { if raw, ok := conf.Config["log_raw"]; ok {
b, err := strconv.ParseBool(raw) v, err := strconv.ParseBool(raw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
logRaw = b cfgOpts = append(cfgOpts, audit.WithRaw(v))
} }
elideListResponses := false
if elideListResponsesRaw, ok := conf.Config["elide_list_responses"]; ok { if elideListResponsesRaw, ok := conf.Config["elide_list_responses"]; ok {
value, err := strconv.ParseBool(elideListResponsesRaw) v, err := strconv.ParseBool(elideListResponsesRaw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
elideListResponses = value cfgOpts = append(cfgOpts, audit.WithElision(v))
} }
// Check if mode is provided
mode := os.FileMode(0o600) mode := os.FileMode(0o600)
if modeRaw, ok := conf.Config["mode"]; ok { if modeRaw, ok := conf.Config["mode"]; ok {
m, err := strconv.ParseUint(modeRaw, 8, 32) m, err := strconv.ParseUint(modeRaw, 8, 32)
@@ -95,7 +92,7 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
switch m { switch m {
case 0: case 0:
// if mode is 0000, then do not modify file mode // if mode is 0000, then do not modify file mode
if path != "stdout" && path != "discard" { if path != stdout && path != discard {
fileInfo, err := os.Stat(path) fileInfo, err := os.Stat(path)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -107,12 +104,7 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
} }
} }
cfg, err := audit.NewFormatterConfig( cfg, err := audit.NewFormatterConfig(cfgOpts...)
audit.WithElision(elideListResponses),
audit.WithFormat(format),
audit.WithHMACAccessor(hmacAccessor),
audit.WithRaw(logRaw),
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -136,11 +128,13 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
return nil, fmt.Errorf("error creating formatter: %w", err) return nil, fmt.Errorf("error creating formatter: %w", err)
} }
var w audit.Writer var w audit.Writer
switch format { switch b.formatConfig.RequiredFormat {
case "json": case audit.JSONFormat:
w = &audit.JSONWriter{Prefix: conf.Config["prefix"]} w = &audit.JSONWriter{Prefix: conf.Config["prefix"]}
case "jsonx": case audit.JSONxFormat:
w = &audit.JSONxWriter{Prefix: conf.Config["prefix"]} w = &audit.JSONxWriter{Prefix: conf.Config["prefix"]}
default:
return nil, fmt.Errorf("unknown format type %q", b.formatConfig.RequiredFormat)
} }
fw, err := audit.NewEntryFormatterWriter(b.formatConfig, f, w) fw, err := audit.NewEntryFormatterWriter(b.formatConfig, f, w)
@@ -164,16 +158,24 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
var sinkNode eventlogger.Node var sinkNode eventlogger.Node
switch path { switch path {
case "stdout": case stdout:
sinkNode = &audit.SinkWrapper{Name: path, Sink: event.NewStdoutSinkNode(format)} sinkNode = &audit.SinkWrapper{Name: path, Sink: event.NewStdoutSinkNode(b.formatConfig.RequiredFormat.String())}
case "discard": case discard:
sinkNode = &audit.SinkWrapper{Name: path, Sink: event.NewNoopSink()} sinkNode = &audit.SinkWrapper{Name: path, Sink: event.NewNoopSink()}
default: default:
var err error var err error
var opts []event.Option
// Check if mode is provided
if modeRaw, ok := conf.Config["mode"]; ok {
opts = append(opts, event.WithFileMode(modeRaw))
}
// The NewFileSink function attempts to open the file and will // The NewFileSink function attempts to open the file and will
// return an error if it can't. // return an error if it can't.
n, err := event.NewFileSink(b.path, format, event.WithFileMode(strconv.FormatUint(uint64(mode), 8))) n, err := event.NewFileSink(
b.path,
b.formatConfig.RequiredFormat.String(), opts...)
if err != nil { if err != nil {
return nil, fmt.Errorf("file sink creation failed for path %q: %w", path, err) return nil, fmt.Errorf("file sink creation failed for path %q: %w", path, err)
} }
@@ -189,8 +191,8 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
b.nodeMap[sinkNodeID] = sinkNode b.nodeMap[sinkNodeID] = sinkNode
} else { } else {
switch path { switch path {
case "stdout": case stdout:
case "discard": case discard:
default: default:
// Ensure that the file can be successfully opened for writing; // Ensure that the file can be successfully opened for writing;
// otherwise it will be too late to catch later without problems // otherwise it will be too late to catch later without problems
@@ -257,9 +259,9 @@ func (b *Backend) Salt(ctx context.Context) (*salt.Salt, error) {
func (b *Backend) LogRequest(ctx context.Context, in *logical.LogInput) error { func (b *Backend) LogRequest(ctx context.Context, in *logical.LogInput) error {
var writer io.Writer var writer io.Writer
switch b.path { switch b.path {
case "stdout": case stdout:
writer = os.Stdout writer = os.Stdout
case "discard": case discard:
return nil return nil
} }
@@ -288,7 +290,7 @@ func (b *Backend) log(_ context.Context, buf *bytes.Buffer, writer io.Writer) er
if _, err := reader.WriteTo(writer); err == nil { if _, err := reader.WriteTo(writer); err == nil {
b.fileLock.Unlock() b.fileLock.Unlock()
return nil return nil
} else if b.path == "stdout" { } else if b.path == stdout {
b.fileLock.Unlock() b.fileLock.Unlock()
return err return err
} }
@@ -313,9 +315,9 @@ func (b *Backend) log(_ context.Context, buf *bytes.Buffer, writer io.Writer) er
func (b *Backend) LogResponse(ctx context.Context, in *logical.LogInput) error { func (b *Backend) LogResponse(ctx context.Context, in *logical.LogInput) error {
var writer io.Writer var writer io.Writer
switch b.path { switch b.path {
case "stdout": case stdout:
writer = os.Stdout writer = os.Stdout
case "discard": case discard:
return nil return nil
} }
@@ -337,9 +339,9 @@ func (b *Backend) LogTestMessage(ctx context.Context, in *logical.LogInput, conf
// Old behavior // Old behavior
var writer io.Writer var writer io.Writer
switch b.path { switch b.path {
case "stdout": case stdout:
writer = os.Stdout writer = os.Stdout
case "discard": case discard:
return nil return nil
} }
@@ -390,7 +392,7 @@ func (b *Backend) open() error {
func (b *Backend) Reload(_ context.Context) error { func (b *Backend) Reload(_ context.Context) error {
switch b.path { switch b.path {
case "stdout", "discard": case stdout, discard:
return nil return nil
} }

View File

@@ -12,9 +12,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/eventlogger" "github.com/hashicorp/eventlogger"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/vault/audit" "github.com/hashicorp/vault/audit"
"github.com/hashicorp/vault/internal/observability/event" "github.com/hashicorp/vault/internal/observability/event"
"github.com/hashicorp/vault/sdk/helper/salt" "github.com/hashicorp/vault/sdk/helper/salt"
@@ -38,7 +39,6 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
if !ok { if !ok {
socketType = "tcp" socketType = "tcp"
} }
writeDeadline, ok := conf.Config["write_timeout"] writeDeadline, ok := conf.Config["write_timeout"]
if !ok { if !ok {
writeDeadline = "2s" writeDeadline = "2s"
@@ -48,51 +48,39 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
return nil, err return nil, err
} }
format, ok := conf.Config["format"] var cfgOpts []audit.Option
if !ok {
format = audit.JSONFormat.String() if format, ok := conf.Config["format"]; ok {
} cfgOpts = append(cfgOpts, audit.WithFormat(format))
switch format {
case audit.JSONFormat.String(), audit.JSONxFormat.String():
default:
return nil, fmt.Errorf("unknown format type %q", format)
} }
// Check if hashing of accessor is disabled // Check if hashing of accessor is disabled
hmacAccessor := true
if hmacAccessorRaw, ok := conf.Config["hmac_accessor"]; ok { if hmacAccessorRaw, ok := conf.Config["hmac_accessor"]; ok {
value, err := strconv.ParseBool(hmacAccessorRaw) v, err := strconv.ParseBool(hmacAccessorRaw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
hmacAccessor = value cfgOpts = append(cfgOpts, audit.WithHMACAccessor(v))
} }
// Check if raw logging is enabled // Check if raw logging is enabled
logRaw := false
if raw, ok := conf.Config["log_raw"]; ok { if raw, ok := conf.Config["log_raw"]; ok {
b, err := strconv.ParseBool(raw) v, err := strconv.ParseBool(raw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
logRaw = b cfgOpts = append(cfgOpts, audit.WithRaw(v))
} }
elideListResponses := false
if elideListResponsesRaw, ok := conf.Config["elide_list_responses"]; ok { if elideListResponsesRaw, ok := conf.Config["elide_list_responses"]; ok {
value, err := strconv.ParseBool(elideListResponsesRaw) v, err := strconv.ParseBool(elideListResponsesRaw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
elideListResponses = value cfgOpts = append(cfgOpts, audit.WithElision(v))
} }
cfg, err := audit.NewFormatterConfig( cfg, err := audit.NewFormatterConfig(cfgOpts...)
audit.WithElision(elideListResponses),
audit.WithFormat(format),
audit.WithHMACAccessor(hmacAccessor),
audit.WithRaw(logRaw),
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -113,10 +101,10 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
return nil, fmt.Errorf("error creating formatter: %w", err) return nil, fmt.Errorf("error creating formatter: %w", err)
} }
var w audit.Writer var w audit.Writer
switch format { switch b.formatConfig.RequiredFormat {
case audit.JSONFormat.String(): case audit.JSONFormat:
w = &audit.JSONWriter{Prefix: conf.Config["prefix"]} w = &audit.JSONWriter{Prefix: conf.Config["prefix"]}
case audit.JSONxFormat.String(): case audit.JSONxFormat:
w = &audit.JSONxWriter{Prefix: conf.Config["prefix"]} w = &audit.JSONxWriter{Prefix: conf.Config["prefix"]}
} }
@@ -128,6 +116,16 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
b.formatter = fw b.formatter = fw
if useEventLogger { if useEventLogger {
var opts []event.Option
if socketType, ok := conf.Config["socket_type"]; ok {
opts = append(opts, event.WithSocketType(socketType))
}
if writeDeadline, ok := conf.Config["write_timeout"]; ok {
opts = append(opts, event.WithMaxDuration(writeDeadline))
}
b.nodeIDList = make([]eventlogger.NodeID, 2) b.nodeIDList = make([]eventlogger.NodeID, 2)
b.nodeMap = make(map[eventlogger.NodeID]eventlogger.Node) b.nodeMap = make(map[eventlogger.NodeID]eventlogger.Node)
@@ -138,7 +136,7 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
b.nodeIDList[0] = formatterNodeID b.nodeIDList[0] = formatterNodeID
b.nodeMap[formatterNodeID] = f b.nodeMap[formatterNodeID] = f
n, err := event.NewSocketSink(format, address, event.WithSocketType(socketType), event.WithMaxDuration(writeDuration.String())) n, err := event.NewSocketSink(b.formatConfig.RequiredFormat.String(), address, opts...)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating socket sink node: %w", err) return nil, fmt.Errorf("error creating socket sink node: %w", err)
} }

View File

@@ -39,57 +39,45 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
tag = "vault" tag = "vault"
} }
format, ok := conf.Config["format"] var cfgOpts []audit.Option
if !ok {
format = audit.JSONFormat.String() if format, ok := conf.Config["format"]; ok {
} cfgOpts = append(cfgOpts, audit.WithFormat(format))
switch format {
case audit.JSONFormat.String(), audit.JSONxFormat.String():
default:
return nil, fmt.Errorf("unknown format type %q", format)
} }
// Check if hashing of accessor is disabled // Check if hashing of accessor is disabled
hmacAccessor := true
if hmacAccessorRaw, ok := conf.Config["hmac_accessor"]; ok { if hmacAccessorRaw, ok := conf.Config["hmac_accessor"]; ok {
value, err := strconv.ParseBool(hmacAccessorRaw) v, err := strconv.ParseBool(hmacAccessorRaw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
hmacAccessor = value cfgOpts = append(cfgOpts, audit.WithHMACAccessor(v))
} }
// Check if raw logging is enabled // Check if raw logging is enabled
logRaw := false
if raw, ok := conf.Config["log_raw"]; ok { if raw, ok := conf.Config["log_raw"]; ok {
b, err := strconv.ParseBool(raw) v, err := strconv.ParseBool(raw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
logRaw = b cfgOpts = append(cfgOpts, audit.WithRaw(v))
} }
elideListResponses := false
if elideListResponsesRaw, ok := conf.Config["elide_list_responses"]; ok { if elideListResponsesRaw, ok := conf.Config["elide_list_responses"]; ok {
value, err := strconv.ParseBool(elideListResponsesRaw) v, err := strconv.ParseBool(elideListResponsesRaw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
elideListResponses = value cfgOpts = append(cfgOpts, audit.WithElision(v))
} }
// Get the logger cfg, err := audit.NewFormatterConfig(cfgOpts...)
logger, err := gsyslog.NewLogger(gsyslog.LOG_INFO, facility, tag)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cfg, err := audit.NewFormatterConfig( // Get the logger
audit.WithElision(elideListResponses), logger, err := gsyslog.NewLogger(gsyslog.LOG_INFO, facility, tag)
audit.WithFormat(format),
audit.WithHMACAccessor(hmacAccessor),
audit.WithRaw(logRaw),
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -108,10 +96,10 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
} }
var w audit.Writer var w audit.Writer
switch format { switch b.formatConfig.RequiredFormat {
case audit.JSONFormat.String(): case audit.JSONFormat:
w = &audit.JSONWriter{Prefix: conf.Config["prefix"]} w = &audit.JSONWriter{Prefix: conf.Config["prefix"]}
case audit.JSONxFormat.String(): case audit.JSONxFormat:
w = &audit.JSONxWriter{Prefix: conf.Config["prefix"]} w = &audit.JSONxWriter{Prefix: conf.Config["prefix"]}
} }
@@ -123,6 +111,17 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
b.formatter = fw b.formatter = fw
if useEventLogger { if useEventLogger {
var opts []event.Option
// Get facility or default to AUTH
if facility, ok := conf.Config["facility"]; ok {
opts = append(opts, event.WithFacility(facility))
}
if tag, ok := conf.Config["tag"]; ok {
opts = append(opts, event.WithTag(tag))
}
b.nodeIDList = make([]eventlogger.NodeID, 2) b.nodeIDList = make([]eventlogger.NodeID, 2)
b.nodeMap = make(map[eventlogger.NodeID]eventlogger.Node) b.nodeMap = make(map[eventlogger.NodeID]eventlogger.Node)
@@ -133,7 +132,7 @@ func Factory(ctx context.Context, conf *audit.BackendConfig, useEventLogger bool
b.nodeIDList[0] = formatterNodeID b.nodeIDList[0] = formatterNodeID
b.nodeMap[formatterNodeID] = f b.nodeMap[formatterNodeID] = f
n, err := event.NewSyslogSink(format, event.WithFacility(facility), event.WithTag(tag)) n, err := event.NewSyslogSink(b.formatConfig.RequiredFormat.String(), opts...)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating syslog sink node: %w", err) return nil, fmt.Errorf("error creating syslog sink node: %w", err)
} }

View File

@@ -32,12 +32,15 @@ type options struct {
// getDefaultOptions returns Options with their default values. // getDefaultOptions returns Options with their default values.
func getDefaultOptions() options { func getDefaultOptions() options {
fileMode := os.FileMode(0o600)
return options{ return options{
withNow: time.Now(), withNow: time.Now(),
withFacility: "AUTH", withFacility: "AUTH",
withTag: "vault", withTag: "vault",
withSocketType: "tcp", withSocketType: "tcp",
withMaxDuration: 2 * time.Second, withMaxDuration: 2 * time.Second,
withFileMode: &fileMode,
} }
} }
@@ -110,11 +113,7 @@ func WithNow(now time.Time) Option {
// WithFacility provides an Option to represent a 'facility' for a syslog sink. // WithFacility provides an Option to represent a 'facility' for a syslog sink.
func WithFacility(facility string) Option { func WithFacility(facility string) Option {
return func(o *options) error { return func(o *options) error {
facility = strings.TrimSpace(facility) o.withFacility = facility
if facility != "" {
o.withFacility = facility
}
return nil return nil
} }
@@ -123,11 +122,7 @@ func WithFacility(facility string) Option {
// WithTag provides an Option to represent a 'tag' for a syslog sink. // WithTag provides an Option to represent a 'tag' for a syslog sink.
func WithTag(tag string) Option { func WithTag(tag string) Option {
return func(o *options) error { return func(o *options) error {
tag = strings.TrimSpace(tag) o.withTag = tag
if tag != "" {
o.withTag = tag
}
return nil return nil
} }

View File

@@ -205,7 +205,7 @@ func TestOptions_WithFacility(t *testing.T) {
}, },
"whitespace": { "whitespace": {
Value: " ", Value: " ",
ExpectedValue: "", ExpectedValue: " ",
}, },
"value": { "value": {
Value: "juan", Value: "juan",
@@ -213,7 +213,7 @@ func TestOptions_WithFacility(t *testing.T) {
}, },
"spacey-value": { "spacey-value": {
Value: " juan ", Value: " juan ",
ExpectedValue: "juan", ExpectedValue: " juan ",
}, },
} }
@@ -243,7 +243,7 @@ func TestOptions_WithTag(t *testing.T) {
}, },
"whitespace": { "whitespace": {
Value: " ", Value: " ",
ExpectedValue: "", ExpectedValue: " ",
}, },
"value": { "value": {
Value: "juan", Value: "juan",
@@ -251,7 +251,7 @@ func TestOptions_WithTag(t *testing.T) {
}, },
"spacey-value": { "spacey-value": {
Value: " juan ", Value: " juan ",
ExpectedValue: "juan", ExpectedValue: " juan ",
}, },
} }