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 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
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -305,8 +314,14 @@ func TestPolicyACL(t *testing.T) {
|
||||||
Policy: PolicyDeny,
|
Policy: PolicyDeny,
|
||||||
},
|
},
|
||||||
&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
|
||||||
|
|
Loading…
Reference in New Issue