Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listeners: Redaction only for TCP #23592

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -886,9 +886,9 @@ func (c *ServerCommand) InitListeners(config *server.Config, disableClustering b
}

if reloadFunc != nil {
relSlice := (*c.reloadFuncs)["listener|"+lnConfig.Type]
relSlice := (*c.reloadFuncs)["listener|"+lnConfig.Type.String()]
relSlice = append(relSlice, reloadFunc)
(*c.reloadFuncs)["listener|"+lnConfig.Type] = relSlice
(*c.reloadFuncs)["listener|"+lnConfig.Type.String()] = relSlice
}

if !disableClustering && lnConfig.Type == "tcp" {
Expand Down
33 changes: 25 additions & 8 deletions command/server/config_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,15 @@ listener "tcp" {
redact_addresses = true
redact_cluster_name = true
redact_version = true
}
listener "unix" {
address = "/var/run/vault.sock"
socket_mode = "644"
socket_user = "1000"
socket_group = "1000"
redact_addresses = true
redact_cluster_name = true
redact_version = true
}`))

config := Config{
Expand All @@ -903,16 +912,14 @@ listener "tcp" {
config.Listeners = listeners
// Track which types of listener were found.
for _, l := range config.Listeners {
config.found(l.Type, l.Type)
config.found(l.Type.String(), l.Type.String())
}

if len(config.Listeners) == 0 {
t.Fatalf("expected at least one listener in the config")
}
listener := config.Listeners[0]
if listener.Type != "tcp" {
t.Fatalf("expected tcp listener in the config")
}
require.Len(t, config.Listeners, 2)
tcpListener := config.Listeners[0]
require.Equal(t, configutil.TCP, tcpListener.Type)
unixListner := config.Listeners[1]
require.Equal(t, configutil.Unix, unixListner.Type)

expected := &Config{
SharedConfig: &configutil.SharedConfig{
Expand Down Expand Up @@ -946,6 +953,16 @@ listener "tcp" {
RedactClusterName: true,
RedactVersion: true,
},
{
Type: "unix",
Address: "/var/run/vault.sock",
SocketMode: "644",
SocketUser: "1000",
SocketGroup: "1000",
RedactAddresses: false,
RedactClusterName: false,
RedactVersion: false,
},
},
},
}
Expand Down
2 changes: 1 addition & 1 deletion command/server/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var BuiltinListeners = map[string]ListenerFactory{
// NewListener creates a new listener of the given type with the given
// configuration. The type is looked up in the BuiltinListeners map.
func NewListener(l *configutil.Listener, logger io.Writer, ui cli.Ui) (net.Listener, map[string]string, reloadutil.ReloadFunc, error) {
f, ok := BuiltinListeners[l.Type]
f, ok := BuiltinListeners[l.Type.String()]
peteski22 marked this conversation as resolved.
Show resolved Hide resolved
if !ok {
return nil, nil, nil, fmt.Errorf("unknown listener type: %q", l.Type)
}
Expand Down
2 changes: 1 addition & 1 deletion internalshared/configutil/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func ParseConfig(d string) (*SharedConfig, error) {

// Track which types of listener were found.
for _, l := range result.Listeners {
result.found(l.Type, l.Type)
result.found(l.Type.String(), l.Type.String())
}
}

Expand Down
51 changes: 41 additions & 10 deletions internalshared/configutil/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ import (
"github.com/hashicorp/vault/helper/namespace"
)

const (
TCP listenerType = "tcp"
Unix listenerType = "unix"
)

// listenerType represents the supported types of listener.
type listenerType string
peteski22 marked this conversation as resolved.
Show resolved Hide resolved

type ListenerTelemetry struct {
UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
UnauthenticatedMetricsAccess bool `hcl:"-"`
Expand All @@ -45,7 +53,7 @@ type Listener struct {
UnusedKeys UnusedKeyMap `hcl:",unusedKeyPositions"`
RawConfig map[string]interface{}

Type string
Type listenerType
Purpose []string `hcl:"-"`
PurposeRaw interface{} `hcl:"purpose"`
Role string `hcl:"role"`
Expand Down Expand Up @@ -254,6 +262,11 @@ func parseListener(item *ast.ObjectItem) (*Listener, error) {
return l, nil
}

// String returns the string version of a listener type.
func (t listenerType) String() string {
return string(t)
}

// parseChrootNamespace attempts to parse the raw listener chroot namespace settings.
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
Expand All @@ -279,27 +292,28 @@ func (l *Listener) parseChrootNamespaceSettings() error {
// The state of the listener will be modified.
func (l *Listener) parseType(fallback string) error {
switch {
case l.Type != "":
case l.Type.String() != "":
case fallback != "":
default:
return errors.New("listener type must be specified")
}

// Use type if available, otherwise fall back.
result := l.Type
if result == "" {
result = fallback
rawType := l.Type
if rawType == "" {
peteski22 marked this conversation as resolved.
Show resolved Hide resolved
rawType = listenerType(fallback)
}
result = strings.ToLower(result)

parsedType := listenerType(strings.ToLower(rawType.String()))
peteski22 marked this conversation as resolved.
Show resolved Hide resolved

// Sanity check the values
switch result {
case "tcp", "unix":
switch parsedType {
case TCP, Unix:
default:
return fmt.Errorf("unsupported listener type %q", result)
return fmt.Errorf("unsupported listener type %q", parsedType.String())
peteski22 marked this conversation as resolved.
Show resolved Hide resolved
}

l.Type = result
l.Type = parsedType

return nil
}
Expand Down Expand Up @@ -396,6 +410,13 @@ func (l *Listener) parseTLSSettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseHTTPHeaderSettings() error {
// Custom response headers are only supported by TCP listeners.
// Clear raw data and return early if it was something else.
if l.Type != TCP {
l.CustomResponseHeadersRaw = nil
return nil
}

// if CustomResponseHeadersRaw is nil, we still need to set the default headers
customHeadersMap, err := ParseCustomResponseHeaders(l.CustomResponseHeadersRaw)
if err != nil {
Expand Down Expand Up @@ -604,6 +625,16 @@ func (l *Listener) parseCORSSettings() error {
// The state of the listener will be modified, raw data will be cleared upon
// successful parsing.
func (l *Listener) parseRedactionSettings() error {
// Redaction is only supported on TCP listeners.
// Clear raw data and return early if it was something else.
if l.Type != TCP {
l.RedactAddressesRaw = nil
l.RedactClusterNameRaw = nil
l.RedactVersionRaw = nil

return nil
}

var err error

if l.RedactAddressesRaw != nil {
Expand Down
40 changes: 38 additions & 2 deletions internalshared/configutil/listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,15 @@ func TestListener_parseType(t *testing.T) {
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
l := &Listener{Type: tc.inputType}
l := &Listener{Type: listenerType(tc.inputType)}
err := l.parseType(tc.inputFallback)
switch {
case tc.isErrorExpected:
require.Error(t, err)
require.ErrorContains(t, err, tc.errorMessage)
default:
require.NoError(t, err)
require.Equal(t, tc.expectedValue, l.Type)
require.Equal(t, tc.expectedValue, l.Type.String())
}
})
}
Expand Down Expand Up @@ -861,23 +861,27 @@ func TestListener_parseCORSSettings(t *testing.T) {
// assign the relevant value on the SharedConfig struct.
func TestListener_parseHTTPHeaderSettings(t *testing.T) {
tests := map[string]struct {
listenerType listenerType
rawCustomResponseHeaders []map[string]any
expectedNumCustomResponseHeaders int
isErrorExpected bool
errorMessage string
}{
"nil": {
listenerType: TCP,
isErrorExpected: false,
expectedNumCustomResponseHeaders: 1, // default: Strict-Transport-Security
},
"custom-headers-bad": {
listenerType: TCP,
rawCustomResponseHeaders: []map[string]any{
{"juan": false},
},
isErrorExpected: true,
errorMessage: "failed to parse custom_response_headers",
},
"custom-headers-good": {
listenerType: TCP,
rawCustomResponseHeaders: []map[string]any{
{
"2xx": []map[string]any{
Expand All @@ -888,6 +892,18 @@ func TestListener_parseHTTPHeaderSettings(t *testing.T) {
expectedNumCustomResponseHeaders: 2,
isErrorExpected: false,
},
"unix-no-headers": {
listenerType: Unix,
rawCustomResponseHeaders: []map[string]any{
{
"2xx": []map[string]any{
{"X-Custom-Header": []any{"Custom Header Value 1", "Custom Header Value 2"}},
},
},
},
expectedNumCustomResponseHeaders: 0,
isErrorExpected: false,
},
}

for name, tc := range tests {
Expand All @@ -898,6 +914,7 @@ func TestListener_parseHTTPHeaderSettings(t *testing.T) {

// Configure listener with raw values
l := &Listener{
Type: tc.listenerType,
CustomResponseHeadersRaw: tc.rawCustomResponseHeaders,
}

Expand Down Expand Up @@ -978,6 +995,7 @@ func TestListener_parseChrootNamespaceSettings(t *testing.T) {
// assign the relevant value on the SharedConfig struct.
func TestListener_parseRedactionSettings(t *testing.T) {
tests := map[string]struct {
listenerType listenerType
rawRedactAddresses any
expectedRedactAddresses bool
rawRedactClusterName any
Expand All @@ -988,41 +1006,58 @@ func TestListener_parseRedactionSettings(t *testing.T) {
errorMessage string
}{
"missing": {
listenerType: TCP,
isErrorExpected: false,
expectedRedactAddresses: false,
expectedRedactClusterName: false,
expectedRedactVersion: false,
},
"redact-addresses-bad": {
listenerType: TCP,
rawRedactAddresses: "juan",
isErrorExpected: true,
errorMessage: "invalid value for redact_addresses",
},
"redact-addresses-good": {
listenerType: TCP,
rawRedactAddresses: "true",
expectedRedactAddresses: true,
isErrorExpected: false,
},
"redact-cluster-name-bad": {
listenerType: TCP,
rawRedactClusterName: "juan",
isErrorExpected: true,
errorMessage: "invalid value for redact_cluster_name",
},
"redact-cluster-name-good": {
listenerType: TCP,
rawRedactClusterName: "true",
expectedRedactClusterName: true,
isErrorExpected: false,
},
"redact-version-bad": {
listenerType: TCP,
rawRedactVersion: "juan",
isErrorExpected: true,
errorMessage: "invalid value for redact_version",
},
"redact-version-good": {
listenerType: TCP,
rawRedactVersion: "true",
expectedRedactVersion: true,
isErrorExpected: false,
},
"redact-unix-na": {
listenerType: Unix,
rawRedactAddresses: "true",
expectedRedactAddresses: false,
rawRedactClusterName: "true",
expectedRedactClusterName: false,
rawRedactVersion: "true",
expectedRedactVersion: false,
isErrorExpected: false,
},
}

for name, tc := range tests {
Expand All @@ -1033,6 +1068,7 @@ func TestListener_parseRedactionSettings(t *testing.T) {

// Configure listener with raw values
l := &Listener{
Type: tc.listenerType,
RedactAddressesRaw: tc.rawRedactAddresses,
RedactClusterNameRaw: tc.rawRedactClusterName,
RedactVersionRaw: tc.rawRedactVersion,
Expand Down
Loading