mirror of https://github.com/status-im/consul.git
consul: Resolve parent ACLs
This commit is contained in:
parent
2fe94709e6
commit
10db4c7c8f
|
@ -100,7 +100,7 @@ func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) {
|
|||
|
||||
// Handle the happy path
|
||||
if err == nil {
|
||||
return s.useACLPolicy(id, cached, &out)
|
||||
return s.useACLPolicy(id, authDC, cached, &out)
|
||||
}
|
||||
|
||||
// Check for not-found
|
||||
|
@ -125,7 +125,7 @@ func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) {
|
|||
}
|
||||
|
||||
// useACLPolicy handles an ACLPolicy response
|
||||
func (s *Server) useACLPolicy(id string, cached *aclCacheEntry, p *structs.ACLPolicy) (acl.ACL, error) {
|
||||
func (s *Server) useACLPolicy(id, authDC string, cached *aclCacheEntry, p *structs.ACLPolicy) (acl.ACL, error) {
|
||||
// Check if we can used the cached policy
|
||||
if cached != nil && cached.ETag == p.ETag {
|
||||
if p.TTL > 0 {
|
||||
|
@ -140,17 +140,18 @@ func (s *Server) useACLPolicy(id string, cached *aclCacheEntry, p *structs.ACLPo
|
|||
if ok {
|
||||
compiled = raw.(acl.ACL)
|
||||
} else {
|
||||
// Determine the root policy
|
||||
var root acl.ACL
|
||||
switch p.Root {
|
||||
case "allow":
|
||||
root = acl.AllowAll()
|
||||
default:
|
||||
root = acl.DenyAll()
|
||||
// Resolve the parent policy
|
||||
parent := acl.RootACL(p.Parent)
|
||||
if parent == nil {
|
||||
var err error
|
||||
parent, err = s.lookupACL(p.Parent, authDC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the ACL
|
||||
acl, err := acl.New(root, p.Policy)
|
||||
acl, err := acl.New(parent, p.Policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -94,23 +94,23 @@ func (a *ACL) GetPolicy(args *structs.ACLPolicyRequest, reply *structs.ACLPolicy
|
|||
}
|
||||
|
||||
// Get the policy via the cache
|
||||
policy, err := a.srv.aclAuthCache.GetACLPolicy(args.ACL)
|
||||
parent, policy, err := a.srv.aclAuthCache.GetACLPolicy(args.ACL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate an ETag
|
||||
conf := a.srv.config
|
||||
etag := fmt.Sprintf("%s:%s", conf.ACLDefaultPolicy, policy.ID)
|
||||
etag := fmt.Sprintf("%s:%s", parent, policy.ID)
|
||||
|
||||
// Setup the response
|
||||
reply.ETag = etag
|
||||
reply.Root = conf.ACLDefaultPolicy
|
||||
reply.TTL = conf.ACLTTL
|
||||
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
|
||||
|
|
|
@ -295,6 +295,63 @@ func TestACL_NonAuthority_Found(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestACL_NonAuthority_Management(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1" // Enable ACLs!
|
||||
c.ACLMasterToken = "foobar"
|
||||
c.ACLDefaultPolicy = "deny"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
client := rpcClient(t, s1)
|
||||
defer client.Close()
|
||||
|
||||
dir2, s2 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1" // Enable ACLs!
|
||||
c.ACLDefaultPolicy = "deny"
|
||||
c.Bootstrap = false // Disable bootstrap
|
||||
})
|
||||
defer os.RemoveAll(dir2)
|
||||
defer s2.Shutdown()
|
||||
|
||||
// Try to join
|
||||
addr := fmt.Sprintf("127.0.0.1:%d",
|
||||
s1.config.SerfLANConfig.MemberlistConfig.BindPort)
|
||||
if _, err := s2.JoinLAN([]string{addr}); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
testutil.WaitForResult(func() (bool, error) {
|
||||
p1, _ := s1.raftPeers.Peers()
|
||||
return len(p1) == 2, errors.New(fmt.Sprintf("%v", p1))
|
||||
}, func(err error) {
|
||||
t.Fatalf("should have 2 peers: %v", err)
|
||||
})
|
||||
testutil.WaitForLeader(t, client.Call, "dc1")
|
||||
|
||||
// find the non-authoritative server
|
||||
var nonAuth *Server
|
||||
if !s1.IsLeader() {
|
||||
nonAuth = s1
|
||||
} else {
|
||||
nonAuth = s2
|
||||
}
|
||||
|
||||
// Resolve the token
|
||||
acl, err := nonAuth.resolveToken("foobar")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if acl == nil {
|
||||
t.Fatalf("missing acl")
|
||||
}
|
||||
|
||||
// Check the policy, should allow all
|
||||
if !acl.KeyRead("foo/test") {
|
||||
t.Fatalf("unexpected failed read")
|
||||
}
|
||||
}
|
||||
|
||||
func TestACL_DownPolicy_Deny(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
|
|
|
@ -487,7 +487,7 @@ type IndexedACLs struct {
|
|||
|
||||
type ACLPolicy struct {
|
||||
ETag string
|
||||
Root string
|
||||
Parent string
|
||||
Policy *acl.Policy
|
||||
TTL time.Duration
|
||||
QueryMeta
|
||||
|
|
Loading…
Reference in New Issue