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
}
opts, err := getOpts(opt...)
var tokenPresent bool
token := r.Header.Get(consts.AuthHeaderName)
if opts.withRedactVersion {
body.Version = opts.withRedactionValue
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(r.Context(), token)
lock.Unlock()
tokenPresent = err == nil && tokenEntry != nil
}
opts, _ := getOpts(opt...)
if opts.withRedactClusterName {
body.ClusterName = opts.withRedactionValue
if !tokenPresent {
if opts.withRedactVersion {
body.Version = opts.withRedactionValue
}
if opts.withRedactClusterName {
body.ClusterName = opts.withRedactionValue
}
}
w.Header().Set("Content-Type", "application/json")

View File

@@ -4,9 +4,9 @@
package http
import (
"context"
"net/http"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/logical"
"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) {
switch r.Method {
case "GET":
handleSysLeaderGet(core, w, opt...)
handleSysLeaderGet(core, w, r, opt...)
default:
respondError(w, http.StatusMethodNotAllowed, nil)
}
})
}
func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, opt ...ListenerConfigOption) {
ctx := context.Background()
func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, r *http.Request, opt ...ListenerConfigOption) {
var tokenPresent bool
token := r.Header.Get(consts.AuthHeaderName)
ctx := r.Context()
opts, _ := getOpts(opt...)
if opts.withRedactAddresses {
ctx = logical.CreateContextRedactionSettings(ctx, false, true, false)
if token != "" {
// We don't care about the error, we just want to know if token exists
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)

View File

@@ -98,7 +98,7 @@ func handleSysUnseal(core *vault.Core) http.Handler {
return
}
core.ResetUnsealProcess()
handleSysSealStatusRaw(core, w)
handleSysSealStatusRaw(core, w, r)
return
}
@@ -148,7 +148,7 @@ func handleSysUnseal(core *vault.Core) http.Handler {
}
// 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
}
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) {
ctx := context.Background()
func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Request, opt ...ListenerConfigOption) {
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)
if err != nil {
respondError(w, http.StatusInternalServerError, err)
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)
}
@@ -203,7 +208,6 @@ func handleSysSealBackendStatusRaw(core *vault.Core, w http.ResponseWriter, r *h
respondError(w, http.StatusInternalServerError, err)
return
}
respondOk(w, status)
}

View File

@@ -15,11 +15,18 @@ import (
"testing"
"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/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/vault"
"github.com/hashicorp/vault/vault/seal"
"github.com/hashicorp/vault/version"
"github.com/stretchr/testify/assert"
)
func TestSysSealStatus(t *testing.T) {
@@ -556,3 +563,64 @@ func TestSysStepDown(t *testing.T) {
resp := testHttpPut(t, token, addr+"/v1/sys/step-down", nil)
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["address"] = fmt.Sprintf("%s:%d", "0.0.0.0", config.Port)
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)
portStr := fmt.Sprintf("%d/tcp", config.Port)
if strutil.StrListContains(ports, portStr) {

View File

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

View File

@@ -743,6 +743,10 @@ func (c *Core) HAStateWithLock() consts.HAState {
return c.HAState()
}
func (c *Core) HALock() sync.Locker {
return c.stateLock.RLocker()
}
// CoreConfig is used to parameterize a core
type CoreConfig struct {
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) {
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)
if err != nil {
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) {
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)
if err != nil {
return nil, err