consul: Starting token enforcement
This commit is contained in:
parent
9c2b7b9e10
commit
17ee7f5057
|
@ -17,11 +17,22 @@ const (
|
|||
// rootDenied is returned when attempting to resolve a root ACL
|
||||
rootDenied = "Cannot resolve root ACL"
|
||||
|
||||
// permissionDenied is returned when an ACL based rejection happens
|
||||
permissionDenied = "Permission denied"
|
||||
|
||||
// aclDisabled is returned when ACL changes are not permitted
|
||||
// since they are disabled.
|
||||
aclDisabled = "ACL support disabled"
|
||||
|
||||
// anonymousToken is the token ID we re-write to if there
|
||||
// is no token ID provided
|
||||
anonymousToken = "anonymous"
|
||||
)
|
||||
|
||||
var (
|
||||
permissionDeniedErr = errors.New(permissionDenied)
|
||||
)
|
||||
|
||||
// aclCacheEntry is used to cache non-authoritative ACL's
|
||||
// If non-authoritative, then we must respect a TTL
|
||||
type aclCacheEntry struct {
|
||||
|
@ -42,9 +53,10 @@ func (s *Server) aclFault(id string) (string, string, error) {
|
|||
return "", "", errors.New(aclNotFound)
|
||||
}
|
||||
|
||||
// Management tokens have no policy and inherit from allow
|
||||
// Management tokens have no policy and inherit from the
|
||||
// 'manage' root policy
|
||||
if acl.Type == structs.ACLTypeManagement {
|
||||
return "allow", "", nil
|
||||
return "manage", "", nil
|
||||
}
|
||||
|
||||
// Otherwise use the base policy
|
||||
|
|
|
@ -22,6 +22,18 @@ func (a *ACL) Apply(args *structs.ACLRequest, reply *string) error {
|
|||
}
|
||||
defer metrics.MeasureSince([]string{"consul", "acl", "apply"}, time.Now())
|
||||
|
||||
// Verify we are allowed to serve this request
|
||||
if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
|
||||
return fmt.Errorf(aclDisabled)
|
||||
}
|
||||
|
||||
// Verify token is permitted to list ACLs
|
||||
if acl, err := a.srv.resolveToken(args.Token); err != nil {
|
||||
return err
|
||||
} else if acl == nil || !acl.ACLModify() {
|
||||
return permissionDeniedErr
|
||||
}
|
||||
|
||||
switch args.Op {
|
||||
case structs.ACLSet:
|
||||
// Verify the ACL type
|
||||
|
@ -71,6 +83,11 @@ func (a *ACL) Get(args *structs.ACLSpecificRequest,
|
|||
return err
|
||||
}
|
||||
|
||||
// Verify we are allowed to serve this request
|
||||
if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
|
||||
return fmt.Errorf(aclDisabled)
|
||||
}
|
||||
|
||||
// Get the local state
|
||||
state := a.srv.fsm.State()
|
||||
return a.srv.blockingRPC(&args.QueryOptions,
|
||||
|
@ -93,6 +110,11 @@ func (a *ACL) GetPolicy(args *structs.ACLPolicyRequest, reply *structs.ACLPolicy
|
|||
return err
|
||||
}
|
||||
|
||||
// Verify we are allowed to serve this request
|
||||
if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
|
||||
return fmt.Errorf(aclDisabled)
|
||||
}
|
||||
|
||||
// Get the policy via the cache
|
||||
parent, policy, err := a.srv.aclAuthCache.GetACLPolicy(args.ACL)
|
||||
if err != nil {
|
||||
|
@ -123,6 +145,18 @@ func (a *ACL) List(args *structs.DCSpecificRequest,
|
|||
return err
|
||||
}
|
||||
|
||||
// Verify we are allowed to serve this request
|
||||
if a.srv.config.ACLDatacenter != a.srv.config.Datacenter {
|
||||
return fmt.Errorf(aclDisabled)
|
||||
}
|
||||
|
||||
// Verify token is permitted to list ACLs
|
||||
if acl, err := a.srv.resolveToken(args.Token); err != nil {
|
||||
return err
|
||||
} else if acl == nil || !acl.ACLList() {
|
||||
return permissionDeniedErr
|
||||
}
|
||||
|
||||
// Get the local state
|
||||
state := a.srv.fsm.State()
|
||||
return a.srv.blockingRPC(&args.QueryOptions,
|
||||
|
|
|
@ -2,6 +2,7 @@ package consul
|
|||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -10,7 +11,10 @@ import (
|
|||
)
|
||||
|
||||
func TestACLEndpoint_Apply(t *testing.T) {
|
||||
dir1, s1 := testServer(t)
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
client := rpcClient(t, s1)
|
||||
|
@ -25,6 +29,7 @@ func TestACLEndpoint_Apply(t *testing.T) {
|
|||
Name: "User token",
|
||||
Type: structs.ACLTypeClient,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var out string
|
||||
if err := client.Call("ACL.Apply", &arg, &out); err != nil {
|
||||
|
@ -65,8 +70,10 @@ func TestACLEndpoint_Apply(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestACLEndpoint_Get(t *testing.T) {
|
||||
dir1, s1 := testServer(t)
|
||||
func TestACLEndpoint_Apply_Denied(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
client := rpcClient(t, s1)
|
||||
|
@ -83,6 +90,34 @@ func TestACLEndpoint_Get(t *testing.T) {
|
|||
},
|
||||
}
|
||||
var out string
|
||||
err := client.Call("ACL.Apply", &arg, &out)
|
||||
if err == nil || !strings.Contains(err.Error(), permissionDenied) {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestACLEndpoint_Get(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
client := rpcClient(t, s1)
|
||||
defer client.Close()
|
||||
|
||||
testutil.WaitForLeader(t, client.Call, "dc1")
|
||||
|
||||
arg := structs.ACLRequest{
|
||||
Datacenter: "dc1",
|
||||
Op: structs.ACLSet,
|
||||
ACL: structs.ACL{
|
||||
Name: "User token",
|
||||
Type: structs.ACLTypeClient,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var out string
|
||||
if err := client.Call("ACL.Apply", &arg, &out); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
@ -109,7 +144,10 @@ func TestACLEndpoint_Get(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestACLEndpoint_GetPolicy(t *testing.T) {
|
||||
dir1, s1 := testServer(t)
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
client := rpcClient(t, s1)
|
||||
|
@ -124,6 +162,7 @@ func TestACLEndpoint_GetPolicy(t *testing.T) {
|
|||
Name: "User token",
|
||||
Type: structs.ACLTypeClient,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var out string
|
||||
if err := client.Call("ACL.Apply", &arg, &out); err != nil {
|
||||
|
@ -162,7 +201,10 @@ func TestACLEndpoint_GetPolicy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestACLEndpoint_List(t *testing.T) {
|
||||
dir1, s1 := testServer(t)
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
client := rpcClient(t, s1)
|
||||
|
@ -179,6 +221,7 @@ func TestACLEndpoint_List(t *testing.T) {
|
|||
Name: "User token",
|
||||
Type: structs.ACLTypeClient,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var out string
|
||||
if err := client.Call("ACL.Apply", &arg, &out); err != nil {
|
||||
|
@ -188,7 +231,8 @@ func TestACLEndpoint_List(t *testing.T) {
|
|||
}
|
||||
|
||||
getR := structs.DCSpecificRequest{
|
||||
Datacenter: "dc1",
|
||||
Datacenter: "dc1",
|
||||
QueryOptions: structs.QueryOptions{Token: "root"},
|
||||
}
|
||||
var acls structs.IndexedACLs
|
||||
if err := client.Call("ACL.List", &getR, &acls); err != nil {
|
||||
|
@ -198,11 +242,16 @@ func TestACLEndpoint_List(t *testing.T) {
|
|||
if acls.Index == 0 {
|
||||
t.Fatalf("Bad: %v", acls)
|
||||
}
|
||||
if len(acls.ACLs) != 5 {
|
||||
|
||||
// 5 + anonymous + master
|
||||
if len(acls.ACLs) != 7 {
|
||||
t.Fatalf("Bad: %v", acls.ACLs)
|
||||
}
|
||||
for i := 0; i < len(acls.ACLs); i++ {
|
||||
s := acls.ACLs[i]
|
||||
if s.ID == anonymousToken || s.ID == "root" {
|
||||
continue
|
||||
}
|
||||
if !strContains(ids, s.ID) {
|
||||
t.Fatalf("bad: %v", s)
|
||||
}
|
||||
|
@ -211,3 +260,24 @@ func TestACLEndpoint_List(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestACLEndpoint_List_Denied(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
client := rpcClient(t, s1)
|
||||
defer client.Close()
|
||||
|
||||
testutil.WaitForLeader(t, client.Call, "dc1")
|
||||
|
||||
getR := structs.DCSpecificRequest{
|
||||
Datacenter: "dc1",
|
||||
}
|
||||
var acls structs.IndexedACLs
|
||||
err := client.Call("ACL.List", &getR, &acls)
|
||||
if err == nil || !strings.Contains(err.Error(), permissionDenied) {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ func TestACL_Authority_NotFound(t *testing.T) {
|
|||
func TestACL_Authority_Found(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1" // Enable ACLs!
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
|
@ -93,6 +94,7 @@ func TestACL_Authority_Found(t *testing.T) {
|
|||
Type: structs.ACLTypeClient,
|
||||
Rules: testACLPolicy,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var id string
|
||||
if err := client.Call("ACL.Apply", &arg, &id); err != nil {
|
||||
|
@ -250,6 +252,7 @@ func TestACL_NonAuthority_NotFound(t *testing.T) {
|
|||
func TestACL_NonAuthority_Found(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
|
@ -287,6 +290,7 @@ func TestACL_NonAuthority_Found(t *testing.T) {
|
|||
Type: structs.ACLTypeClient,
|
||||
Rules: testACLPolicy,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var id string
|
||||
if err := client.Call("ACL.Apply", &arg, &id); err != nil {
|
||||
|
@ -380,6 +384,7 @@ func TestACL_DownPolicy_Deny(t *testing.T) {
|
|||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLDownPolicy = "deny"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
|
@ -418,6 +423,7 @@ func TestACL_DownPolicy_Deny(t *testing.T) {
|
|||
Type: structs.ACLTypeClient,
|
||||
Rules: testACLPolicy,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var id string
|
||||
if err := client.Call("ACL.Apply", &arg, &id); err != nil {
|
||||
|
@ -452,6 +458,7 @@ func TestACL_DownPolicy_Allow(t *testing.T) {
|
|||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLDownPolicy = "allow"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
|
@ -490,6 +497,7 @@ func TestACL_DownPolicy_Allow(t *testing.T) {
|
|||
Type: structs.ACLTypeClient,
|
||||
Rules: testACLPolicy,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var id string
|
||||
if err := client.Call("ACL.Apply", &arg, &id); err != nil {
|
||||
|
@ -525,6 +533,7 @@ func TestACL_DownPolicy_ExtendCache(t *testing.T) {
|
|||
c.ACLDatacenter = "dc1"
|
||||
c.ACLTTL = 0
|
||||
c.ACLDownPolicy = "extend-cache"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
|
@ -564,6 +573,7 @@ func TestACL_DownPolicy_ExtendCache(t *testing.T) {
|
|||
Type: structs.ACLTypeClient,
|
||||
Rules: testACLPolicy,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var id string
|
||||
if err := client.Call("ACL.Apply", &arg, &id); err != nil {
|
||||
|
@ -606,6 +616,7 @@ func TestACL_DownPolicy_ExtendCache(t *testing.T) {
|
|||
func TestACL_MultiDC_Found(t *testing.T) {
|
||||
dir1, s1 := testServerWithConfig(t, func(c *Config) {
|
||||
c.ACLDatacenter = "dc1"
|
||||
c.ACLMasterToken = "root"
|
||||
})
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
|
@ -638,6 +649,7 @@ func TestACL_MultiDC_Found(t *testing.T) {
|
|||
Type: structs.ACLTypeClient,
|
||||
Rules: testACLPolicy,
|
||||
},
|
||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||
}
|
||||
var id string
|
||||
if err := client.Call("ACL.Apply", &arg, &id); err != nil {
|
||||
|
|
Loading…
Reference in New Issue