acl: remove ACL.GetPolicy endpoint and resolve legacy acls
And all code that was no longer used once those two were removed.
This commit is contained in:
parent
b8da06a34d
commit
b73b68d696
|
@ -453,54 +453,6 @@ func NewPolicyFromSource(id string, revision uint64, rules string, syntax Syntax
|
|||
return policy, err
|
||||
}
|
||||
|
||||
// TODO(ACL-Legacy): remove this
|
||||
func (policy *Policy) ConvertToLegacy() *Policy {
|
||||
converted := &Policy{
|
||||
ID: policy.ID,
|
||||
Revision: policy.Revision,
|
||||
PolicyRules: PolicyRules{
|
||||
ACL: policy.ACL,
|
||||
Keyring: policy.Keyring,
|
||||
Operator: policy.Operator,
|
||||
},
|
||||
}
|
||||
|
||||
converted.Agents = append(converted.Agents, policy.Agents...)
|
||||
converted.Agents = append(converted.Agents, policy.AgentPrefixes...)
|
||||
converted.Keys = append(converted.Keys, policy.Keys...)
|
||||
converted.Keys = append(converted.Keys, policy.KeyPrefixes...)
|
||||
converted.Nodes = append(converted.Nodes, policy.Nodes...)
|
||||
converted.Nodes = append(converted.Nodes, policy.NodePrefixes...)
|
||||
converted.Services = append(converted.Services, policy.Services...)
|
||||
converted.Services = append(converted.Services, policy.ServicePrefixes...)
|
||||
converted.Sessions = append(converted.Sessions, policy.Sessions...)
|
||||
converted.Sessions = append(converted.Sessions, policy.SessionPrefixes...)
|
||||
converted.Events = append(converted.Events, policy.Events...)
|
||||
converted.Events = append(converted.Events, policy.EventPrefixes...)
|
||||
converted.PreparedQueries = append(converted.PreparedQueries, policy.PreparedQueries...)
|
||||
converted.PreparedQueries = append(converted.PreparedQueries, policy.PreparedQueryPrefixes...)
|
||||
return converted
|
||||
}
|
||||
|
||||
// TODO(ACL-Legacy): remove this
|
||||
func (policy *Policy) ConvertFromLegacy() *Policy {
|
||||
return &Policy{
|
||||
ID: policy.ID,
|
||||
Revision: policy.Revision,
|
||||
PolicyRules: PolicyRules{
|
||||
AgentPrefixes: policy.Agents,
|
||||
KeyPrefixes: policy.Keys,
|
||||
NodePrefixes: policy.Nodes,
|
||||
ServicePrefixes: policy.Services,
|
||||
SessionPrefixes: policy.Sessions,
|
||||
EventPrefixes: policy.Events,
|
||||
PreparedQueryPrefixes: policy.PreparedQueries,
|
||||
Keyring: policy.Keyring,
|
||||
Operator: policy.Operator,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// takesPrecedenceOver returns true when permission a
|
||||
// should take precedence over permission b
|
||||
func takesPrecedenceOver(a, b string) bool {
|
||||
|
|
|
@ -383,135 +383,6 @@ func (r *ACLResolver) Close() {
|
|||
r.aclConf.Close()
|
||||
}
|
||||
|
||||
func (r *ACLResolver) fetchAndCacheTokenLegacy(token string, cached *structs.AuthorizerCacheEntry) (acl.Authorizer, error) {
|
||||
req := structs.ACLPolicyResolveLegacyRequest{
|
||||
Datacenter: r.delegate.ACLDatacenter(true),
|
||||
ACL: token,
|
||||
}
|
||||
|
||||
cacheTTL := r.config.ACLTokenTTL
|
||||
if cached != nil {
|
||||
cacheTTL = cached.TTL
|
||||
}
|
||||
|
||||
var reply structs.ACLPolicyResolveLegacyResponse
|
||||
err := r.delegate.RPC("ACL.GetPolicy", &req, &reply)
|
||||
if err == nil {
|
||||
parent := acl.RootAuthorizer(reply.Parent)
|
||||
if parent == nil {
|
||||
var authorizer acl.Authorizer
|
||||
if cached != nil {
|
||||
authorizer = cached.Authorizer
|
||||
}
|
||||
r.cache.PutAuthorizerWithTTL(token, authorizer, cacheTTL)
|
||||
return authorizer, acl.ErrInvalidParent
|
||||
}
|
||||
|
||||
var policies []*acl.Policy
|
||||
policy := reply.Policy
|
||||
if policy != nil {
|
||||
policies = append(policies, policy.ConvertFromLegacy())
|
||||
}
|
||||
|
||||
authorizer, err := acl.NewPolicyAuthorizerWithDefaults(parent, policies, r.aclConf)
|
||||
|
||||
r.cache.PutAuthorizerWithTTL(token, authorizer, reply.TTL)
|
||||
return authorizer, err
|
||||
}
|
||||
|
||||
if acl.IsErrNotFound(err) {
|
||||
// Make sure to remove from the cache if it was deleted
|
||||
r.cache.PutAuthorizerWithTTL(token, nil, cacheTTL)
|
||||
return nil, acl.ErrNotFound
|
||||
|
||||
}
|
||||
|
||||
// some other RPC error
|
||||
switch r.config.ACLDownPolicy {
|
||||
case "allow":
|
||||
r.cache.PutAuthorizerWithTTL(token, acl.AllowAll(), cacheTTL)
|
||||
return acl.AllowAll(), nil
|
||||
case "async-cache", "extend-cache":
|
||||
if cached != nil {
|
||||
r.cache.PutAuthorizerWithTTL(token, cached.Authorizer, cacheTTL)
|
||||
return cached.Authorizer, nil
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
r.cache.PutAuthorizerWithTTL(token, acl.DenyAll(), cacheTTL)
|
||||
return acl.DenyAll(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
func (r *ACLResolver) resolveTokenLegacy(token string) (structs.ACLIdentity, acl.Authorizer, error) {
|
||||
defer metrics.MeasureSince([]string{"acl", "resolveTokenLegacy"}, time.Now())
|
||||
|
||||
// Attempt to resolve locally first (local results are not cached)
|
||||
// This is only useful for servers where either legacy replication is being
|
||||
// done or the server is within the primary datacenter.
|
||||
if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done {
|
||||
if err == nil && identity != nil {
|
||||
policies, err := r.resolvePoliciesForIdentity(identity)
|
||||
if err != nil {
|
||||
return identity, nil, err
|
||||
}
|
||||
|
||||
authz, err := policies.Compile(r.cache, r.aclConf)
|
||||
if err != nil {
|
||||
return identity, nil, err
|
||||
}
|
||||
|
||||
return identity, acl.NewChainedAuthorizer([]acl.Authorizer{authz, acl.RootAuthorizer(r.config.ACLDefaultPolicy)}), nil
|
||||
}
|
||||
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
identity := &missingIdentity{
|
||||
reason: "legacy-token",
|
||||
token: token,
|
||||
}
|
||||
|
||||
// Look in the cache prior to making a RPC request
|
||||
entry := r.cache.GetAuthorizer(token)
|
||||
|
||||
if entry != nil && entry.Age() <= minTTL(entry.TTL, r.config.ACLTokenTTL) {
|
||||
metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1)
|
||||
if entry.Authorizer != nil {
|
||||
return identity, entry.Authorizer, nil
|
||||
}
|
||||
return identity, nil, acl.ErrNotFound
|
||||
}
|
||||
|
||||
metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1)
|
||||
|
||||
// Resolve the token in the background and wait on the result if we must
|
||||
waitChan := r.legacyGroup.DoChan(token, func() (interface{}, error) {
|
||||
authorizer, err := r.fetchAndCacheTokenLegacy(token, entry)
|
||||
return authorizer, err
|
||||
})
|
||||
|
||||
waitForResult := entry == nil || r.config.ACLDownPolicy != "async-cache"
|
||||
if !waitForResult {
|
||||
// waitForResult being false requires the cacheEntry to not be nil
|
||||
if entry.Authorizer != nil {
|
||||
return identity, entry.Authorizer, nil
|
||||
}
|
||||
return identity, nil, acl.ErrNotFound
|
||||
}
|
||||
|
||||
// block waiting for the async RPC to finish.
|
||||
res := <-waitChan
|
||||
|
||||
var authorizer acl.Authorizer
|
||||
if res.Val != nil { // avoid a nil-not-nil bug
|
||||
authorizer = res.Val.(acl.Authorizer)
|
||||
}
|
||||
|
||||
return identity, authorizer, res.Err
|
||||
}
|
||||
|
||||
func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) {
|
||||
cacheID := tokenSecretCacheID(token)
|
||||
|
||||
|
@ -1326,19 +1197,6 @@ func (r *ACLResolver) ACLsEnabled() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (r *ACLResolver) GetMergedPolicyForToken(token string) (structs.ACLIdentity, *acl.Policy, error) {
|
||||
ident, policies, err := r.resolveTokenToIdentityAndPolicies(token)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(policies) == 0 {
|
||||
return nil, nil, acl.ErrNotFound
|
||||
}
|
||||
|
||||
policy, err := policies.Merge(r.cache, r.aclConf)
|
||||
return ident, policy, err
|
||||
}
|
||||
|
||||
// aclFilter is used to filter results from our state store based on ACL rules
|
||||
// configured for the provided token.
|
||||
type aclFilter struct {
|
||||
|
|
|
@ -1372,56 +1372,6 @@ func (a *ACL) PolicyResolve(args *structs.ACLPolicyBatchGetRequest, reply *struc
|
|||
return nil
|
||||
}
|
||||
|
||||
// makeACLETag returns an ETag for the given parent and policy.
|
||||
func makeACLETag(parent string, policy *acl.Policy) string {
|
||||
return fmt.Sprintf("%s:%s", parent, policy.ID)
|
||||
}
|
||||
|
||||
// GetPolicy is used to retrieve a compiled policy object with a TTL. Does not
|
||||
// support a blocking query.
|
||||
//
|
||||
// TODO(ACL-Legacy): remove this
|
||||
func (a *ACL) GetPolicy(args *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error {
|
||||
if done, err := a.srv.ForwardRPC("ACL.GetPolicy", args, reply); done {
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify we are allowed to serve this request
|
||||
if a.srv.config.PrimaryDatacenter != a.srv.config.Datacenter {
|
||||
return acl.ErrDisabled
|
||||
}
|
||||
|
||||
// Get the policy via the cache
|
||||
parent := a.srv.config.ACLResolverSettings.ACLDefaultPolicy
|
||||
|
||||
ident, policy, err := a.srv.acls.GetMergedPolicyForToken(args.ACL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if token, ok := ident.(*structs.ACLToken); ok && token.Type == structs.ACLTokenTypeManagement {
|
||||
parent = "manage"
|
||||
}
|
||||
|
||||
// translates the structures internals to most closely match what could be expressed in the original rule language
|
||||
policy = policy.ConvertToLegacy()
|
||||
|
||||
// Generate an ETag
|
||||
etag := makeACLETag(parent, policy)
|
||||
|
||||
// Setup the response
|
||||
reply.ETag = etag
|
||||
reply.TTL = a.srv.config.ACLResolverSettings.ACLTokenTTL
|
||||
a.srv.setQueryMeta(&reply.QueryMeta)
|
||||
|
||||
// Only send the policy on an Etag mis-match
|
||||
if args.ETag != etag {
|
||||
reply.Parent = parent
|
||||
reply.Policy = policy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReplicationStatus is used to retrieve the current ACL replication status.
|
||||
func (a *ACL) ReplicationStatus(args *structs.DCSpecificRequest,
|
||||
reply *structs.ACLReplicationStatus) error {
|
||||
|
|
|
@ -6,6 +6,12 @@ import (
|
|||
"github.com/hashicorp/consul/agent/structs"
|
||||
)
|
||||
|
||||
type LegacyACLGetPolicy struct{}
|
||||
|
||||
func (a *ACL) GetPolicy(*LegacyACLGetPolicy, *LegacyACLGetPolicy) error {
|
||||
return fmt.Errorf("ACL.GetPolicy: the legacy ACL system has been removed")
|
||||
}
|
||||
|
||||
func (a *ACL) Bootstrap(*structs.DCSpecificRequest, *structs.ACL) error {
|
||||
return fmt.Errorf("ACL.Bootstrap: the legacy ACL system has been removed")
|
||||
}
|
||||
|
|
|
@ -74,30 +74,6 @@ func TestACLEndpoint_BootstrapTokens(t *testing.T) {
|
|||
require.Equal(t, out.CreateIndex, out.ModifyIndex)
|
||||
}
|
||||
|
||||
func TestACLEndpoint_GetPolicy_Management(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("too slow for testing.Short")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
_, srv, codec := testACLServerWithConfig(t, nil, false)
|
||||
|
||||
// wait for leader election and leader establishment to finish.
|
||||
// after this the global management policy, master token and
|
||||
// anonymous token will have been injected into the state store
|
||||
// and we will be ready to resolve the master token
|
||||
waitForLeaderEstablishment(t, srv)
|
||||
|
||||
req := structs.ACLPolicyResolveLegacyRequest{
|
||||
Datacenter: srv.config.Datacenter,
|
||||
ACL: TestDefaultMasterToken,
|
||||
}
|
||||
|
||||
var resp structs.ACLPolicyResolveLegacyResponse
|
||||
require.NoError(t, msgpackrpc.CallWithCodec(codec, "ACL.GetPolicy", &req, &resp))
|
||||
require.Equal(t, "manage", resp.Parent)
|
||||
}
|
||||
|
||||
func TestACLEndpoint_ReplicationStatus(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("too slow for testing.Short")
|
||||
|
|
|
@ -434,7 +434,6 @@ type ACLResolverTestDelegate struct {
|
|||
localTokens bool
|
||||
localPolicies bool
|
||||
localRoles bool
|
||||
getPolicyFn func(*structs.ACLPolicyResolveLegacyRequest, *structs.ACLPolicyResolveLegacyResponse) error
|
||||
tokenReadFn func(*structs.ACLTokenGetRequest, *structs.ACLTokenResponse) error
|
||||
policyResolveFn func(*structs.ACLPolicyBatchGetRequest, *structs.ACLPolicyBatchResponse) error
|
||||
roleResolveFn func(*structs.ACLRoleBatchGetRequest, *structs.ACLRoleBatchResponse) error
|
||||
|
@ -675,12 +674,6 @@ func (d *ACLResolverTestDelegate) ResolveRoleFromID(roleID string) (bool, *struc
|
|||
|
||||
func (d *ACLResolverTestDelegate) RPC(method string, args interface{}, reply interface{}) error {
|
||||
switch method {
|
||||
case "ACL.GetPolicy":
|
||||
atomic.AddInt32(&d.remoteLegacyResolutions, 1)
|
||||
if d.getPolicyFn != nil {
|
||||
return d.getPolicyFn(args.(*structs.ACLPolicyResolveLegacyRequest), reply.(*structs.ACLPolicyResolveLegacyResponse))
|
||||
}
|
||||
panic("Bad Test Implementation: should provide a getPolicyFn to the ACLResolverTestDelegate")
|
||||
case "ACL.TokenRead":
|
||||
atomic.AddInt32(&d.remoteTokenResolutions, 1)
|
||||
if d.tokenReadFn != nil {
|
||||
|
@ -1571,49 +1564,6 @@ func TestACLResolver_Client(t *testing.T) {
|
|||
require.EqualValues(t, 0, delegate.remoteLegacyResolutions)
|
||||
})
|
||||
|
||||
t.Run("Resolve-Identity-Legacy", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
delegate := &ACLResolverTestDelegate{
|
||||
enabled: true,
|
||||
datacenter: "dc1",
|
||||
legacy: true,
|
||||
localTokens: false,
|
||||
localPolicies: false,
|
||||
getPolicyFn: func(_ *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error {
|
||||
reply.Parent = "deny"
|
||||
reply.TTL = 30
|
||||
reply.ETag = "nothing"
|
||||
reply.Policy = &acl.Policy{
|
||||
ID: "not-needed",
|
||||
PolicyRules: acl.PolicyRules{
|
||||
Nodes: []*acl.NodeRule{
|
||||
{
|
||||
Name: "foo",
|
||||
Policy: acl.PolicyWrite,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
r := newTestACLResolver(t, delegate, nil)
|
||||
|
||||
ident, err := r.ResolveTokenToIdentity("found-policy-and-role")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ident)
|
||||
require.Equal(t, "legacy-token", ident.ID())
|
||||
require.EqualValues(t, 0, delegate.localTokenResolutions)
|
||||
require.EqualValues(t, 0, delegate.remoteTokenResolutions)
|
||||
require.EqualValues(t, 0, delegate.localPolicyResolutions)
|
||||
require.EqualValues(t, 0, delegate.remotePolicyResolutions)
|
||||
require.EqualValues(t, 0, delegate.localRoleResolutions)
|
||||
require.EqualValues(t, 0, delegate.remoteRoleResolutions)
|
||||
require.EqualValues(t, 1, delegate.remoteLegacyResolutions)
|
||||
})
|
||||
|
||||
t.Run("Concurrent-Token-Resolve", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
@ -2231,280 +2181,6 @@ func testACLResolver_variousTokens(t *testing.T, delegate *ACLResolverTestDelega
|
|||
})
|
||||
}
|
||||
|
||||
func TestACLResolver_Legacy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("Cached", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cached := false
|
||||
delegate := &ACLResolverTestDelegate{
|
||||
enabled: true,
|
||||
datacenter: "dc1",
|
||||
legacy: true,
|
||||
localTokens: false,
|
||||
localPolicies: false,
|
||||
getPolicyFn: func(_ *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error {
|
||||
if !cached {
|
||||
reply.Parent = "deny"
|
||||
reply.TTL = 30
|
||||
reply.ETag = "nothing"
|
||||
reply.Policy = &acl.Policy{
|
||||
ID: "not-needed",
|
||||
PolicyRules: acl.PolicyRules{
|
||||
Nodes: []*acl.NodeRule{
|
||||
{
|
||||
Name: "foo",
|
||||
Policy: acl.PolicyWrite,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cached = true
|
||||
return nil
|
||||
}
|
||||
return errRPC
|
||||
},
|
||||
}
|
||||
r := newTestACLResolver(t, delegate, nil)
|
||||
|
||||
authz, err := r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
|
||||
// this should be from the cache
|
||||
authz, err = r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
})
|
||||
|
||||
t.Run("Cache-Expiry-Extend", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cached := false
|
||||
delegate := &ACLResolverTestDelegate{
|
||||
enabled: true,
|
||||
datacenter: "dc1",
|
||||
legacy: true,
|
||||
localTokens: false,
|
||||
localPolicies: false,
|
||||
getPolicyFn: func(_ *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error {
|
||||
if !cached {
|
||||
reply.Parent = "deny"
|
||||
reply.TTL = 0
|
||||
reply.ETag = "nothing"
|
||||
reply.Policy = &acl.Policy{
|
||||
ID: "not-needed",
|
||||
PolicyRules: acl.PolicyRules{
|
||||
Nodes: []*acl.NodeRule{
|
||||
{
|
||||
Name: "foo",
|
||||
Policy: acl.PolicyWrite,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cached = true
|
||||
return nil
|
||||
}
|
||||
return errRPC
|
||||
},
|
||||
}
|
||||
r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) {
|
||||
config.Config.ACLTokenTTL = 0
|
||||
})
|
||||
|
||||
authz, err := r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
|
||||
// this should be from the cache
|
||||
authz, err = r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
})
|
||||
|
||||
t.Run("Cache-Expiry-Allow", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cached := false
|
||||
delegate := &ACLResolverTestDelegate{
|
||||
enabled: true,
|
||||
datacenter: "dc1",
|
||||
legacy: true,
|
||||
localTokens: false,
|
||||
localPolicies: false,
|
||||
getPolicyFn: func(_ *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error {
|
||||
if !cached {
|
||||
reply.Parent = "deny"
|
||||
reply.TTL = 0
|
||||
reply.ETag = "nothing"
|
||||
reply.Policy = &acl.Policy{
|
||||
ID: "not-needed",
|
||||
PolicyRules: acl.PolicyRules{
|
||||
Nodes: []*acl.NodeRule{
|
||||
{
|
||||
Name: "foo",
|
||||
Policy: acl.PolicyWrite,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cached = true
|
||||
return nil
|
||||
}
|
||||
return errRPC
|
||||
},
|
||||
}
|
||||
r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) {
|
||||
config.Config.ACLDownPolicy = "allow"
|
||||
config.Config.ACLTokenTTL = 0
|
||||
})
|
||||
|
||||
authz, err := r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
|
||||
// this should be from the cache
|
||||
authz, err = r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("fo", nil))
|
||||
})
|
||||
|
||||
t.Run("Cache-Expiry-Deny", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cached := false
|
||||
delegate := &ACLResolverTestDelegate{
|
||||
enabled: true,
|
||||
datacenter: "dc1",
|
||||
legacy: true,
|
||||
localTokens: false,
|
||||
localPolicies: false,
|
||||
getPolicyFn: func(_ *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error {
|
||||
if !cached {
|
||||
reply.Parent = "deny"
|
||||
reply.TTL = 0
|
||||
reply.ETag = "nothing"
|
||||
reply.Policy = &acl.Policy{
|
||||
ID: "not-needed",
|
||||
PolicyRules: acl.PolicyRules{
|
||||
Nodes: []*acl.NodeRule{
|
||||
{
|
||||
Name: "foo",
|
||||
Policy: acl.PolicyWrite,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cached = true
|
||||
return nil
|
||||
}
|
||||
return errRPC
|
||||
},
|
||||
}
|
||||
r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) {
|
||||
config.Config.ACLDownPolicy = "deny"
|
||||
config.Config.ACLTokenTTL = 0
|
||||
})
|
||||
|
||||
authz, err := r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
|
||||
// this should be from the cache
|
||||
authz, err = r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
})
|
||||
|
||||
t.Run("Cache-Expiry-Async-Cache", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cached := false
|
||||
delegate := &ACLResolverTestDelegate{
|
||||
enabled: true,
|
||||
datacenter: "dc1",
|
||||
legacy: true,
|
||||
localTokens: false,
|
||||
localPolicies: false,
|
||||
getPolicyFn: func(_ *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error {
|
||||
if !cached {
|
||||
reply.Parent = "deny"
|
||||
reply.TTL = 0
|
||||
reply.ETag = "nothing"
|
||||
reply.Policy = &acl.Policy{
|
||||
ID: "not-needed",
|
||||
PolicyRules: acl.PolicyRules{
|
||||
Nodes: []*acl.NodeRule{
|
||||
{
|
||||
Name: "foo",
|
||||
Policy: acl.PolicyWrite,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cached = true
|
||||
return nil
|
||||
}
|
||||
return acl.ErrNotFound
|
||||
},
|
||||
}
|
||||
r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) {
|
||||
config.Config.ACLDownPolicy = "async-cache"
|
||||
config.Config.ACLTokenTTL = 0
|
||||
})
|
||||
|
||||
authz, err := r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
// there is a bit of translation that happens
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo", nil))
|
||||
require.Equal(t, acl.Allow, authz.NodeWrite("foo/bar", nil))
|
||||
require.Equal(t, acl.Deny, authz.NodeWrite("fo", nil))
|
||||
|
||||
// delivered from the cache
|
||||
authz2, err := r.ResolveToken("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, authz)
|
||||
require.True(t, authz == authz2)
|
||||
|
||||
// the go routine spawned will eventually return and this will be a not found error
|
||||
retry.Run(t, func(t *retry.R) {
|
||||
authz3, err := r.ResolveToken("foo")
|
||||
assert.Error(t, err)
|
||||
assert.True(t, acl.IsErrNotFound(err))
|
||||
assert.Nil(t, authz3)
|
||||
})
|
||||
})
|
||||
}
|
||||
func TestACL_filterHealthChecks(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create some health checks.
|
||||
|
|
|
@ -811,15 +811,6 @@ func (policies ACLPolicies) Compile(cache *ACLCaches, entConf *acl.Config) (acl.
|
|||
return authorizer, nil
|
||||
}
|
||||
|
||||
func (policies ACLPolicies) Merge(cache *ACLCaches, entConf *acl.Config) (*acl.Policy, error) {
|
||||
parsed, err := policies.resolveWithCache(cache, entConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return acl.MergePolicies(parsed), nil
|
||||
}
|
||||
|
||||
type ACLRoles []*ACLRole
|
||||
|
||||
// HashKey returns a consistent hash for a set of roles.
|
||||
|
|
|
@ -3,8 +3,9 @@ package structs
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
)
|
||||
|
||||
type ACLCachesConfig struct {
|
||||
|
@ -218,14 +219,6 @@ func (c *ACLCaches) PutAuthorizer(id string, authorizer acl.Authorizer) {
|
|||
c.authorizers.Add(id, &AuthorizerCacheEntry{Authorizer: authorizer, CacheTime: time.Now()})
|
||||
}
|
||||
|
||||
func (c *ACLCaches) PutAuthorizerWithTTL(id string, authorizer acl.Authorizer, ttl time.Duration) {
|
||||
if c == nil || c.authorizers == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.authorizers.Add(id, &AuthorizerCacheEntry{Authorizer: authorizer, CacheTime: time.Now(), TTL: ttl})
|
||||
}
|
||||
|
||||
func (c *ACLCaches) PutRole(roleID string, role *ACLRole) {
|
||||
if c == nil || c.roles == nil {
|
||||
return
|
||||
|
|
|
@ -8,9 +8,6 @@ package structs
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -114,25 +111,3 @@ type ACLBootstrap struct {
|
|||
|
||||
RaftIndex
|
||||
}
|
||||
|
||||
// ACLPolicyResolveLegacyRequest is used to request an ACL by Token SecretID, conditionally
|
||||
// filtering on an ID
|
||||
type ACLPolicyResolveLegacyRequest struct {
|
||||
Datacenter string // The Datacenter the RPC may be sent to
|
||||
ACL string // The Tokens Secret ID
|
||||
ETag string // Caching ETag to prevent resending the policy when not needed
|
||||
QueryOptions
|
||||
}
|
||||
|
||||
// RequestDatacenter returns the DC this request is targeted to.
|
||||
func (r *ACLPolicyResolveLegacyRequest) RequestDatacenter() string {
|
||||
return r.Datacenter
|
||||
}
|
||||
|
||||
type ACLPolicyResolveLegacyResponse struct {
|
||||
ETag string
|
||||
Parent string
|
||||
Policy *acl.Policy
|
||||
TTL time.Duration
|
||||
QueryMeta
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ func TestStructs_Implements(t *testing.T) {
|
|||
_ RPCInfo = &SessionRequest{}
|
||||
_ RPCInfo = &SessionSpecificRequest{}
|
||||
_ RPCInfo = &EventFireRequest{}
|
||||
_ RPCInfo = &ACLPolicyResolveLegacyRequest{}
|
||||
_ RPCInfo = &ACLPolicyBatchGetRequest{}
|
||||
_ RPCInfo = &ACLPolicyGetRequest{}
|
||||
_ RPCInfo = &ACLTokenGetRequest{}
|
||||
|
|
Loading…
Reference in New Issue