agent/caching: enable caching of leases generated by autoauth token (#6293)
* agent/caching: enable caching of leases generated by autoauth token * add test for auth/token/create path * update error message log * Some minor updates * add sleep timer for renewal logic to process
This commit is contained in:
parent
ffabeda5d9
commit
c07253999c
|
@ -339,22 +339,6 @@ func (c *AgentCommand) Run(args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
var inmemSink sink.Sink
|
||||
if config.Cache.UseAutoAuthToken {
|
||||
cacheLogger.Debug("auto-auth token is allowed to be used; configuring inmem sink")
|
||||
inmemSink, err = inmem.New(&sink.SinkConfig{
|
||||
Logger: cacheLogger,
|
||||
})
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating inmem sink for cache: %v", err))
|
||||
return 1
|
||||
}
|
||||
sinks = append(sinks, &sink.SinkConfig{
|
||||
Logger: cacheLogger,
|
||||
Sink: inmemSink,
|
||||
})
|
||||
}
|
||||
|
||||
// Create the API proxier
|
||||
apiProxy, err := cache.NewAPIProxy(&cache.APIProxyConfig{
|
||||
Client: client,
|
||||
|
@ -378,6 +362,22 @@ func (c *AgentCommand) Run(args []string) int {
|
|||
return 1
|
||||
}
|
||||
|
||||
var inmemSink sink.Sink
|
||||
if config.Cache.UseAutoAuthToken {
|
||||
cacheLogger.Debug("auto-auth token is allowed to be used; configuring inmem sink")
|
||||
inmemSink, err = inmem.New(&sink.SinkConfig{
|
||||
Logger: cacheLogger,
|
||||
}, leaseCache)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error creating inmem sink for cache: %v", err))
|
||||
return 1
|
||||
}
|
||||
sinks = append(sinks, &sink.SinkConfig{
|
||||
Logger: cacheLogger,
|
||||
Sink: inmemSink,
|
||||
})
|
||||
}
|
||||
|
||||
// Create a muxer and add paths relevant for the lease cache layer
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
hclog "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/vault/api"
|
||||
cachememdb "github.com/hashicorp/vault/command/agent/cache/cachememdb"
|
||||
"github.com/hashicorp/vault/helper/base62"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/cryptoutil"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
|
@ -264,7 +265,7 @@ func (c *LeaseCache) Send(ctx context.Context, req *SendRequest) (*SendResponse,
|
|||
entry.TokenParent = req.Token
|
||||
}
|
||||
|
||||
renewCtxInfo = c.createCtxInfo(parentCtx, secret.Auth.ClientToken)
|
||||
renewCtxInfo = c.createCtxInfo(parentCtx)
|
||||
index.Token = secret.Auth.ClientToken
|
||||
index.TokenAccessor = secret.Auth.Accessor
|
||||
|
||||
|
@ -316,7 +317,7 @@ func (c *LeaseCache) Send(ctx context.Context, req *SendRequest) (*SendResponse,
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *LeaseCache) createCtxInfo(ctx context.Context, token string) *ContextInfo {
|
||||
func (c *LeaseCache) createCtxInfo(ctx context.Context) *ContextInfo {
|
||||
if ctx == nil {
|
||||
ctx = c.baseCtxInfo.Ctx
|
||||
}
|
||||
|
@ -759,3 +760,61 @@ func deriveNamespaceAndRevocationPath(req *SendRequest) (string, string) {
|
|||
|
||||
return namespace, fmt.Sprintf("/v1%s", nonVersionedPath)
|
||||
}
|
||||
|
||||
// RegisterAutoAuthToken adds the provided auto-token into the cache. This is
|
||||
// primarily used to register the auto-auth token and should only be called
|
||||
// within a sink's WriteToken func.
|
||||
func (c *LeaseCache) RegisterAutoAuthToken(token string) error {
|
||||
// Get the token from the cache
|
||||
oldIndex, err := c.db.Get(cachememdb.IndexNameToken, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the index is found, defer its cancelFunc
|
||||
if oldIndex != nil {
|
||||
defer oldIndex.RenewCtxInfo.CancelFunc()
|
||||
}
|
||||
|
||||
// The following randomly generated values are required for index stored by
|
||||
// the cache, but are not actually used. We use random values to prevent
|
||||
// accidental access.
|
||||
id, err := base62.Random(5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
namespace, err := base62.Random(5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestPath, err := base62.Random(5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
index := &cachememdb.Index{
|
||||
ID: id,
|
||||
Token: token,
|
||||
Namespace: namespace,
|
||||
RequestPath: requestPath,
|
||||
}
|
||||
|
||||
// Derive a context off of the lease cache's base context
|
||||
ctxInfo := c.createCtxInfo(nil)
|
||||
|
||||
index.RenewCtxInfo = &cachememdb.ContextInfo{
|
||||
Ctx: ctxInfo.Ctx,
|
||||
CancelFunc: ctxInfo.CancelFunc,
|
||||
DoneCh: ctxInfo.DoneCh,
|
||||
}
|
||||
|
||||
// Store the index in the cache
|
||||
c.logger.Debug("storing auto-auth token into the cache")
|
||||
err = c.db.Set(index)
|
||||
if err != nil {
|
||||
c.logger.Error("failed to cache the auto-auth token", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package agent
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -21,12 +20,23 @@ import (
|
|||
"github.com/hashicorp/vault/command/agent/sink"
|
||||
"github.com/hashicorp/vault/command/agent/sink/file"
|
||||
"github.com/hashicorp/vault/command/agent/sink/inmem"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
vaulthttp "github.com/hashicorp/vault/http"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
)
|
||||
|
||||
const policyAutoAuthAppRole = `
|
||||
path "/kv/*" {
|
||||
capabilities = ["sudo", "create", "read", "update", "delete", "list"]
|
||||
}
|
||||
|
||||
path "/auth/token/create" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
`
|
||||
|
||||
func TestCache_UsingAutoAuthToken(t *testing.T) {
|
||||
var err error
|
||||
logger := logging.NewVaultLogger(log.Trace)
|
||||
|
@ -34,6 +44,9 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||
DisableMlock: true,
|
||||
DisableCache: true,
|
||||
Logger: log.NewNullLogger(),
|
||||
LogicalBackends: map[string]logical.Factory{
|
||||
"kv": vault.LeasedPassthroughBackendFactory,
|
||||
},
|
||||
CredentialBackends: map[string]logical.Factory{
|
||||
"approle": credAppRole.Factory,
|
||||
},
|
||||
|
@ -58,6 +71,28 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||
defer os.Setenv(api.EnvVaultCACert, os.Getenv(api.EnvVaultCACert))
|
||||
os.Setenv(api.EnvVaultCACert, fmt.Sprintf("%s/ca_cert.pem", cluster.TempDir))
|
||||
|
||||
err = client.Sys().Mount("kv", &api.MountInput{
|
||||
Type: "kv",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a secret in the backend
|
||||
_, err = client.Logical().Write("kv/foo", map[string]interface{}{
|
||||
"value": "bar",
|
||||
"ttl": "1h",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Add an kv-admin policy
|
||||
if err := client.Sys().PutPolicy("test-autoauth", policyAutoAuthAppRole); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Enable approle
|
||||
err = client.Sys().EnableAuthWithOptions("approle", &api.EnableAuthOptions{
|
||||
Type: "approle",
|
||||
})
|
||||
|
@ -69,6 +104,7 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||
"bind_secret_id": "true",
|
||||
"token_ttl": "3s",
|
||||
"token_max_ttl": "10s",
|
||||
"policies": []string{"test-autoauth"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -127,6 +163,29 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||
"remove_secret_id_file_after_reading": true,
|
||||
}
|
||||
|
||||
cacheLogger := logging.NewVaultLogger(hclog.Trace).Named("cache")
|
||||
|
||||
// Create the API proxier
|
||||
apiProxy, err := cache.NewAPIProxy(&cache.APIProxyConfig{
|
||||
Client: client,
|
||||
Logger: cacheLogger.Named("apiproxy"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create the lease cache proxier and set its underlying proxier to
|
||||
// the API proxier.
|
||||
leaseCache, err := cache.NewLeaseCache(&cache.LeaseCacheConfig{
|
||||
Client: client,
|
||||
BaseContext: ctx,
|
||||
Proxier: apiProxy,
|
||||
Logger: cacheLogger.Named("leasecache"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
am, err := agentapprole.NewApproleAuthMethod(&auth.AuthConfig{
|
||||
Logger: logger.Named("auth.approle"),
|
||||
MountPath: "auth/approle",
|
||||
|
@ -166,7 +225,7 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||
Logger: logger.Named("sink.inmem"),
|
||||
}
|
||||
|
||||
inmemSink, err := inmem.New(inmemSinkConfig)
|
||||
inmemSink, err := inmem.New(inmemSinkConfig, leaseCache)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -239,29 +298,6 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||
|
||||
defer listener.Close()
|
||||
|
||||
cacheLogger := logging.NewVaultLogger(hclog.Trace).Named("cache")
|
||||
|
||||
// Create the API proxier
|
||||
apiProxy, err := cache.NewAPIProxy(&cache.APIProxyConfig{
|
||||
Client: client,
|
||||
Logger: cacheLogger.Named("apiproxy"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create the lease cache proxier and set its underlying proxier to
|
||||
// the API proxier.
|
||||
leaseCache, err := cache.NewLeaseCache(&cache.LeaseCacheConfig{
|
||||
Client: client,
|
||||
BaseContext: ctx,
|
||||
Proxier: apiProxy,
|
||||
Logger: cacheLogger.Named("leasecache"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a muxer and add paths relevant for the lease cache layer
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle(consts.AgentPathCacheClear, leaseCache.HandleCacheClear(ctx))
|
||||
|
@ -295,4 +331,51 @@ func TestCache_UsingAutoAuthToken(t *testing.T) {
|
|||
if resp == nil {
|
||||
t.Fatalf("failed to use the auto-auth token to perform lookup-self")
|
||||
}
|
||||
|
||||
// The following block tests lease creation caching using the auto-auth token.
|
||||
{
|
||||
resp, err = testClient.Logical().Read("kv/foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
origReqID := resp.RequestID
|
||||
|
||||
resp, err = testClient.Logical().Read("kv/foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Sleep for a bit to allow renewer logic to kick in
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
cacheReqID := resp.RequestID
|
||||
|
||||
if origReqID != cacheReqID {
|
||||
t.Fatalf("request ID mismatch, expected second request to be a cached response: %s != %s", origReqID, cacheReqID)
|
||||
}
|
||||
}
|
||||
|
||||
// The following block tests auth token creation caching (child, non-orphan
|
||||
// tokens) using the auto-auth token.
|
||||
{
|
||||
resp, err = testClient.Logical().Write("auth/token/create", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
origReqID := resp.RequestID
|
||||
|
||||
// Sleep for a bit to allow renewer logic to kick in
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
resp, err = testClient.Logical().Write("auth/token/create", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cacheReqID := resp.RequestID
|
||||
|
||||
if origReqID != cacheReqID {
|
||||
t.Fatalf("request ID mismatch, expected second request to be a cached response: %s != %s", origReqID, cacheReqID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,27 +4,37 @@ import (
|
|||
"errors"
|
||||
|
||||
hclog "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/vault/command/agent/cache"
|
||||
"github.com/hashicorp/vault/command/agent/sink"
|
||||
)
|
||||
|
||||
// inmemSink retains the auto-auth token in memory and exposes it via
|
||||
// sink.SinkReader interface.
|
||||
type inmemSink struct {
|
||||
logger hclog.Logger
|
||||
token string
|
||||
logger hclog.Logger
|
||||
token string
|
||||
leaseCache *cache.LeaseCache
|
||||
}
|
||||
|
||||
func New(conf *sink.SinkConfig) (sink.Sink, error) {
|
||||
// New creates a new instance of inmemSink.
|
||||
func New(conf *sink.SinkConfig, leaseCache *cache.LeaseCache) (sink.Sink, error) {
|
||||
if conf.Logger == nil {
|
||||
return nil, errors.New("nil logger provided")
|
||||
}
|
||||
|
||||
return &inmemSink{
|
||||
logger: conf.Logger,
|
||||
logger: conf.Logger,
|
||||
leaseCache: leaseCache,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *inmemSink) WriteToken(token string) error {
|
||||
s.token = token
|
||||
|
||||
if s.leaseCache != nil {
|
||||
s.leaseCache.RegisterAutoAuthToken(token)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue