Redacted Information With Valid Token (#25735)

This commit is contained in:
divyaac
2024-03-01 10:20:31 -08:00
committed by GitHub
parent 8cbab3b09f
commit c467620740
8 changed files with 160 additions and 32 deletions

View File

@@ -57,14 +57,27 @@ func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request
return return
} }
opts, err := getOpts(opt...) var tokenPresent bool
token := r.Header.Get(consts.AuthHeaderName)
if opts.withRedactVersion { if token != "" {
body.Version = opts.withRedactionValue // We don't care about the error, we just want to know if the token exists
lock := core.HALock()
lock.Lock()
tokenEntry, err := core.LookupToken(r.Context(), token)
lock.Unlock()
tokenPresent = err == nil && tokenEntry != nil
} }
opts, _ := getOpts(opt...)
if opts.withRedactClusterName { if !tokenPresent {
body.ClusterName = opts.withRedactionValue if opts.withRedactVersion {
body.Version = opts.withRedactionValue
}
if opts.withRedactClusterName {
body.ClusterName = opts.withRedactionValue
}
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@@ -4,9 +4,9 @@
package http package http
import ( import (
"context"
"net/http" "net/http"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault" "github.com/hashicorp/vault/vault"
) )
@@ -17,19 +17,29 @@ func handleSysLeader(core *vault.Core, opt ...ListenerConfigOption) http.Handler
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method { switch r.Method {
case "GET": case "GET":
handleSysLeaderGet(core, w, opt...) handleSysLeaderGet(core, w, r, opt...)
default: default:
respondError(w, http.StatusMethodNotAllowed, nil) respondError(w, http.StatusMethodNotAllowed, nil)
} }
}) })
} }
func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, opt ...ListenerConfigOption) { func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, r *http.Request, opt ...ListenerConfigOption) {
ctx := context.Background() var tokenPresent bool
token := r.Header.Get(consts.AuthHeaderName)
ctx := r.Context()
opts, _ := getOpts(opt...) if token != "" {
if opts.withRedactAddresses { // We don't care about the error, we just want to know if token exists
ctx = logical.CreateContextRedactionSettings(ctx, false, true, false) lock := core.HALock()
lock.Lock()
tokenEntry, err := core.LookupToken(ctx, token)
lock.Unlock()
tokenPresent = err == nil && tokenEntry != nil
}
if tokenPresent {
ctx = logical.CreateContextRedactionSettings(r.Context(), false, false, false)
} }
resp, err := core.GetLeaderStatus(ctx) resp, err := core.GetLeaderStatus(ctx)

View File

@@ -98,7 +98,7 @@ func handleSysUnseal(core *vault.Core) http.Handler {
return return
} }
core.ResetUnsealProcess() core.ResetUnsealProcess()
handleSysSealStatusRaw(core, w) handleSysSealStatusRaw(core, w, r)
return return
} }
@@ -148,7 +148,7 @@ func handleSysUnseal(core *vault.Core) http.Handler {
} }
// Return the seal status // Return the seal status
handleSysSealStatusRaw(core, w) handleSysSealStatusRaw(core, w, r)
}) })
} }
@@ -159,7 +159,7 @@ func handleSysSealStatus(core *vault.Core, opt ...ListenerConfigOption) http.Han
return return
} }
handleSysSealStatusRaw(core, w, opt...) handleSysSealStatusRaw(core, w, r, opt...)
}) })
} }
@@ -174,25 +174,30 @@ func handleSysSealBackendStatus(core *vault.Core) http.Handler {
}) })
} }
func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, opt ...ListenerConfigOption) { func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Request, opt ...ListenerConfigOption) {
ctx := context.Background() ctx := r.Context()
var tokenPresent bool
token := r.Header.Get(consts.AuthHeaderName)
if token != "" {
// We don't care about the error, we just want to know if the token exists
lock := core.HALock()
lock.Lock()
tokenEntry, err := core.LookupToken(ctx, token)
lock.Unlock()
tokenPresent = err == nil && tokenEntry != nil
}
// If there are is no valid token then we will redact the specified values
if tokenPresent {
ctx = logical.CreateContextRedactionSettings(ctx, false, false, false)
}
status, err := core.GetSealStatus(ctx, true) status, err := core.GetSealStatus(ctx, true)
if err != nil { if err != nil {
respondError(w, http.StatusInternalServerError, err) respondError(w, http.StatusInternalServerError, err)
return return
} }
opts, err := getOpts(opt...)
if opts.withRedactVersion {
status.Version = opts.withRedactionValue
status.BuildDate = opts.withRedactionValue
}
if opts.withRedactClusterName {
status.ClusterName = opts.withRedactionValue
}
respondOk(w, status) respondOk(w, status)
} }
@@ -203,7 +208,6 @@ func handleSysSealBackendStatusRaw(core *vault.Core, w http.ResponseWriter, r *h
respondError(w, http.StatusInternalServerError, err) respondError(w, http.StatusInternalServerError, err)
return return
} }
respondOk(w, status) respondOk(w, status)
} }

View File

