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
|
// 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue