Ensure that cache entries for tokens are prefixed “token-secret… (#6688)

This will be necessary once we store other types of identities in here.
This commit is contained in:
Matt Keeler 2019-10-25 13:05:43 -04:00 committed by GitHub
parent a688ea952d
commit 87c44a3b8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 25 deletions

View File

@ -89,6 +89,10 @@ func IsACLRemoteError(err error) bool {
return ok return ok
} }
func tokenSecretCacheID(token string) string {
return "token-secret:" + token
}
type ACLResolverDelegate interface { type ACLResolverDelegate interface {
ACLsEnabled() bool ACLsEnabled() bool
ACLDatacenter(legacy bool) string ACLDatacenter(legacy bool) string
@ -343,6 +347,8 @@ func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) {
} }
func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) { func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) {
cacheID := tokenSecretCacheID(token)
req := structs.ACLTokenGetRequest{ req := structs.ACLTokenGetRequest{
Datacenter: r.delegate.ACLDatacenter(false), Datacenter: r.delegate.ACLDatacenter(false),
TokenID: token, TokenID: token,
@ -357,17 +363,17 @@ func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *struc
err := r.delegate.RPC("ACL.TokenRead", &req, &resp) err := r.delegate.RPC("ACL.TokenRead", &req, &resp)
if err == nil { if err == nil {
if resp.Token == nil { if resp.Token == nil {
r.cache.PutIdentity(token, nil) r.cache.PutIdentity(cacheID, nil)
return nil, acl.ErrNotFound return nil, acl.ErrNotFound
} else { } else {
r.cache.PutIdentity(token, resp.Token) r.cache.PutIdentity(cacheID, resp.Token)
return resp.Token, nil return resp.Token, nil
} }
} }
if acl.IsErrNotFound(err) { if acl.IsErrNotFound(err) {
// Make sure to remove from the cache if it was deleted // Make sure to remove from the cache if it was deleted
r.cache.PutIdentity(token, nil) r.cache.PutIdentity(cacheID, nil)
return nil, acl.ErrNotFound return nil, acl.ErrNotFound
} }
@ -375,11 +381,11 @@ func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *struc
// some other RPC error // some other RPC error
if cached != nil && (r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache") { if cached != nil && (r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache") {
// extend the cache // extend the cache
r.cache.PutIdentity(token, cached.Identity) r.cache.PutIdentity(cacheID, cached.Identity)
return cached.Identity, nil return cached.Identity, nil
} }
r.cache.PutIdentity(token, nil) r.cache.PutIdentity(cacheID, nil)
return nil, err return nil, err
} }
@ -390,7 +396,7 @@ func (r *ACLResolver) resolveIdentityFromToken(token string) (structs.ACLIdentit
} }
// Check the cache before making any RPC requests // Check the cache before making any RPC requests
cacheEntry := r.cache.GetIdentity(token) cacheEntry := r.cache.GetIdentity(tokenSecretCacheID(token))
if cacheEntry != nil && cacheEntry.Age() <= r.config.ACLTokenTTL { if cacheEntry != nil && cacheEntry.Age() <= r.config.ACLTokenTTL {
metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1) metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1)
return cacheEntry.Identity, nil return cacheEntry.Identity, nil
@ -540,7 +546,7 @@ func (r *ACLResolver) maybeHandleIdentityErrorDuringFetch(identity structs.ACLId
if acl.IsErrNotFound(err) { if acl.IsErrNotFound(err) {
// make sure to indicate that this identity is no longer valid within // make sure to indicate that this identity is no longer valid within
// the cache // the cache
r.cache.PutIdentity(identity.SecretToken(), nil) r.cache.PutIdentity(tokenSecretCacheID(identity.SecretToken()), nil)
// Do not touch the cache. Getting a top level ACL not found error // Do not touch the cache. Getting a top level ACL not found error
// only indicates that the secret token used in the request // only indicates that the secret token used in the request
@ -551,7 +557,7 @@ func (r *ACLResolver) maybeHandleIdentityErrorDuringFetch(identity structs.ACLId
if acl.IsErrPermissionDenied(err) { if acl.IsErrPermissionDenied(err) {
// invalidate our ID cache so that identity resolution will take place // invalidate our ID cache so that identity resolution will take place
// again in the future // again in the future
r.cache.RemoveIdentity(identity.SecretToken()) r.cache.RemoveIdentity(tokenSecretCacheID(identity.SecretToken()))
// Do not remove from the cache for permission denied // Do not remove from the cache for permission denied
// what this does indicate is that our view of the token is out of date // what this does indicate is that our view of the token is out of date

View File

@ -634,7 +634,7 @@ func (a *ACL) tokenSetInternal(args *structs.ACLTokenSetRequest, reply *structs.
} }
// Purge the identity from the cache to prevent using the previous definition of the identity // Purge the identity from the cache to prevent using the previous definition of the identity
a.srv.acls.cache.RemoveIdentity(token.SecretID) a.srv.acls.cache.RemoveIdentity(tokenSecretCacheID(token.SecretID))
if respErr, ok := resp.(error); ok { if respErr, ok := resp.(error); ok {
return respErr return respErr
@ -776,7 +776,7 @@ func (a *ACL) TokenDelete(args *structs.ACLTokenDeleteRequest, reply *string) er
} }
// Purge the identity from the cache to prevent using the previous definition of the identity // Purge the identity from the cache to prevent using the previous definition of the identity
a.srv.acls.cache.RemoveIdentity(token.SecretID) a.srv.acls.cache.RemoveIdentity(tokenSecretCacheID(token.SecretID))
if respErr, ok := resp.(error); ok { if respErr, ok := resp.(error); ok {
return respErr return respErr
@ -2249,7 +2249,7 @@ func (a *ACL) Logout(args *structs.ACLLogoutRequest, reply *bool) error {
// Purge the identity from the cache to prevent using the previous definition of the identity // Purge the identity from the cache to prevent using the previous definition of the identity
if token != nil { if token != nil {
a.srv.acls.cache.RemoveIdentity(token.SecretID) a.srv.acls.cache.RemoveIdentity(tokenSecretCacheID(token.SecretID))
} }
if respErr, ok := resp.(error); ok { if respErr, ok := resp.(error); ok {

View File

@ -186,7 +186,7 @@ func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error {
// Clear the cache if applicable // Clear the cache if applicable
if args.ACL.ID != "" { if args.ACL.ID != "" {
a.srv.acls.cache.RemoveIdentity(args.ACL.ID) a.srv.acls.cache.RemoveIdentity(tokenSecretCacheID(args.ACL.ID))
} }
return nil return nil

View File

@ -693,10 +693,10 @@ func TestACLResolver_ResolveRootACL(t *testing.T) {
func TestACLResolver_DownPolicy(t *testing.T) { func TestACLResolver_DownPolicy(t *testing.T) {
t.Parallel() t.Parallel()
requireIdentityCached := func(t *testing.T, r *ACLResolver, token string, present bool, msg string) { requireIdentityCached := func(t *testing.T, r *ACLResolver, id string, present bool, msg string) {
t.Helper() t.Helper()
cacheVal := r.cache.GetIdentity(token) cacheVal := r.cache.GetIdentity(id)
require.NotNil(t, cacheVal) require.NotNil(t, cacheVal)
if present { if present {
require.NotNil(t, cacheVal.Identity, msg) require.NotNil(t, cacheVal.Identity, msg)
@ -738,7 +738,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
require.NotNil(t, authz) require.NotNil(t, authz)
require.Equal(t, authz, acl.DenyAll()) require.Equal(t, authz, acl.DenyAll())
requireIdentityCached(t, r, "foo", false, "not present") requireIdentityCached(t, r, tokenSecretCacheID("foo"), false, "not present")
}) })
t.Run("Allow", func(t *testing.T) { t.Run("Allow", func(t *testing.T) {
@ -763,7 +763,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
require.NotNil(t, authz) require.NotNil(t, authz)
require.Equal(t, authz, acl.AllowAll()) require.Equal(t, authz, acl.AllowAll())
requireIdentityCached(t, r, "foo", false, "not present") requireIdentityCached(t, r, tokenSecretCacheID("foo"), false, "not present")
}) })
t.Run("Expired-Policy", func(t *testing.T) { t.Run("Expired-Policy", func(t *testing.T) {
@ -857,7 +857,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
require.NotNil(t, authz) require.NotNil(t, authz)
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil)) require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
requireIdentityCached(t, r, "found", true, "cached") requireIdentityCached(t, r, tokenSecretCacheID("found"), true, "cached")
authz2, err := r.ResolveToken("found") authz2, err := r.ResolveToken("found")
require.NoError(t, err) require.NoError(t, err)
@ -888,7 +888,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
require.NotNil(t, authz) require.NotNil(t, authz)
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil)) require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
requireIdentityCached(t, r, "found-role", true, "still cached") requireIdentityCached(t, r, tokenSecretCacheID("found-role"), true, "still cached")
authz2, err := r.ResolveToken("found-role") authz2, err := r.ResolveToken("found-role")
require.NoError(t, err) require.NoError(t, err)
@ -1154,7 +1154,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
require.NotNil(t, authz) require.NotNil(t, authz)
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil)) require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
requireIdentityCached(t, r, "found", true, "cached") requireIdentityCached(t, r, tokenSecretCacheID("found"), true, "cached")
// The identity should have been cached so this should still be valid // The identity should have been cached so this should still be valid
authz2, err := r.ResolveToken("found") authz2, err := r.ResolveToken("found")
@ -1171,7 +1171,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
assert.Nil(t, authz3) assert.Nil(t, authz3)
}) })
requireIdentityCached(t, r, "found", false, "no longer cached") requireIdentityCached(t, r, tokenSecretCacheID("found"), false, "no longer cached")
}) })
t.Run("PolicyResolve-TokenNotFound", func(t *testing.T) { t.Run("PolicyResolve-TokenNotFound", func(t *testing.T) {
@ -1225,7 +1225,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil)) require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
// Verify that the caches are setup properly. // Verify that the caches are setup properly.
requireIdentityCached(t, r, secretID, true, "cached") requireIdentityCached(t, r, tokenSecretCacheID(secretID), true, "cached")
requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token
requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token
@ -1236,7 +1236,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
_, err = r.ResolveToken(secretID) _, err = r.ResolveToken(secretID)
require.True(t, acl.IsErrNotFound(err)) require.True(t, acl.IsErrNotFound(err))
requireIdentityCached(t, r, secretID, false, "identity not found cached") requireIdentityCached(t, r, tokenSecretCacheID(secretID), false, "identity not found cached")
requirePolicyCached(t, r, "node-wr", true, "still cached") requirePolicyCached(t, r, "node-wr", true, "still cached")
require.Nil(t, r.cache.GetPolicy("dc2-key-wr"), "not stored at all") require.Nil(t, r.cache.GetPolicy("dc2-key-wr"), "not stored at all")
}) })
@ -1287,7 +1287,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil)) require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
// Verify that the caches are setup properly. // Verify that the caches are setup properly.
requireIdentityCached(t, r, secretID, true, "cached") requireIdentityCached(t, r, tokenSecretCacheID(secretID), true, "cached")
requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token
requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token
@ -1298,7 +1298,7 @@ func TestACLResolver_DownPolicy(t *testing.T) {
_, err = r.ResolveToken(secretID) _, err = r.ResolveToken(secretID)
require.True(t, acl.IsErrPermissionDenied(err)) require.True(t, acl.IsErrPermissionDenied(err))
require.Nil(t, r.cache.GetIdentity(secretID), "identity not stored at all") require.Nil(t, r.cache.GetIdentity(tokenSecretCacheID(secretID)), "identity not stored at all")
requirePolicyCached(t, r, "node-wr", true, "still cached") requirePolicyCached(t, r, "node-wr", true, "still cached")
require.Nil(t, r.cache.GetPolicy("dc2-key-wr"), "not stored at all") require.Nil(t, r.cache.GetPolicy("dc2-key-wr"), "not stored at all")
}) })

View File

@ -106,7 +106,7 @@ func (s *Server) reapExpiredACLTokens(local, global bool) (int, error) {
// Purge the identities from the cache // Purge the identities from the cache
for _, secretID := range secretIDs { for _, secretID := range secretIDs {
s.acls.cache.RemoveIdentity(secretID) s.acls.cache.RemoveIdentity(tokenSecretCacheID(secretID))
} }
if respErr, ok := resp.(error); ok { if respErr, ok := resp.(error); ok {