acl: implement IntentionRead/Write methods on ACL interface

This commit is contained in:
Mitchell Hashimoto 2018-03-04 00:38:04 -08:00
parent 437cc76af5
commit 193f93107a
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 118 additions and 2 deletions

View File

@ -60,6 +60,13 @@ type ACL interface {
// EventWrite determines if a specific event may be fired. // EventWrite determines if a specific event may be fired.
EventWrite(string) bool 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 checks for permission to list keys under a prefix
KeyList(string) bool KeyList(string) bool
@ -154,6 +161,14 @@ func (s *StaticACL) EventWrite(string) bool {
return s.defaultAllow 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 { func (s *StaticACL) KeyRead(string) bool {
return s.defaultAllow return s.defaultAllow
} }
@ -275,6 +290,9 @@ type PolicyACL struct {
// agentRules contains the agent policies // agentRules contains the agent policies
agentRules *radix.Tree agentRules *radix.Tree
// intentionRules contains the service intention policies
intentionRules *radix.Tree
// keyRules contains the key policies // keyRules contains the key policies
keyRules *radix.Tree keyRules *radix.Tree
@ -308,6 +326,7 @@ func New(parent ACL, policy *Policy, sentinel sentinel.Evaluator) (*PolicyACL, e
p := &PolicyACL{ p := &PolicyACL{
parent: parent, parent: parent,
agentRules: radix.New(), agentRules: radix.New(),
intentionRules: radix.New(),
keyRules: radix.New(), keyRules: radix.New(),
nodeRules: radix.New(), nodeRules: radix.New(),
serviceRules: radix.New(), serviceRules: radix.New(),
@ -347,6 +366,25 @@ func New(parent ACL, policy *Policy, sentinel sentinel.Evaluator) (*PolicyACL, e
sentinelPolicy: sp.Sentinel, sentinelPolicy: sp.Sentinel,
} }
p.serviceRules.Insert(sp.Name, policyRule) 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 // Load the session policy
@ -455,6 +493,44 @@ func (p *PolicyACL) EventWrite(name string) bool {
return p.parent.EventWrite(name) 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 // KeyRead returns if a key is allowed to be read
func (p *PolicyACL) KeyRead(key string) bool { func (p *PolicyACL) KeyRead(key string) bool {
// Look for a matching rule // Look for a matching rule

View File

@ -53,6 +53,9 @@ func TestStaticACL(t *testing.T) {
if !all.EventWrite("foobar") { if !all.EventWrite("foobar") {
t.Fatalf("should allow") t.Fatalf("should allow")
} }
if !all.IntentionWrite("foobar") {
t.Fatalf("should allow")
}
if !all.KeyRead("foobar") { if !all.KeyRead("foobar") {
t.Fatalf("should allow") t.Fatalf("should allow")
} }
@ -123,6 +126,9 @@ func TestStaticACL(t *testing.T) {
if none.EventWrite("") { if none.EventWrite("") {
t.Fatalf("should not allow") t.Fatalf("should not allow")
} }
if none.IntentionWrite("foo") {
t.Fatalf("should not allow")
}
if none.KeyRead("foobar") { if none.KeyRead("foobar") {
t.Fatalf("should not allow") t.Fatalf("should not allow")
} }
@ -187,6 +193,9 @@ func TestStaticACL(t *testing.T) {
if !manage.EventWrite("foobar") { if !manage.EventWrite("foobar") {
t.Fatalf("should allow") t.Fatalf("should allow")
} }
if !manage.IntentionWrite("foobar") {
t.Fatalf("should allow")
}
if !manage.KeyRead("foobar") { if !manage.KeyRead("foobar") {
t.Fatalf("should allow") t.Fatalf("should allow")
} }
@ -307,6 +316,12 @@ func TestPolicyACL(t *testing.T) {
&ServicePolicy{ &ServicePolicy{
Name: "barfoo", Name: "barfoo",
Policy: PolicyWrite, 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 // Test the services
type servicecase struct { type servicecase struct {
inp string inp string