@@ -15,11 +15,18 @@ import (
"testing" "testing"
"github.com/go-test/deep" "github.com/go-test/deep"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/audit"
auditFile "github.com/hashicorp/vault/builtin/audit/file"
"github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/logical" "github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault" "github.com/hashicorp/vault/vault"
"github.com/hashicorp/vault/vault/seal" "github.com/hashicorp/vault/vault/seal"
"github.com/hashicorp/vault/version" "github.com/hashicorp/vault/version"
"github.com/stretchr/testify/assert"
) )
func TestSysSealStatus(t *testing.T) { func TestSysSealStatus(t *testing.T) {
@@ -556,3 +563,64 @@ func TestSysStepDown(t *testing.T) {
resp := testHttpPut(t, token, addr+"/v1/sys/step-down", nil) resp := testHttpPut(t, token, addr+"/v1/sys/step-down", nil)
testResponseStatus(t, resp, 204) testResponseStatus(t, resp, 204)
} }
// TestSysSealStatusRedaction tests that the response from a
// a request to sys/seal-status are redacted only if no valid token
// is provided with the request
func TestSysSealStatusRedaction(t *testing.T) {
conf := &vault.CoreConfig{
EnableUI: false,
EnableRaw: true,
BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(),
AuditBackends: map[string]audit.Factory{
"file": auditFile.Factory,
},
}
core, _, token := vault.TestCoreUnsealedWithConfig(t, conf)
// Setup new custom listener
ln, addr := TestListener(t)
props := &vault.HandlerProperties{
Core: core,
ListenerConfig: &configutil.Listener{
RedactVersion: true,
},
}
TestServerWithListenerAndProperties(t, ln, addr, core, props)
defer ln.Close()
TestServerAuth(t, addr, token)
client := cleanhttp.DefaultClient()
// Check seal-status
req, err := http.NewRequest("GET", addr+"/v1/sys/seal-status", nil)
if err != nil {
t.Fatalf("err: %s", err)
}
req.Header.Set(consts.AuthHeaderName, token)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("err: %s", err)
}
testResponseStatus(t, resp, 200)
// Verify that version exists when provided a valid token
var actual map[string]interface{}
testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual)
assert.NotEmpty(t, actual["version"])
// Verify that version is redacted when no token is provided
req, err = http.NewRequest("GET", addr+"/v1/sys/seal-status", nil)
if err != nil {
t.Fatalf("err: %s", err)
}
req.Header.Set(consts.AuthHeaderName, "")
resp, err = client.Do(req)
if err != nil {
t.Fatalf("err: %s", err)
}
testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual)
assert.Empty(t, actual["version"])
}

View File

@@ -640,6 +640,9 @@ func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOption
listener := cfg["tcp"].(map[string]interface{}) listener := cfg["tcp"].(map[string]interface{})
listener["address"] = fmt.Sprintf("%s:%d", "0.0.0.0", config.Port) listener["address"] = fmt.Sprintf("%s:%d", "0.0.0.0", config.Port)
listener["chroot_namespace"] = config.ChrootNamespace listener["chroot_namespace"] = config.ChrootNamespace
listener["redact_addresses"] = config.RedactAddresses
listener["redact_cluster_name"] = config.RedactClusterName
listener["redact_version"] = config.RedactVersion
listenerConfig = append(listenerConfig, cfg) listenerConfig = append(listenerConfig, cfg)
portStr := fmt.Sprintf("%d/tcp", config.Port) portStr := fmt.Sprintf("%d/tcp", config.Port)
if strutil.StrListContains(ports, portStr) { if strutil.StrListContains(ports, portStr) {

View File

@@ -105,8 +105,11 @@ type ClusterOptions struct {
} }
type VaultNodeListenerConfig struct { type VaultNodeListenerConfig struct {
Port int Port int
ChrootNamespace string ChrootNamespace string
RedactAddresses bool
RedactClusterName bool
RedactVersion bool
} }
type CA struct { type CA struct {

View File

@@ -743,6 +743,10 @@ func (c *Core) HAStateWithLock() consts.HAState {
return c.HAState() return c.HAState()
} }
func (c *Core) HALock() sync.Locker {
return c.stateLock.RLocker()
}
// CoreConfig is used to parameterize a core // CoreConfig is used to parameterize a core
type CoreConfig struct { type CoreConfig struct {
entCoreConfig entCoreConfig

View File

@@ -5675,6 +5675,17 @@ func (core *Core) GetLeaderStatusLocked(ctx context.Context) (*LeaderResponse, e
} }
func (b *SystemBackend) handleSealStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { func (b *SystemBackend) handleSealStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
var tokenPresent bool
token := req.ClientToken
if token != "" {
// We don't care about the error, we just want to know if the token exists
_, tokenEntry, _, _, err := b.Core.fetchACLTokenEntryAndEntity(ctx, req)
tokenPresent = err == nil && tokenEntry != nil
}
// If there is a valid token then we will not redact any values
if tokenPresent {
ctx = logical.CreateContextRedactionSettings(ctx, false, false, false)
}
status, err := b.Core.GetSealStatus(ctx, false) status, err := b.Core.GetSealStatus(ctx, false)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -5694,6 +5705,18 @@ func (b *SystemBackend) handleSealStatus(ctx context.Context, req *logical.Reque
} }
func (b *SystemBackend) handleLeaderStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { func (b *SystemBackend) handleLeaderStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
var tokenPresent bool
token := req.ClientToken
if token != "" {
// We don't care about the error, we just want to know if token exists
_, tokenEntry, _, _, err := b.Core.fetchACLTokenEntryAndEntity(ctx, req)
tokenPresent = err == nil && tokenEntry != nil
}
if tokenPresent {
ctx = logical.CreateContextRedactionSettings(ctx, false, false, false)
}
status, err := b.Core.GetLeaderStatusLocked(ctx) status, err := b.Core.GetLeaderStatusLocked(ctx)
if err != nil { if err != nil {
return nil, err return nil, err