acl: initial pass at keyring ACLs
This commit is contained in:
parent
503fa1eed1
commit
4ef6545583
54
acl/acl.go
54
acl/acl.go
|
@ -58,6 +58,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
|
||||||
|
|
||||||
|
// KeyringRead determines if the encryption keyring used in
|
||||||
|
// the gossip layer can be read.
|
||||||
|
KeyringRead() bool
|
||||||
|
|
||||||
|
// KeyringWrite determines if the keyring can be manipulated
|
||||||
|
KeyringWrite() bool
|
||||||
|
|
||||||
// ACLList checks for permission to list all the ACLs
|
// ACLList checks for permission to list all the ACLs
|
||||||
ACLList() bool
|
ACLList() bool
|
||||||
|
|
||||||
|
@ -101,6 +108,14 @@ func (s *StaticACL) EventWrite(string) bool {
|
||||||
return s.defaultAllow
|
return s.defaultAllow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StaticACL) KeyringRead() bool {
|
||||||
|
return s.defaultAllow
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StaticACL) KeyringWrite() bool {
|
||||||
|
return s.defaultAllow
|
||||||
|
}
|
||||||
|
|
||||||
func (s *StaticACL) ACLList() bool {
|
func (s *StaticACL) ACLList() bool {
|
||||||
return s.allowManage
|
return s.allowManage
|
||||||
}
|
}
|
||||||
|
@ -153,6 +168,11 @@ type PolicyACL struct {
|
||||||
|
|
||||||
// eventRules contains the user event policies
|
// eventRules contains the user event policies
|
||||||
eventRules *radix.Tree
|
eventRules *radix.Tree
|
||||||
|
|
||||||
|
// keyringRules contains the keyring policies. The keyring has
|
||||||
|
// a very simple yes/no without prefix mathing, so here we
|
||||||
|
// don't need to use a radix tree.
|
||||||
|
keyringRules map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New is used to construct a policy based ACL from a set of policies
|
// New is used to construct a policy based ACL from a set of policies
|
||||||
|
@ -163,6 +183,7 @@ func New(parent ACL, policy *Policy) (*PolicyACL, error) {
|
||||||
keyRules: radix.New(),
|
keyRules: radix.New(),
|
||||||
serviceRules: radix.New(),
|
serviceRules: radix.New(),
|
||||||
eventRules: radix.New(),
|
eventRules: radix.New(),
|
||||||
|
keyringRules: make(map[string]struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the key policy
|
// Load the key policy
|
||||||
|
@ -180,6 +201,11 @@ func New(parent ACL, policy *Policy) (*PolicyACL, error) {
|
||||||
p.eventRules.Insert(ep.Event, ep.Policy)
|
p.eventRules.Insert(ep.Event, ep.Policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load the keyring policy
|
||||||
|
for _, krp := range policy.Keyring {
|
||||||
|
p.keyringRules[krp.Policy] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +347,34 @@ func (p *PolicyACL) EventWrite(name string) bool {
|
||||||
return p.parent.EventWrite(name)
|
return p.parent.EventWrite(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyringRead is used to determine if the keyring can be
|
||||||
|
// read by the current ACL token.
|
||||||
|
func (p *PolicyACL) KeyringRead() bool {
|
||||||
|
// First check for an explicit deny
|
||||||
|
if _, ok := p.keyringRules[KeyringPolicyDeny]; ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check for read or write. Write implies read.
|
||||||
|
_, ok := p.keyringRules[KeyringPolicyRead]
|
||||||
|
if !ok {
|
||||||
|
_, ok = p.keyringRules[KeyringPolicyWrite]
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyringWrite determines if the keyring can be manipulated.
|
||||||
|
func (p *PolicyACL) KeyringWrite() bool {
|
||||||
|
// First check for an explicit deny
|
||||||
|
if _, ok := p.keyringRules[KeyringPolicyDeny]; ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for read permission
|
||||||
|
_, ok := p.keyringRules[KeyringPolicyWrite]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// ACLList checks if listing of ACLs is allowed
|
// ACLList checks if listing of ACLs is allowed
|
||||||
func (p *PolicyACL) ACLList() bool {
|
func (p *PolicyACL) ACLList() bool {
|
||||||
return p.parent.ACLList()
|
return p.parent.ACLList()
|
||||||
|
|
|
@ -16,6 +16,9 @@ const (
|
||||||
EventPolicyRead = "read"
|
EventPolicyRead = "read"
|
||||||
EventPolicyWrite = "write"
|
EventPolicyWrite = "write"
|
||||||
EventPolicyDeny = "deny"
|
EventPolicyDeny = "deny"
|
||||||
|
KeyringPolicyWrite = "write"
|
||||||
|
KeyringPolicyRead = "read"
|
||||||
|
KeyringPolicyDeny = "deny"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Policy is used to represent the policy specified by
|
// Policy is used to represent the policy specified by
|
||||||
|
@ -25,6 +28,7 @@ type Policy struct {
|
||||||
Keys []*KeyPolicy `hcl:"key,expand"`
|
Keys []*KeyPolicy `hcl:"key,expand"`
|
||||||
Services []*ServicePolicy `hcl:"service,expand"`
|
Services []*ServicePolicy `hcl:"service,expand"`
|
||||||
Events []*EventPolicy `hcl:"event,expand"`
|
Events []*EventPolicy `hcl:"event,expand"`
|
||||||
|
Keyring []*KeyringPolicy `hcl:"keyring"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyPolicy represents a policy for a key
|
// KeyPolicy represents a policy for a key
|
||||||
|
@ -57,6 +61,17 @@ func (e *EventPolicy) GoString() string {
|
||||||
return fmt.Sprintf("%#v", *e)
|
return fmt.Sprintf("%#v", *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyringPolicy represents a policy for the encryption keyring.
|
||||||
|
type KeyringPolicy struct {
|
||||||
|
// We only need a single field for the keyring, since access
|
||||||
|
// is binary (allowed or disallowed) and no prefix is respected.
|
||||||
|
Policy string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KeyringPolicy) GoString() string {
|
||||||
|
return fmt.Sprintf("%#v", *k)
|
||||||
|
}
|
||||||
|
|
||||||
// Parse is used to parse the specified ACL rules into an
|
// Parse is used to parse the specified ACL rules into an
|
||||||
// intermediary set of policies, before being compiled into
|
// intermediary set of policies, before being compiled into
|
||||||
// the ACL
|
// the ACL
|
||||||
|
@ -105,5 +120,16 @@ func Parse(rules string) (*Policy, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate the keyring policy
|
||||||
|
for _, krp := range p.Keyring {
|
||||||
|
switch krp.Policy {
|
||||||
|
case KeyringPolicyRead:
|
||||||
|
case KeyringPolicyWrite:
|
||||||
|
case KeyringPolicyDeny:
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Invalid keyring policy: %#v", krp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package consul
|
package consul
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/consul/structs"
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
"github.com/hashicorp/serf/serf"
|
"github.com/hashicorp/serf/serf"
|
||||||
)
|
)
|
||||||
|
@ -80,6 +82,30 @@ func (m *Internal) KeyringOperation(
|
||||||
args *structs.KeyringRequest,
|
args *structs.KeyringRequest,
|
||||||
reply *structs.KeyringResponses) error {
|
reply *structs.KeyringResponses) error {
|
||||||
|
|
||||||
|
// Check ACLs
|
||||||
|
acl, err := m.srv.resolveToken(args.Token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if acl != nil {
|
||||||
|
switch args.Operation {
|
||||||
|
case structs.KeyringList:
|
||||||
|
if !acl.KeyringRead() {
|
||||||
|
return fmt.Errorf("Reading keyring denied by ACLs")
|
||||||
|
}
|
||||||
|
case structs.KeyringInstall:
|
||||||
|
fallthrough
|
||||||
|
case structs.KeyringUse:
|
||||||
|
fallthrough
|
||||||
|
case structs.KeyringRemove:
|
||||||
|
if !acl.KeyringWrite() {
|
||||||
|
return fmt.Errorf("Modifying keyring denied due to ACLs")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("Invalid keyring operation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only perform WAN keyring querying and RPC forwarding once
|
// Only perform WAN keyring querying and RPC forwarding once
|
||||||
if !args.Forwarded {
|
if !args.Forwarded {
|
||||||
args.Forwarded = true
|
args.Forwarded = true
|
||||||
|
|
Loading…
Reference in New Issue