open-vault/vault/acl.go

132 lines
3.4 KiB
Go
Raw Normal View History

2015-03-18 01:31:20 +00:00
package vault
import (
"github.com/armon/go-radix"
"github.com/hashicorp/vault/logical"
)
// ACL is used to wrap a set of policies to provide
// an efficient interface for access control.
type ACL struct {
// exactRules contains the path policies that are exact
exactRules *radix.Tree
// globRules contains the path policies that glob
globRules *radix.Tree
2015-03-18 01:31:20 +00:00
// root is enabled if the "root" named policy is present.
root bool
}
// New is used to construct a policy based ACL from a set of policies.
func NewACL(policies []*Policy) (*ACL, error) {
// Initialize
a := &ACL{
exactRules: radix.New(),
globRules: radix.New(),
root: false,
2015-03-18 01:31:20 +00:00
}
// Inject each policy
for _, policy := range policies {
// Ignore a nil policy object
if policy == nil {
continue
}
2015-03-18 01:31:20 +00:00
// Check if this is root
if policy.Name == "root" {
a.root = true
}
for _, pc := range policy.Paths {
// Check which tree to use
tree := a.exactRules
if pc.Glob {
tree = a.globRules
}
2015-03-18 01:31:20 +00:00
// Check for an existing policy
raw, ok := tree.Get(pc.Prefix)
2015-03-18 01:31:20 +00:00
if !ok {
tree.Insert(pc.Prefix, pc)
2015-03-18 01:31:20 +00:00
continue
}
existing := raw.(*PathCapabilities)
switch {
2016-01-12 22:08:10 +00:00
case existing.CapabilitiesBitmap&DenyCapabilityInt > 0:
// If we are explicitly denied in the existing capability set,
// don't save anything else
2016-01-12 22:08:10 +00:00
case pc.CapabilitiesBitmap&DenyCapabilityInt > 0:
// If this new policy explicitly denies, only save the deny value
tree.Insert(pc.Prefix, pc)
2015-03-18 01:31:20 +00:00
default:
// Insert the capabilities in this new policy into the existing
// value; since it's a pointer we can just modify the
// underlying data
2016-01-12 22:08:10 +00:00
existing.CapabilitiesBitmap |= pc.CapabilitiesBitmap
2015-03-18 01:31:20 +00:00
}
}
}
return a, nil
}
2016-01-12 22:08:10 +00:00
// AllowOperation is used to check if the given operation is permitted. The
// first bool indicates if an op is allowed, the second whether sudo priviliges
// exist for that op and path.
func (a *ACL) AllowOperation(op logical.Operation, path string) (allowed bool, sudo bool) {
2015-03-18 01:31:20 +00:00
// Fast-path root
if a.root {
return true, true
2015-03-18 01:31:20 +00:00
}
// Help is always allowed
if op == logical.HelpOperation {
return true, false
}
// Find an exact matching rule, look for glob if no match
var policy *PathCapabilities
raw, ok := a.exactRules.Get(path)
2015-03-18 01:31:20 +00:00
if ok {
policy = raw.(*PathCapabilities)
goto CHECK
2015-03-18 01:31:20 +00:00
}
// Find a glob rule, default deny if no match
_, raw, ok = a.globRules.LongestPrefix(path)
if !ok {
return false, false
} else {
policy = raw.(*PathCapabilities)
}
2015-03-18 01:31:20 +00:00
CHECK:
2015-03-18 01:31:20 +00:00
// Check if the minimum permissions are met
// If "deny" has been explicitly set, only deny will be in the map, so we
// only need to check for the existence of other values
2016-01-12 22:08:10 +00:00
sudo = policy.CapabilitiesBitmap&SudoCapabilityInt > 0
switch op.String() {
case "read":
allowed = policy.CapabilitiesBitmap&ReadCapabilityInt > 0
case "list":
allowed = policy.CapabilitiesBitmap&ListCapabilityInt > 0
case "update":
allowed = policy.CapabilitiesBitmap&UpdateCapabilityInt > 0
case "delete":
allowed = policy.CapabilitiesBitmap&DeleteCapabilityInt > 0
case "create":
allowed = policy.CapabilitiesBitmap&CreateCapabilityInt > 0
case "revoke":
allowed = policy.CapabilitiesBitmap&UpdateCapabilityInt > 0
case "renew":
allowed = policy.CapabilitiesBitmap&UpdateCapabilityInt > 0
case "rollback":
allowed = policy.CapabilitiesBitmap&UpdateCapabilityInt > 0
default:
return false, false
}
return
2015-03-18 01:31:20 +00:00
}