mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27:54 +00:00
Added flag to disable X-Vault-Token header proxy if client passes the token (#8101)
* Added flag to disable X-Vault-Token header proxy if client passes the token * Reveresed the flag value to better match the name intent * Introduced UseAutoAuthTokenRaw for Cache to support triplicate value of true/false/force Co-authored-by: Clint <catsby@users.noreply.github.com>
This commit is contained in:
@@ -464,8 +464,10 @@ func (c *AgentCommand) Run(args []string) int {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var proxyVaultToken = !config.Cache.UseAutoAuthTokenEnforce
|
||||||
|
|
||||||
// Create the request handler
|
// Create the request handler
|
||||||
cacheHandler := cache.Handler(ctx, cacheLogger, leaseCache, inmemSink)
|
cacheHandler := cache.Handler(ctx, cacheLogger, leaseCache, inmemSink, proxyVaultToken)
|
||||||
|
|
||||||
var listeners []net.Listener
|
var listeners []net.Listener
|
||||||
for i, lnConfig := range config.Listeners {
|
for i, lnConfig := range config.Listeners {
|
||||||
|
|||||||
61
command/agent/cache/cache_test.go
vendored
61
command/agent/cache/cache_test.go
vendored
@@ -152,7 +152,7 @@ func setupClusterAndAgentCommon(ctx context.Context, t *testing.T, coreConfig *v
|
|||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle("/agent/v1/cache-clear", leaseCache.HandleCacheClear(ctx))
|
mux.Handle("/agent/v1/cache-clear", leaseCache.HandleCacheClear(ctx))
|
||||||
|
|
||||||
mux.Handle("/", Handler(ctx, cacheLogger, leaseCache, nil))
|
mux.Handle("/", Handler(ctx, cacheLogger, leaseCache, nil, true))
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: mux,
|
Handler: mux,
|
||||||
ReadHeaderTimeout: 10 * time.Second,
|
ReadHeaderTimeout: 10 * time.Second,
|
||||||
@@ -243,7 +243,7 @@ func TestCache_AutoAuthTokenStripping(t *testing.T) {
|
|||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
||||||
|
|
||||||
mux.Handle("/", Handler(ctx, cacheLogger, leaseCache, mock.NewSink("testid")))
|
mux.Handle("/", Handler(ctx, cacheLogger, leaseCache, mock.NewSink("testid"), true))
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: mux,
|
Handler: mux,
|
||||||
ReadHeaderTimeout: 10 * time.Second,
|
ReadHeaderTimeout: 10 * time.Second,
|
||||||
@@ -281,6 +281,63 @@ func TestCache_AutoAuthTokenStripping(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCache_AutoAuthClientTokenProxyStripping(t *testing.T) {
|
||||||
|
leaseCache := &mockTokenVerifierProxier{}
|
||||||
|
dummyToken := "DUMMY"
|
||||||
|
realToken := "testid"
|
||||||
|
|
||||||
|
cluster := vault.NewTestCluster(t, nil, &vault.TestClusterOptions{
|
||||||
|
HandlerFunc: vaulthttp.Handler,
|
||||||
|
})
|
||||||
|
cluster.Start()
|
||||||
|
defer cluster.Cleanup()
|
||||||
|
|
||||||
|
cores := cluster.Cores
|
||||||
|
vault.TestWaitActive(t, cores[0].Core)
|
||||||
|
client := cores[0].Client
|
||||||
|
|
||||||
|
cacheLogger := logging.NewVaultLogger(hclog.Trace).Named("cache")
|
||||||
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := namespace.RootContext(nil)
|
||||||
|
|
||||||
|
// Create a muxer and add paths relevant for the lease cache layer
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
//mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
||||||
|
|
||||||
|
mux.Handle("/", Handler(ctx, cacheLogger, leaseCache, mock.NewSink(realToken), false))
|
||||||
|
server := &http.Server{
|
||||||
|
Handler: mux,
|
||||||
|
ReadHeaderTimeout: 10 * time.Second,
|
||||||
|
ReadTimeout: 30 * time.Second,
|
||||||
|
IdleTimeout: 5 * time.Minute,
|
||||||
|
ErrorLog: cacheLogger.StandardLogger(nil),
|
||||||
|
}
|
||||||
|
go server.Serve(listener)
|
||||||
|
|
||||||
|
testClient, err := client.Clone()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := testClient.SetAddress("http://" + listener.Addr().String()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty the token in the client. Auto-auth token should be put to use.
|
||||||
|
testClient.SetToken(dummyToken)
|
||||||
|
_, err = testClient.Auth().Token().LookupSelf()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if leaseCache.currentToken != realToken {
|
||||||
|
t.Fatalf("failed to use real token from auto-auth")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCache_ConcurrentRequests(t *testing.T) {
|
func TestCache_ConcurrentRequests(t *testing.T) {
|
||||||
coreConfig := &vault.CoreConfig{
|
coreConfig := &vault.CoreConfig{
|
||||||
DisableMlock: true,
|
DisableMlock: true,
|
||||||
|
|||||||
7
command/agent/cache/handler.go
vendored
7
command/agent/cache/handler.go
vendored
@@ -20,11 +20,16 @@ import (
|
|||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Handler(ctx context.Context, logger hclog.Logger, proxier Proxier, inmemSink sink.Sink) http.Handler {
|
func Handler(ctx context.Context, logger hclog.Logger, proxier Proxier, inmemSink sink.Sink, proxyVaultToken bool) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
logger.Info("received request", "method", r.Method, "path", r.URL.Path)
|
logger.Info("received request", "method", r.Method, "path", r.URL.Path)
|
||||||
|
|
||||||
|
if !proxyVaultToken {
|
||||||
|
r.Header.Del(consts.AuthHeaderName)
|
||||||
|
}
|
||||||
|
|
||||||
token := r.Header.Get(consts.AuthHeaderName)
|
token := r.Header.Get(consts.AuthHeaderName)
|
||||||
|
|
||||||
if token == "" && inmemSink != nil {
|
if token == "" && inmemSink != nil {
|
||||||
logger.Debug("using auto auth token", "method", r.Method, "path", r.URL.Path)
|
logger.Debug("using auto auth token", "method", r.Method, "path", r.URL.Path)
|
||||||
token = inmemSink.(sink.SinkReader).Token()
|
token = inmemSink.(sink.SinkReader).Token()
|
||||||
|
|||||||
16
command/agent/cache/testing.go
vendored
16
command/agent/cache/testing.go
vendored
@@ -64,3 +64,19 @@ func newTestSendResponse(status int, body string) *SendResponse {
|
|||||||
|
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockTokenVerifierProxier struct {
|
||||||
|
currentToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mockTokenVerifierProxier) Send(ctx context.Context, req *SendRequest) (*SendResponse, error) {
|
||||||
|
p.currentToken = req.Token
|
||||||
|
resp := newTestSendResponse(http.StatusOK,
|
||||||
|
`{"data": {"id": "` + p.currentToken + `"}}`)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mockTokenVerifierProxier) GetCurrentRequestToken() (string) {
|
||||||
|
return p.currentToken
|
||||||
|
}
|
||||||
@@ -298,7 +298,7 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||||||
mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
||||||
|
|
||||||
// Passing a non-nil inmemsink tells the agent to use the auto-auth token
|
// Passing a non-nil inmemsink tells the agent to use the auto-auth token
|
||||||
mux.Handle("/", cache.Handler(ctx, cacheLogger, leaseCache, inmemSink))
|
mux.Handle("/", cache.Handler(ctx, cacheLogger, leaseCache, inmemSink, true))
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: mux,
|
Handler: mux,
|
||||||
ReadHeaderTimeout: 10 * time.Second,
|
ReadHeaderTimeout: 10 * time.Second,
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ type Vault struct {
|
|||||||
|
|
||||||
// Cache contains any configuration needed for Cache mode
|
// Cache contains any configuration needed for Cache mode
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
UseAutoAuthToken bool `hcl:"use_auto_auth_token"`
|
UseAutoAuthTokenRaw interface{} `hcl:"use_auto_auth_token"`
|
||||||
|
UseAutoAuthToken bool `hcl:"-"`
|
||||||
|
UseAutoAuthTokenEnforce bool `hcl:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listener contains configuration for any Vault Agent listeners
|
// Listener contains configuration for any Vault Agent listeners
|
||||||
@@ -219,6 +221,26 @@ func parseCache(result *Config, list *ast.ObjectList) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.UseAutoAuthTokenRaw != nil {
|
||||||
|
c.UseAutoAuthToken, err = parseutil.ParseBool(c.UseAutoAuthTokenRaw)
|
||||||
|
if err != nil {
|
||||||
|
// Could be a value of "force" instead of "true"/"false"
|
||||||
|
switch c.UseAutoAuthTokenRaw.(type) {
|
||||||
|
case string:
|
||||||
|
v := c.UseAutoAuthTokenRaw.(string)
|
||||||
|
|
||||||
|
if !strings.EqualFold(v, "force") {
|
||||||
|
return fmt.Errorf("value of 'use_auto_auth_token' can be either true/false/force, %q is an invalid option", c.UseAutoAuthTokenRaw)
|
||||||
|
}
|
||||||
|
c.UseAutoAuthToken = true
|
||||||
|
c.UseAutoAuthTokenEnforce = true
|
||||||
|
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result.Cache = &c
|
result.Cache = &c
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ func TestLoadConfigFile_AgentCache(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Cache: &Cache{
|
Cache: &Cache{
|
||||||
UseAutoAuthToken: true,
|
UseAutoAuthToken: true,
|
||||||
|
UseAutoAuthTokenEnforce: false,
|
||||||
|
UseAutoAuthTokenRaw: true,
|
||||||
},
|
},
|
||||||
Listeners: []*Listener{
|
Listeners: []*Listener{
|
||||||
&Listener{
|
&Listener{
|
||||||
@@ -269,6 +271,133 @@ func TestLoadConfigFile_AgentCache_AutoAuth_NoSink(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Cache: &Cache{
|
Cache: &Cache{
|
||||||
UseAutoAuthToken: true,
|
UseAutoAuthToken: true,
|
||||||
|
UseAutoAuthTokenEnforce: false,
|
||||||
|
UseAutoAuthTokenRaw: true,
|
||||||
|
},
|
||||||
|
Listeners: []*Listener{
|
||||||
|
&Listener{
|
||||||
|
Type: "tcp",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"address": "127.0.0.1:8300",
|
||||||
|
"tls_disable": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PidFile: "./pidfile",
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := deep.Equal(config, expected); diff != nil {
|
||||||
|
t.Fatal(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadConfigFile_AgentCache_AutoAuth_Force(t *testing.T) {
|
||||||
|
config, err := LoadConfig("./test-fixtures/config-cache-auto_auth-force.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &Config{
|
||||||
|
AutoAuth: &AutoAuth{
|
||||||
|
Method: &Method{
|
||||||
|
Type: "aws",
|
||||||
|
MountPath: "auth/aws",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"role": "foobar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Cache: &Cache{
|
||||||
|
UseAutoAuthToken: true,
|
||||||
|
UseAutoAuthTokenEnforce: true,
|
||||||
|
UseAutoAuthTokenRaw: "force",
|
||||||
|
},
|
||||||
|
Listeners: []*Listener{
|
||||||
|
&Listener{
|
||||||
|
Type: "tcp",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"address": "127.0.0.1:8300",
|
||||||
|
"tls_disable": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PidFile: "./pidfile",
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := deep.Equal(config, expected); diff != nil {
|
||||||
|
t.Fatal(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadConfigFile_AgentCache_AutoAuth_True(t *testing.T) {
|
||||||
|
config, err := LoadConfig("./test-fixtures/config-cache-auto_auth-true.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &Config{
|
||||||
|
AutoAuth: &AutoAuth{
|
||||||
|
Method: &Method{
|
||||||
|
Type: "aws",
|
||||||
|
MountPath: "auth/aws",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"role": "foobar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Cache: &Cache{
|
||||||
|
UseAutoAuthToken: true,
|
||||||
|
UseAutoAuthTokenEnforce: false,
|
||||||
|
UseAutoAuthTokenRaw: "true",
|
||||||
|
},
|
||||||
|
Listeners: []*Listener{
|
||||||
|
&Listener{
|
||||||
|
Type: "tcp",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"address": "127.0.0.1:8300",
|
||||||
|
"tls_disable": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PidFile: "./pidfile",
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := deep.Equal(config, expected); diff != nil {
|
||||||
|
t.Fatal(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadConfigFile_AgentCache_AutoAuth_False(t *testing.T) {
|
||||||
|
config, err := LoadConfig("./test-fixtures/config-cache-auto_auth-false.hcl")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &Config{
|
||||||
|
AutoAuth: &AutoAuth{
|
||||||
|
Method: &Method{
|
||||||
|
Type: "aws",
|
||||||
|
MountPath: "auth/aws",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"role": "foobar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Sinks: []*Sink{
|
||||||
|
&Sink{
|
||||||
|
Type: "file",
|
||||||
|
DHType: "curve25519",
|
||||||
|
DHPath: "/tmp/file-foo-dhpath",
|
||||||
|
AAD: "foobar",
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"path": "/tmp/file-foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Cache: &Cache{
|
||||||
|
UseAutoAuthToken: false,
|
||||||
|
UseAutoAuthTokenEnforce: false,
|
||||||
|
UseAutoAuthTokenRaw: "false",
|
||||||
},
|
},
|
||||||
Listeners: []*Listener{
|
Listeners: []*Listener{
|
||||||
&Listener{
|
&Listener{
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
pid_file = "./pidfile"
|
||||||
|
|
||||||
|
auto_auth {
|
||||||
|
method {
|
||||||
|
type = "aws"
|
||||||
|
config = {
|
||||||
|
role = "foobar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sink {
|
||||||
|
type = "file"
|
||||||
|
config = {
|
||||||
|
path = "/tmp/file-foo"
|
||||||
|
}
|
||||||
|
aad = "foobar"
|
||||||
|
dh_type = "curve25519"
|
||||||
|
dh_path = "/tmp/file-foo-dhpath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache {
|
||||||
|
use_auto_auth_token = "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
listener "tcp" {
|
||||||
|
address = "127.0.0.1:8300"
|
||||||
|
tls_disable = true
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
pid_file = "./pidfile"
|
||||||
|
|
||||||
|
auto_auth {
|
||||||
|
method {
|
||||||
|
type = "aws"
|
||||||
|
config = {
|
||||||
|
role = "foobar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache {
|
||||||
|
use_auto_auth_token = "force"
|
||||||
|
}
|
||||||
|
|
||||||
|
listener "tcp" {
|
||||||
|
address = "127.0.0.1:8300"
|
||||||
|
tls_disable = true
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
pid_file = "./pidfile"
|
||||||
|
|
||||||
|
auto_auth {
|
||||||
|
method {
|
||||||
|
type = "aws"
|
||||||
|
config = {
|
||||||
|
role = "foobar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache {
|
||||||
|
use_auto_auth_token = "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
listener "tcp" {
|
||||||
|
address = "127.0.0.1:8300"
|
||||||
|
tls_disable = true
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user