consul: Resolve parent ACLs

This commit is contained in:
Armon Dadgar 2014-08-12 10:54:56 -07:00
parent 2fe94709e6
commit 10db4c7c8f
4 changed files with 72 additions and 14 deletions

View File

@ -100,7 +100,7 @@ func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) {
// Handle the happy path // Handle the happy path
if err == nil { if err == nil {
return s.useACLPolicy(id, cached, &out) return s.useACLPolicy(id, authDC, cached, &out)
} }
// Check for not-found // Check for not-found
@ -125,7 +125,7 @@ func (s *Server) lookupACL(id, authDC string) (acl.ACL, error) {
} }
// useACLPolicy handles an ACLPolicy response // 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 // Check if we can used the cached policy
if cached != nil && cached.ETag == p.ETag { if cached != nil && cached.ETag == p.ETag {
if p.TTL > 0 { if p.TTL > 0 {
@ -140,17 +140,18 @@ func (s *Server) useACLPolicy(id string, cached *aclCacheEntry, p *structs.ACLPo
if ok { if ok {
compiled = raw.(acl.ACL) compiled = raw.(acl.ACL)
} else { } else {
// Determine the root policy // Resolve the parent policy
var root acl.ACL parent := acl.RootACL(p.Parent)
switch p.Root { if parent == nil {
case "allow": var err error
root = acl.AllowAll() parent, err = s.lookupACL(p.Parent, authDC)
default: if err != nil {
root = acl.DenyAll() return nil, err
}
} }
// Compile the ACL // Compile the ACL
acl, err := acl.New(root, p.Policy) acl, err := acl.New(parent, p.Policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -94,23 +94,23 @@ func (a *ACL) GetPolicy(args *structs.ACLPolicyRequest, reply *structs.ACLPolicy
} }
// Get the policy via the cache // 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 { if err != nil {
return err return err
} }
// Generate an ETag // Generate an ETag
conf := a.srv.config conf := a.srv.config
etag := fmt.Sprintf("%s:%s", conf.ACLDefaultPolicy, policy.ID) etag := fmt.Sprintf("%s:%s", parent, policy.ID)
// Setup the response // Setup the response
reply.ETag = etag reply.ETag = etag
reply.Root = conf.ACLDefaultPolicy
reply.TTL = conf.ACLTTL reply.TTL = conf.ACLTTL
a.srv.setQueryMeta(&reply.QueryMeta) a.srv.setQueryMeta(&reply.QueryMeta)
// Only send the policy on an Etag mis-match // Only send the policy on an Etag mis-match
if args.ETag != etag { if args.ETag != etag {
reply.Parent = parent
reply.Policy = policy reply.Policy = policy
} }
return nil return nil

View File

@ -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) { func TestACL_DownPolicy_Deny(t *testing.T) {
dir1, s1 := testServerWithConfig(t, func(c *Config) { dir1, s1 := testServerWithConfig(t, func(c *Config) {
c.ACLDatacenter = "dc1" c.ACLDatacenter = "dc1"

View File

@ -487,7 +487,7 @@ type IndexedACLs struct {
type ACLPolicy struct { type ACLPolicy struct {
ETag string ETag string
Root string Parent string
Policy *acl.Policy Policy *acl.Policy
TTL time.Duration TTL time.Duration
QueryMeta QueryMeta