mirror of https://github.com/hashicorp/consul
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
8.5 KiB
277 lines
8.5 KiB
package acl |
|
|
|
import ( |
|
"fmt" |
|
"strings" |
|
) |
|
|
|
type EnforcementDecision int |
|
|
|
const ( |
|
// Deny returned from an Authorizer enforcement method indicates |
|
// that a corresponding rule was found and that access should be denied |
|
Deny EnforcementDecision = iota |
|
// Allow returned from an Authorizer enforcement method indicates |
|
// that a corresponding rule was found and that access should be allowed |
|
Allow |
|
// Default returned from an Authorizer enforcement method indicates |
|
// that a corresponding rule was not found and that whether access |
|
// should be granted or denied should be deferred to the default |
|
// access level |
|
Default |
|
) |
|
|
|
func (d EnforcementDecision) String() string { |
|
switch d { |
|
case Allow: |
|
return "Allow" |
|
case Deny: |
|
return "Deny" |
|
case Default: |
|
return "Default" |
|
default: |
|
return "Unknown" |
|
} |
|
} |
|
|
|
type Resource string |
|
|
|
const ( |
|
ResourceACL Resource = "acl" |
|
ResourceAgent Resource = "agent" |
|
ResourceEvent Resource = "event" |
|
ResourceIntention Resource = "intention" |
|
ResourceKey Resource = "key" |
|
ResourceKeyring Resource = "keyring" |
|
ResourceNode Resource = "node" |
|
ResourceOperator Resource = "operator" |
|
ResourceMesh Resource = "mesh" |
|
ResourceQuery Resource = "query" |
|
ResourceService Resource = "service" |
|
ResourceSession Resource = "session" |
|
) |
|
|
|
// Authorizer is the interface for policy enforcement. |
|
type Authorizer interface { |
|
// ACLRead checks for permission to list all the ACLs |
|
ACLRead(*AuthorizerContext) EnforcementDecision |
|
|
|
// ACLWrite checks for permission to manipulate ACLs |
|
ACLWrite(*AuthorizerContext) EnforcementDecision |
|
|
|
// AgentRead checks for permission to read from agent endpoints for a |
|
// given node. |
|
AgentRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// AgentWrite checks for permission to make changes via agent endpoints |
|
// for a given node. |
|
AgentWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// EventRead determines if a specific event can be queried. |
|
EventRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// EventWrite determines if a specific event may be fired. |
|
EventWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// IntentionDefaultAllow determines the default authorized behavior |
|
// when no intentions match a Connect request. |
|
IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision |
|
|
|
// IntentionRead determines if a specific intention can be read. |
|
IntentionRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// IntentionWrite determines if a specific intention can be |
|
// created, modified, or deleted. |
|
IntentionWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// KeyList checks for permission to list keys under a prefix |
|
KeyList(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// KeyRead checks for permission to read a given key |
|
KeyRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// KeyWrite checks for permission to write a given key |
|
KeyWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// KeyWritePrefix checks for permission to write to an |
|
// entire key prefix. This means there must be no sub-policies |
|
// that deny a write. |
|
KeyWritePrefix(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// KeyringRead determines if the encryption keyring used in |
|
// the gossip layer can be read. |
|
KeyringRead(*AuthorizerContext) EnforcementDecision |
|
|
|
// KeyringWrite determines if the keyring can be manipulated |
|
KeyringWrite(*AuthorizerContext) EnforcementDecision |
|
|
|
// MeshRead determines if the read-only Consul mesh functions |
|
// can be used. |
|
MeshRead(*AuthorizerContext) EnforcementDecision |
|
|
|
// MeshWrite determines if the state-changing Consul mesh |
|
// functions can be used. |
|
MeshWrite(*AuthorizerContext) EnforcementDecision |
|
|
|
// NodeRead checks for permission to read (discover) a given node. |
|
NodeRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// NodeReadAll checks for permission to read (discover) all nodes. |
|
NodeReadAll(*AuthorizerContext) EnforcementDecision |
|
|
|
// NodeWrite checks for permission to create or update (register) a |
|
// given node. |
|
NodeWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// OperatorRead determines if the read-only Consul operator functions |
|
// can be used. |
|
OperatorRead(*AuthorizerContext) EnforcementDecision |
|
|
|
// OperatorWrite determines if the state-changing Consul operator |
|
// functions can be used. |
|
OperatorWrite(*AuthorizerContext) EnforcementDecision |
|
|
|
// PreparedQueryRead determines if a specific prepared query can be read |
|
// to show its contents (this is not used for execution). |
|
PreparedQueryRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// PreparedQueryWrite determines if a specific prepared query can be |
|
// created, modified, or deleted. |
|
PreparedQueryWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// ServiceRead checks for permission to read a given service |
|
ServiceRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// ServiceReadAll checks for permission to read all services |
|
ServiceReadAll(*AuthorizerContext) EnforcementDecision |
|
|
|
// ServiceWrite checks for permission to create or update a given |
|
// service |
|
ServiceWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// SessionRead checks for permission to read sessions for a given node. |
|
SessionRead(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// SessionWrite checks for permission to create sessions for a given |
|
// node. |
|
SessionWrite(string, *AuthorizerContext) EnforcementDecision |
|
|
|
// Snapshot checks for permission to take and restore snapshots. |
|
Snapshot(*AuthorizerContext) EnforcementDecision |
|
|
|
// Embedded Interface for Consul Enterprise specific ACL enforcement |
|
enterpriseAuthorizer |
|
} |
|
|
|
func Enforce(authz Authorizer, rsc Resource, segment string, access string, ctx *AuthorizerContext) (EnforcementDecision, error) { |
|
lowerAccess := strings.ToLower(access) |
|
|
|
switch rsc { |
|
case ResourceACL: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.ACLRead(ctx), nil |
|
case "write": |
|
return authz.ACLWrite(ctx), nil |
|
} |
|
case ResourceAgent: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.AgentRead(segment, ctx), nil |
|
case "write": |
|
return authz.AgentWrite(segment, ctx), nil |
|
} |
|
case ResourceEvent: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.EventRead(segment, ctx), nil |
|
case "write": |
|
return authz.EventWrite(segment, ctx), nil |
|
} |
|
case ResourceIntention: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.IntentionRead(segment, ctx), nil |
|
case "write": |
|
return authz.IntentionWrite(segment, ctx), nil |
|
} |
|
case ResourceKey: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.KeyRead(segment, ctx), nil |
|
case "list": |
|
return authz.KeyList(segment, ctx), nil |
|
case "write": |
|
return authz.KeyWrite(segment, ctx), nil |
|
case "write-prefix": |
|
return authz.KeyWritePrefix(segment, ctx), nil |
|
} |
|
case ResourceKeyring: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.KeyringRead(ctx), nil |
|
case "write": |
|
return authz.KeyringWrite(ctx), nil |
|
} |
|
case ResourceMesh: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.MeshRead(ctx), nil |
|
case "write": |
|
return authz.MeshWrite(ctx), nil |
|
} |
|
case ResourceNode: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.NodeRead(segment, ctx), nil |
|
case "write": |
|
return authz.NodeWrite(segment, ctx), nil |
|
} |
|
case ResourceOperator: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.OperatorRead(ctx), nil |
|
case "write": |
|
return authz.OperatorWrite(ctx), nil |
|
} |
|
case ResourceQuery: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.PreparedQueryRead(segment, ctx), nil |
|
case "write": |
|
return authz.PreparedQueryWrite(segment, ctx), nil |
|
} |
|
case ResourceService: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.ServiceRead(segment, ctx), nil |
|
case "write": |
|
return authz.ServiceWrite(segment, ctx), nil |
|
} |
|
case ResourceSession: |
|
switch lowerAccess { |
|
case "read": |
|
return authz.SessionRead(segment, ctx), nil |
|
case "write": |
|
return authz.SessionWrite(segment, ctx), nil |
|
} |
|
default: |
|
if processed, decision, err := enforceEnterprise(authz, rsc, segment, lowerAccess, ctx); processed { |
|
return decision, err |
|
} |
|
return Deny, fmt.Errorf("Invalid ACL resource requested: %q", rsc) |
|
} |
|
|
|
return Deny, fmt.Errorf("Invalid access level for %s resource: %s", rsc, access) |
|
} |
|
|
|
// NewAuthorizerFromRules is a convenience function to invoke NewPolicyFromSource followed by NewPolicyAuthorizer with |
|
// the parse policy. |
|
func NewAuthorizerFromRules(rules string, syntax SyntaxVersion, conf *Config, meta *EnterprisePolicyMeta) (Authorizer, error) { |
|
policy, err := NewPolicyFromSource(rules, syntax, conf, meta) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return NewPolicyAuthorizer([]*Policy{policy}, conf) |
|
}
|
|
|