mirror of https://github.com/status-im/consul.git
acl: implement IntentionRead/Write methods on ACL interface
This commit is contained in:
parent
437cc76af5
commit
193f93107a
76
acl/acl.go
76
acl/acl.go
|
@ -60,6 +60,13 @@ type ACL interface {
|
|||
// EventWrite determines if a specific event may be fired.
|
||||
EventWrite(string) bool
|
||||
|
||||
// IntentionRead determines if a specific intention can be read.
|
||||
IntentionRead(string) bool
|
||||
|
||||
// IntentionWrite determines if a specific intention can be
|
||||
// created, modified, or deleted.
|
||||
IntentionWrite(string) bool
|
||||
|
||||
// KeyList checks for permission to list keys under a prefix
|
||||
KeyList(string) bool
|
||||
|
||||
|
@ -154,6 +161,14 @@ func (s *StaticACL) EventWrite(string) bool {
|
|||
return s.defaultAllow
|
||||
}
|
||||
|
||||
func (s *StaticACL) IntentionRead(string) bool {
|
||||
return s.defaultAllow
|
||||
}
|
||||
|
||||
func (s *StaticACL) IntentionWrite(string) bool {
|
||||
return s.defaultAllow
|
||||
}
|
||||
|
||||
func (s *StaticACL) KeyRead(string) bool {
|
||||
return s.defaultAllow
|
||||
}
|
||||
|
@ -275,6 +290,9 @@ type PolicyACL struct {
|
|||
// agentRules contains the agent policies
|
||||
agentRules *radix.Tree
|
||||
|
||||
// intentionRules contains the service intention policies
|
||||
intentionRules *radix.Tree
|
||||
|
||||
// keyRules contains the key policies
|
||||
keyRules *radix.Tree
|
||||
|
||||
|
@ -308,6 +326,7 @@ func New(parent ACL, policy *Policy, sentinel sentinel.Evaluator) (*PolicyACL, e
|
|||
p := &PolicyACL{
|
||||
parent: parent,
|
||||
agentRules: radix.New(),
|
||||
intentionRules: radix.New(),
|
||||
keyRules: radix.New(),
|
||||
nodeRules: radix.New(),
|
||||
serviceRules: radix.New(),
|
||||
|
@ -347,6 +366,25 @@ func New(parent ACL, policy *Policy, sentinel sentinel.Evaluator) (*PolicyACL, e
|
|||
sentinelPolicy: sp.Sentinel,
|
||||
}
|
||||
p.serviceRules.Insert(sp.Name, policyRule)
|
||||
|
||||
// Determine the intention. The intention could be blank (not set).
|
||||
// If the intention is not set, the value depends on the value of
|
||||
// the service policy.
|
||||
intention := sp.Intentions
|
||||
if intention == "" {
|
||||
switch sp.Policy {
|
||||
case PolicyRead, PolicyWrite:
|
||||
intention = PolicyRead
|
||||
default:
|
||||
intention = PolicyDeny
|
||||
}
|
||||
}
|
||||
|
||||
policyRule = PolicyRule{
|
||||
aclPolicy: intention,
|
||||
sentinelPolicy: sp.Sentinel,
|
||||
}
|
||||
p.intentionRules.Insert(sp.Name, policyRule)
|
||||
}
|
||||
|
||||
// Load the session policy
|
||||
|
@ -455,6 +493,44 @@ func (p *PolicyACL) EventWrite(name string) bool {
|
|||
return p.parent.EventWrite(name)
|
||||
}
|
||||
|
||||
// IntentionRead checks if writing (creating, updating, or deleting) of an
|
||||
// intention is allowed.
|
||||
func (p *PolicyACL) IntentionRead(prefix string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.intentionRules.LongestPrefix(prefix)
|
||||
if ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// No matching rule, use the parent.
|
||||
return p.parent.IntentionRead(prefix)
|
||||
}
|
||||
|
||||
// IntentionWrite checks if writing (creating, updating, or deleting) of an
|
||||
// intention is allowed.
|
||||
func (p *PolicyACL) IntentionWrite(prefix string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.intentionRules.LongestPrefix(prefix)
|
||||
if ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// No matching rule, use the parent.
|
||||
return p.parent.IntentionWrite(prefix)
|
||||
}
|
||||
|
||||
// KeyRead returns if a key is allowed to be read
|
||||
func (p *PolicyACL) KeyRead(key string) bool {
|
||||
// Look for a matching rule
|
||||
|
|
|
@ -53,6 +53,9 @@ func TestStaticACL(t *testing.T) {
|
|||
if !all.EventWrite("foobar") {
|
||||
t.Fatalf("should allow")
|
||||
}
|
||||
if !all.IntentionWrite("foobar") {
|
||||
t.Fatalf("should allow")
|
||||
}
|
||||
if !all.KeyRead("foobar") {
|
||||
t.Fatalf("should allow")
|
||||
}
|
||||
|
@ -123,6 +126,9 @@ func TestStaticACL(t *testing.T) {
|
|||
if none.EventWrite("") {
|
||||
t.Fatalf("should not allow")
|
||||
}
|
||||
if none.IntentionWrite("foo") {
|
||||
t.Fatalf("should not allow")
|
||||
}
|
||||
if none.KeyRead("foobar") {
|
||||
t.Fatalf("should not allow")
|
||||
}
|
||||
|
@ -187,6 +193,9 @@ func TestStaticACL(t *testing.T) {
|
|||
if !manage.EventWrite("foobar") {
|
||||
t.Fatalf("should allow")
|
||||
}
|
||||
if !manage.IntentionWrite("foobar") {
|
||||
t.Fatalf("should allow")
|
||||
}
|
||||
if !manage.KeyRead("foobar") {
|
||||
t.Fatalf("should allow")
|
||||
}
|
||||
|
@ -307,6 +316,12 @@ func TestPolicyACL(t *testing.T) {
|
|||
&ServicePolicy{
|
||||
Name: "barfoo",
|
||||
Policy: PolicyWrite,
|
||||
Intentions: PolicyWrite,
|
||||
},
|
||||
&ServicePolicy{
|
||||
Name: "intbaz",
|
||||
Policy: PolicyWrite,
|
||||
Intentions: PolicyDeny,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -344,6 +359,31 @@ func TestPolicyACL(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test the intentions
|
||||
type intentioncase struct {
|
||||
inp string
|
||||
read bool
|
||||
write bool
|
||||
}
|
||||
icases := []intentioncase{
|
||||
{"other", true, false},
|
||||
{"foo", true, false},
|
||||
{"bar", false, false},
|
||||
{"foobar", true, false},
|
||||
{"barfo", false, false},
|
||||
{"barfoo", true, true},
|
||||
{"barfoo2", true, true},
|
||||
{"intbaz", false, false},
|
||||
}
|
||||
for _, c := range icases {
|
||||
if c.read != acl.IntentionRead(c.inp) {
|
||||
t.Fatalf("Read fail: %#v", c)
|
||||
}
|
||||
if c.write != acl.IntentionWrite(c.inp) {
|
||||
t.Fatalf("Write fail: %#v", c)
|
||||
}
|
||||
}
|
||||
|
||||
// Test the services
|
||||
type servicecase struct {
|
||||
inp string
|
||||
|
|
Loading…
Reference in New Issue