mirror of https://github.com/status-im/consul.git
Merge pull request #4438 from hashicorp/bugfix/keyring-acl
ACL Bug Fixes
This commit is contained in:
commit
fa7ceb08a0
242
acl/acl.go
242
acl/acl.go
|
@ -328,6 +328,34 @@ type PolicyACL struct {
|
|||
operatorRule string
|
||||
}
|
||||
|
||||
func enforce(rule string, requiredPermission string) (allow, recurse bool) {
|
||||
switch rule {
|
||||
case PolicyWrite:
|
||||
// grants read, list and write permissions
|
||||
return true, false
|
||||
case PolicyList:
|
||||
// grants read and list permissions
|
||||
if requiredPermission == PolicyList || requiredPermission == PolicyRead {
|
||||
return true, false
|
||||
} else {
|
||||
return false, false
|
||||
}
|
||||
case PolicyRead:
|
||||
// grants just read permissions
|
||||
if requiredPermission == PolicyRead {
|
||||
return true, false
|
||||
} else {
|
||||
return false, false
|
||||
}
|
||||
case PolicyDeny:
|
||||
// explicit denial - do not recurse
|
||||
return false, false
|
||||
default:
|
||||
// need to recurse as there was no specific policy set
|
||||
return false, true
|
||||
}
|
||||
}
|
||||
|
||||
// New is used to construct a policy based ACL from a set of policies
|
||||
// and a parent policy to resolve missing cases.
|
||||
func New(parent ACL, policy *Policy, sentinel sentinel.Evaluator) (*PolicyACL, error) {
|
||||
|
@ -433,14 +461,9 @@ func (p *PolicyACL) ACLModify() bool {
|
|||
// node.
|
||||
func (p *PolicyACL) AgentRead(node string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.agentRules.LongestPrefix(node)
|
||||
|
||||
if ok {
|
||||
switch rule {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if _, rule, ok := p.agentRules.LongestPrefix(node); ok {
|
||||
if allow, recurse := enforce(rule.(string), PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,11 +478,8 @@ func (p *PolicyACL) AgentWrite(node string) bool {
|
|||
_, rule, ok := p.agentRules.LongestPrefix(node)
|
||||
|
||||
if ok {
|
||||
switch rule {
|
||||
case PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,15 +497,12 @@ func (p *PolicyACL) Snapshot() bool {
|
|||
func (p *PolicyACL) EventRead(name string) bool {
|
||||
// Longest-prefix match on event names
|
||||
if _, rule, ok := p.eventRules.LongestPrefix(name); ok {
|
||||
switch rule {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(rule.(string), PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing matched, use parent
|
||||
// No matching rule, use the parent.
|
||||
return p.parent.EventRead(name)
|
||||
}
|
||||
|
||||
|
@ -494,7 +511,9 @@ func (p *PolicyACL) EventRead(name string) bool {
|
|||
func (p *PolicyACL) EventWrite(name string) bool {
|
||||
// Longest-prefix match event names
|
||||
if _, rule, ok := p.eventRules.LongestPrefix(name); ok {
|
||||
return rule == PolicyWrite
|
||||
if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
// No match, use parent
|
||||
|
@ -512,14 +531,10 @@ func (p *PolicyACL) IntentionDefaultAllow() bool {
|
|||
// 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 {
|
||||
if _, rule, ok := p.intentionRules.LongestPrefix(prefix); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -531,14 +546,10 @@ func (p *PolicyACL) IntentionRead(prefix string) bool {
|
|||
// 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 {
|
||||
if _, rule, ok := p.intentionRules.LongestPrefix(prefix); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,14 +560,10 @@ func (p *PolicyACL) IntentionWrite(prefix string) bool {
|
|||
// KeyRead returns if a key is allowed to be read
|
||||
func (p *PolicyACL) KeyRead(key string) bool {
|
||||
// Look for a matching rule
|
||||
_, rule, ok := p.keyRules.LongestPrefix(key)
|
||||
if ok {
|
||||
if _, rule, ok := p.keyRules.LongestPrefix(key); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyRead, PolicyWrite, PolicyList:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,14 +574,10 @@ func (p *PolicyACL) KeyRead(key string) bool {
|
|||
// KeyList returns if a key is allowed to be listed
|
||||
func (p *PolicyACL) KeyList(key string) bool {
|
||||
// Look for a matching rule
|
||||
_, rule, ok := p.keyRules.LongestPrefix(key)
|
||||
if ok {
|
||||
if _, rule, ok := p.keyRules.LongestPrefix(key); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyList, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyList); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -585,13 +588,12 @@ func (p *PolicyACL) KeyList(key string) bool {
|
|||
// KeyWrite returns if a key is allowed to be written
|
||||
func (p *PolicyACL) KeyWrite(key string, scope sentinel.ScopeFn) bool {
|
||||
// Look for a matching rule
|
||||
_, rule, ok := p.keyRules.LongestPrefix(key)
|
||||
if ok {
|
||||
if _, rule, ok := p.keyRules.LongestPrefix(key); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyWrite:
|
||||
return p.executeCodePolicy(&pr.sentinelPolicy, scope)
|
||||
default:
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse {
|
||||
if allow {
|
||||
return p.executeCodePolicy(&pr.sentinelPolicy, scope)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -636,48 +638,48 @@ func (p *PolicyACL) KeyWritePrefix(prefix string) bool {
|
|||
// KeyringRead is used to determine if the keyring can be
|
||||
// read by the current ACL token.
|
||||
func (p *PolicyACL) KeyringRead() bool {
|
||||
switch p.keyringRule {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
case PolicyDeny:
|
||||
return false
|
||||
default:
|
||||
return p.parent.KeyringRead()
|
||||
if allow, recurse := enforce(p.keyringRule, PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
|
||||
return p.parent.KeyringRead()
|
||||
}
|
||||
|
||||
// KeyringWrite determines if the keyring can be manipulated.
|
||||
func (p *PolicyACL) KeyringWrite() bool {
|
||||
if p.keyringRule == PolicyWrite {
|
||||
return true
|
||||
if allow, recurse := enforce(p.keyringRule, PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
|
||||
return p.parent.KeyringWrite()
|
||||
}
|
||||
|
||||
// OperatorRead determines if the read-only operator functions are allowed.
|
||||
func (p *PolicyACL) OperatorRead() bool {
|
||||
switch p.operatorRule {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
case PolicyDeny:
|
||||
return false
|
||||
default:
|
||||
return p.parent.OperatorRead()
|
||||
if allow, recurse := enforce(p.operatorRule, PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
|
||||
return p.parent.OperatorRead()
|
||||
}
|
||||
|
||||
// OperatorWrite determines if the state-changing operator functions are
|
||||
// allowed.
|
||||
func (p *PolicyACL) OperatorWrite() bool {
|
||||
if allow, recurse := enforce(p.operatorRule, PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
|
||||
return p.parent.OperatorWrite()
|
||||
}
|
||||
|
||||
// NodeRead checks if reading (discovery) of a node is allowed
|
||||
func (p *PolicyACL) NodeRead(name string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.nodeRules.LongestPrefix(name)
|
||||
|
||||
if ok {
|
||||
if _, rule, ok := p.nodeRules.LongestPrefix(name); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -688,15 +690,10 @@ func (p *PolicyACL) NodeRead(name string) bool {
|
|||
// NodeWrite checks if writing (registering) a node is allowed
|
||||
func (p *PolicyACL) NodeWrite(name string, scope sentinel.ScopeFn) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.nodeRules.LongestPrefix(name)
|
||||
|
||||
if ok {
|
||||
if _, rule, ok := p.nodeRules.LongestPrefix(name); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -704,27 +701,13 @@ func (p *PolicyACL) NodeWrite(name string, scope sentinel.ScopeFn) bool {
|
|||
return p.parent.NodeWrite(name, scope)
|
||||
}
|
||||
|
||||
// OperatorWrite determines if the state-changing operator functions are
|
||||
// allowed.
|
||||
func (p *PolicyACL) OperatorWrite() bool {
|
||||
if p.operatorRule == PolicyWrite {
|
||||
return true
|
||||
}
|
||||
return p.parent.OperatorWrite()
|
||||
}
|
||||
|
||||
// PreparedQueryRead checks if reading (listing) of a prepared query is
|
||||
// allowed - this isn't execution, just listing its contents.
|
||||
func (p *PolicyACL) PreparedQueryRead(prefix string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.preparedQueryRules.LongestPrefix(prefix)
|
||||
|
||||
if ok {
|
||||
switch rule {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix); ok {
|
||||
if allow, recurse := enforce(rule.(string), PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -736,14 +719,9 @@ func (p *PolicyACL) PreparedQueryRead(prefix string) bool {
|
|||
// prepared query is allowed.
|
||||
func (p *PolicyACL) PreparedQueryWrite(prefix string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.preparedQueryRules.LongestPrefix(prefix)
|
||||
|
||||
if ok {
|
||||
switch rule {
|
||||
case PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix); ok {
|
||||
if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -754,14 +732,10 @@ func (p *PolicyACL) PreparedQueryWrite(prefix string) bool {
|
|||
// ServiceRead checks if reading (discovery) of a service is allowed
|
||||
func (p *PolicyACL) ServiceRead(name string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.serviceRules.LongestPrefix(name)
|
||||
if ok {
|
||||
if _, rule, ok := p.serviceRules.LongestPrefix(name); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,14 +746,10 @@ func (p *PolicyACL) ServiceRead(name string) bool {
|
|||
// ServiceWrite checks if writing (registering) a service is allowed
|
||||
func (p *PolicyACL) ServiceWrite(name string, scope sentinel.ScopeFn) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.serviceRules.LongestPrefix(name)
|
||||
if ok {
|
||||
if _, rule, ok := p.serviceRules.LongestPrefix(name); ok {
|
||||
pr := rule.(PolicyRule)
|
||||
switch pr.aclPolicy {
|
||||
case PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,14 +760,9 @@ func (p *PolicyACL) ServiceWrite(name string, scope sentinel.ScopeFn) bool {
|
|||
// SessionRead checks for permission to read sessions for a given node.
|
||||
func (p *PolicyACL) SessionRead(node string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.sessionRules.LongestPrefix(node)
|
||||
|
||||
if ok {
|
||||
switch rule {
|
||||
case PolicyRead, PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if _, rule, ok := p.sessionRules.LongestPrefix(node); ok {
|
||||
if allow, recurse := enforce(rule.(string), PolicyRead); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -808,14 +773,9 @@ func (p *PolicyACL) SessionRead(node string) bool {
|
|||
// SessionWrite checks for permission to create sessions for a given node.
|
||||
func (p *PolicyACL) SessionWrite(node string) bool {
|
||||
// Check for an exact rule or catch-all
|
||||
_, rule, ok := p.sessionRules.LongestPrefix(node)
|
||||
|
||||
if ok {
|
||||
switch rule {
|
||||
case PolicyWrite:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
if _, rule, ok := p.sessionRules.LongestPrefix(node); ok {
|
||||
if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse {
|
||||
return allow
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2426
acl/acl_test.go
2426
acl/acl_test.go
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue