2023-03-28 20:12:41 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-28 20:12:41 +00:00
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
package acl
|
|
|
|
|
2019-12-06 14:25:26 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
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"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-06 14:25:26 +00:00
|
|
|
type Resource string
|
|
|
|
|
|
|
|
const (
|
|
|
|
ResourceACL Resource = "acl"
|
|
|
|
ResourceAgent Resource = "agent"
|
|
|
|
ResourceEvent Resource = "event"
|
2023-09-12 21:22:51 +00:00
|
|
|
ResourceIdentity Resource = "identity"
|
2019-12-06 14:25:26 +00:00
|
|
|
ResourceIntention Resource = "intention"
|
|
|
|
ResourceKey Resource = "key"
|
|
|
|
ResourceKeyring Resource = "keyring"
|
|
|
|
ResourceNode Resource = "node"
|
|
|
|
ResourceOperator Resource = "operator"
|
2021-08-20 22:11:01 +00:00
|
|
|
ResourceMesh Resource = "mesh"
|
2019-12-06 14:25:26 +00:00
|
|
|
ResourceQuery Resource = "query"
|
|
|
|
ResourceService Resource = "service"
|
|
|
|
ResourceSession Resource = "session"
|
2022-06-29 20:38:17 +00:00
|
|
|
ResourcePeering Resource = "peering"
|
2019-12-06 14:25:26 +00:00
|
|
|
)
|
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
// Authorizer is the interface for policy enforcement.
|
|
|
|
type Authorizer interface {
|
|
|
|
// ACLRead checks for permission to list all the ACLs
|
2019-12-18 18:43:24 +00:00
|
|
|
ACLRead(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// ACLWrite checks for permission to manipulate ACLs
|
2019-12-18 18:43:24 +00:00
|
|
|
ACLWrite(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// AgentRead checks for permission to read from agent endpoints for a
|
|
|
|
// given node.
|
2019-12-18 18:43:24 +00:00
|
|
|
AgentRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// AgentWrite checks for permission to make changes via agent endpoints
|
|
|
|
// for a given node.
|
2019-12-18 18:43:24 +00:00
|
|
|
AgentWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// EventRead determines if a specific event can be queried.
|
2019-12-18 18:43:24 +00:00
|
|
|
EventRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// EventWrite determines if a specific event may be fired.
|
2019-12-18 18:43:24 +00:00
|
|
|
EventWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
2023-09-12 21:22:51 +00:00
|
|
|
// IdentityRead checks for permission to read a given workload identity.
|
|
|
|
IdentityRead(string, *AuthorizerContext) EnforcementDecision
|
|
|
|
|
|
|
|
// IdentityReadAll checks for permission to read all workload identities.
|
|
|
|
IdentityReadAll(*AuthorizerContext) EnforcementDecision
|
|
|
|
|
|
|
|
// IdentityWrite checks for permission to create or update a given
|
|
|
|
// workload identity.
|
|
|
|
IdentityWrite(string, *AuthorizerContext) EnforcementDecision
|
|
|
|
|
|
|
|
// IdentityWriteAny checks for write permission on any workload identity.
|
|
|
|
IdentityWriteAny(*AuthorizerContext) EnforcementDecision
|
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
// IntentionDefaultAllow determines the default authorized behavior
|
|
|
|
// when no intentions match a Connect request.
|
2019-12-18 18:43:24 +00:00
|
|
|
IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// IntentionRead determines if a specific intention can be read.
|
2019-12-18 18:43:24 +00:00
|
|
|
IntentionRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// IntentionWrite determines if a specific intention can be
|
|
|
|
// created, modified, or deleted.
|
2019-12-18 18:43:24 +00:00
|
|
|
IntentionWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// KeyList checks for permission to list keys under a prefix
|
2019-12-18 18:43:24 +00:00
|
|
|
KeyList(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// KeyRead checks for permission to read a given key
|
2019-12-18 18:43:24 +00:00
|
|
|
KeyRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// KeyWrite checks for permission to write a given key
|
2019-12-18 18:43:24 +00:00
|
|
|
KeyWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// KeyWritePrefix checks for permission to write to an
|
|
|
|
// entire key prefix. This means there must be no sub-policies
|
|
|
|
// that deny a write.
|
2019-12-18 18:43:24 +00:00
|
|
|
KeyWritePrefix(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// KeyringRead determines if the encryption keyring used in
|
|
|
|
// the gossip layer can be read.
|
2019-12-18 18:43:24 +00:00
|
|
|
KeyringRead(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// KeyringWrite determines if the keyring can be manipulated
|
2019-12-18 18:43:24 +00:00
|
|
|
KeyringWrite(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
2021-08-20 22:11:01 +00:00
|
|
|
// 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
|
|
|
|
|
2022-07-22 20:42:23 +00:00
|
|
|
// PeeringRead determines if the read-only Consul peering functions
|
|
|
|
// can be used.
|
|
|
|
PeeringRead(*AuthorizerContext) EnforcementDecision
|
|
|
|
|
|
|
|
// PeeringWrite determines if the stage-changing Consul peering
|
|
|
|
// functions can be used.
|
|
|
|
PeeringWrite(*AuthorizerContext) EnforcementDecision
|
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
// NodeRead checks for permission to read (discover) a given node.
|
2019-12-18 18:43:24 +00:00
|
|
|
NodeRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
2020-11-04 18:50:03 +00:00
|
|
|
// NodeReadAll checks for permission to read (discover) all nodes.
|
|
|
|
NodeReadAll(*AuthorizerContext) EnforcementDecision
|
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
// NodeWrite checks for permission to create or update (register) a
|
|
|
|
// given node.
|
2019-12-18 18:43:24 +00:00
|
|
|
NodeWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// OperatorRead determines if the read-only Consul operator functions
|
|
|
|
// can be used.
|
2019-12-18 18:43:24 +00:00
|
|
|
OperatorRead(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// OperatorWrite determines if the state-changing Consul operator
|
|
|
|
// functions can be used.
|
2019-12-18 18:43:24 +00:00
|
|
|
OperatorWrite(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// PreparedQueryRead determines if a specific prepared query can be read
|
|
|
|
// to show its contents (this is not used for execution).
|
2019-12-18 18:43:24 +00:00
|
|
|
PreparedQueryRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// PreparedQueryWrite determines if a specific prepared query can be
|
|
|
|
// created, modified, or deleted.
|
2019-12-18 18:43:24 +00:00
|
|
|
PreparedQueryWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// ServiceRead checks for permission to read a given service
|
2019-12-18 18:43:24 +00:00
|
|
|
ServiceRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
2020-11-04 18:50:03 +00:00
|
|
|
// ServiceReadAll checks for permission to read all services
|
|
|
|
ServiceReadAll(*AuthorizerContext) EnforcementDecision
|
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
// ServiceWrite checks for permission to create or update a given
|
|
|
|
// service
|
2019-12-18 18:43:24 +00:00
|
|
|
ServiceWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
2022-03-24 11:25:05 +00:00
|
|
|
// ServiceWriteAny checks for write permission on any service
|
|
|
|
ServiceWriteAny(*AuthorizerContext) EnforcementDecision
|
|
|
|
|
2019-10-15 20:58:50 +00:00
|
|
|
// SessionRead checks for permission to read sessions for a given node.
|
2019-12-18 18:43:24 +00:00
|
|
|
SessionRead(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// SessionWrite checks for permission to create sessions for a given
|
|
|
|
// node.
|
2019-12-18 18:43:24 +00:00
|
|
|
SessionWrite(string, *AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// Snapshot checks for permission to take and restore snapshots.
|
2019-12-18 18:43:24 +00:00
|
|
|
Snapshot(*AuthorizerContext) EnforcementDecision
|
2019-10-15 20:58:50 +00:00
|
|
|
|
|
|
|
// Embedded Interface for Consul Enterprise specific ACL enforcement
|
2019-12-18 18:44:32 +00:00
|
|
|
enterpriseAuthorizer
|
2022-03-11 02:48:27 +00:00
|
|
|
|
|
|
|
// ToAllowAuthorizer is needed until we can use ResolveResult in all the places this interface is used.
|
|
|
|
ToAllowAuthorizer() AllowAuthorizer
|
|
|
|
}
|
|
|
|
|
|
|
|
// AllowAuthorizer is a wrapper to expose the *Allowed methods.
|
|
|
|
// This and the ToAllowAuthorizer function exist to tide us over until the ResolveResult struct
|
|
|
|
// is moved into acl.
|
|
|
|
type AllowAuthorizer struct {
|
|
|
|
Authorizer
|
2022-03-18 17:32:25 +00:00
|
|
|
AccessorID string
|
2022-03-11 02:48:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ACLReadAllowed checks for permission to list all the ACLs
|
|
|
|
func (a AllowAuthorizer) ACLReadAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.ACLRead(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceACL, AccessRead)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ACLWriteAllowed checks for permission to manipulate ACLs
|
|
|
|
func (a AllowAuthorizer) ACLWriteAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.ACLWrite(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceACL, AccessWrite)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AgentReadAllowed checks for permission to read from agent endpoints for a
|
|
|
|
// given node.
|
|
|
|
func (a AllowAuthorizer) AgentReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.AgentRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceAgent, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AgentWriteAllowed checks for permission to make changes via agent endpoints
|
|
|
|
// for a given node.
|
|
|
|
func (a AllowAuthorizer) AgentWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.AgentWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceAgent, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// EventReadAllowed determines if a specific event can be queried.
|
|
|
|
func (a AllowAuthorizer) EventReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.EventRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceEvent, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// EventWriteAllowed determines if a specific event may be fired.
|
|
|
|
func (a AllowAuthorizer) EventWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.EventWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceEvent, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-12 21:22:51 +00:00
|
|
|
// IdentityReadAllowed checks for permission to read a given workload identity,
|
|
|
|
func (a AllowAuthorizer) IdentityReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.IdentityRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IdentityReadAllAllowed checks for permission to read all workload identities.
|
|
|
|
func (a AllowAuthorizer) IdentityReadAllAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.IdentityReadAll(ctx) != Allow {
|
|
|
|
// This is only used to gate certain UI functions right now (e.g metrics)
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessRead, "all identities") // read
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IdentityWriteAllowed checks for permission to create or update a given
|
|
|
|
// workload identity.
|
|
|
|
func (a AllowAuthorizer) IdentityWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.IdentityWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IdentityWriteAnyAllowed checks for write permission on any workload identity
|
|
|
|
func (a AllowAuthorizer) IdentityWriteAnyAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.IdentityWriteAny(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceIdentity, AccessWrite, "any identity")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-11 02:48:27 +00:00
|
|
|
// IntentionDefaultAllowAllowed determines the default authorized behavior
|
|
|
|
// when no intentions match a Connect request.
|
|
|
|
func (a AllowAuthorizer) IntentionDefaultAllowAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.IntentionDefaultAllow(ctx) != Allow {
|
|
|
|
// This is a bit nuanced, in that this isn't set by a rule, but inherited globally
|
|
|
|
// TODO(acl-error-enhancements) revisit when we have full accessor info
|
|
|
|
return PermissionDeniedError{Cause: "Denied by intention default"}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntentionReadAllowed determines if a specific intention can be read.
|
|
|
|
func (a AllowAuthorizer) IntentionReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.IntentionRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceIntention, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntentionWriteAllowed determines if a specific intention can be
|
|
|
|
// created, modified, or deleted.
|
|
|
|
func (a AllowAuthorizer) IntentionWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.IntentionWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceIntention, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeyListAllowed checks for permission to list keys under a prefix
|
|
|
|
func (a AllowAuthorizer) KeyListAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.KeyList(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceKey, AccessList, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeyReadAllowed checks for permission to read a given key
|
|
|
|
func (a AllowAuthorizer) KeyReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.KeyRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceKey, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeyWriteAllowed checks for permission to write a given key
|
|
|
|
func (a AllowAuthorizer) KeyWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.KeyWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceKey, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeyWritePrefixAllowed checks for permission to write to an
|
|
|
|
// entire key prefix. This means there must be no sub-policies
|
|
|
|
// that deny a write.
|
|
|
|
func (a AllowAuthorizer) KeyWritePrefixAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.KeyWritePrefix(name, ctx) != Allow {
|
|
|
|
// TODO(acl-error-enhancements) revisit this message; we may need to do some extra plumbing inside of KeyWritePrefix to
|
|
|
|
// return properly detailed information.
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceKey, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeyringReadAllowed determines if the encryption keyring used in
|
|
|
|
// the gossip layer can be read.
|
|
|
|
func (a AllowAuthorizer) KeyringReadAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.KeyringRead(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceKeyring, AccessRead)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeyringWriteAllowed determines if the keyring can be manipulated
|
|
|
|
func (a AllowAuthorizer) KeyringWriteAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.KeyringWrite(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceKeyring, AccessWrite)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MeshReadAllowed determines if the read-only Consul mesh functions
|
|
|
|
// can be used.
|
|
|
|
func (a AllowAuthorizer) MeshReadAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.MeshRead(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceMesh, AccessRead)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MeshWriteAllowed determines if the state-changing Consul mesh
|
|
|
|
// functions can be used.
|
|
|
|
func (a AllowAuthorizer) MeshWriteAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.MeshWrite(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceMesh, AccessWrite)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-07-12 23:18:05 +00:00
|
|
|
// PeeringReadAllowed determines if the read-only Consul peering functions
|
|
|
|
// can be used.
|
|
|
|
func (a AllowAuthorizer) PeeringReadAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.PeeringRead(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourcePeering, AccessRead)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PeeringWriteAllowed determines if the state-changing Consul peering
|
|
|
|
// functions can be used.
|
|
|
|
func (a AllowAuthorizer) PeeringWriteAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.PeeringWrite(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourcePeering, AccessWrite)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-11 02:48:27 +00:00
|
|
|
// NodeReadAllowed checks for permission to read (discover) a given node.
|
|
|
|
func (a AllowAuthorizer) NodeReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.NodeRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceNode, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodeReadAllAllowed checks for permission to read (discover) all nodes.
|
|
|
|
func (a AllowAuthorizer) NodeReadAllAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.NodeReadAll(ctx) != Allow {
|
|
|
|
// This is only used to gate certain UI functions right now (e.g metrics)
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceNode, AccessRead, "all nodes")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodeWriteAllowed checks for permission to create or update (register) a
|
|
|
|
// given node.
|
|
|
|
func (a AllowAuthorizer) NodeWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.NodeWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceNode, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OperatorReadAllowed determines if the read-only Consul operator functions
|
|
|
|
// can be used.
|
|
|
|
func (a AllowAuthorizer) OperatorReadAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.OperatorRead(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceOperator, AccessRead)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OperatorWriteAllowed determines if the state-changing Consul operator
|
|
|
|
// functions can be used.
|
|
|
|
func (a AllowAuthorizer) OperatorWriteAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.OperatorWrite(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceOperator, AccessWrite)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PreparedQueryReadAllowed determines if a specific prepared query can be read
|
|
|
|
// to show its contents (this is not used for execution).
|
|
|
|
func (a AllowAuthorizer) PreparedQueryReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.PreparedQueryRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceQuery, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PreparedQueryWriteAllowed determines if a specific prepared query can be
|
|
|
|
// created, modified, or deleted.
|
|
|
|
func (a AllowAuthorizer) PreparedQueryWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.PreparedQueryWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceQuery, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceReadAllowed checks for permission to read a given service
|
|
|
|
func (a AllowAuthorizer) ServiceReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.ServiceRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceService, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceReadAllAllowed checks for permission to read all services
|
|
|
|
func (a AllowAuthorizer) ServiceReadAllAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.ServiceReadAll(ctx) != Allow {
|
|
|
|
// This is only used to gate certain UI functions right now (e.g metrics)
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceService, AccessRead, "all services") // read
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceWriteAllowed checks for permission to create or update a given
|
|
|
|
// service
|
|
|
|
func (a AllowAuthorizer) ServiceWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.ServiceWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceService, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-24 11:25:05 +00:00
|
|
|
// ServiceWriteAnyAllowed checks for write permission on any service
|
|
|
|
func (a AllowAuthorizer) ServiceWriteAnyAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.ServiceWriteAny(ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceService, AccessWrite, "any service")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-11 02:48:27 +00:00
|
|
|
// SessionReadAllowed checks for permission to read sessions for a given node.
|
|
|
|
func (a AllowAuthorizer) SessionReadAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.SessionRead(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceSession, AccessRead, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SessionWriteAllowed checks for permission to create sessions for a given
|
|
|
|
// node.
|
|
|
|
func (a AllowAuthorizer) SessionWriteAllowed(name string, ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.SessionWrite(name, ctx) != Allow {
|
|
|
|
return PermissionDeniedByACL(a, ctx, ResourceSession, AccessWrite, name)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SnapshotAllowed checks for permission to take and restore snapshots.
|
|
|
|
func (a AllowAuthorizer) SnapshotAllowed(ctx *AuthorizerContext) error {
|
|
|
|
if a.Authorizer.Snapshot(ctx) != Allow {
|
|
|
|
// Implementation of this currently just checks acl write
|
|
|
|
return PermissionDeniedByACLUnnamed(a, ctx, ResourceACL, AccessWrite)
|
|
|
|
}
|
|
|
|
return nil
|
2019-10-15 20:58:50 +00:00
|
|
|
}
|
2019-12-06 14:25:26 +00:00
|
|
|
|
2019-12-18 18:43:24 +00:00
|
|
|
func Enforce(authz Authorizer, rsc Resource, segment string, access string, ctx *AuthorizerContext) (EnforcementDecision, error) {
|
2019-12-06 14:25:26 +00:00
|
|
|
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
|
|
|
|
}
|
2023-09-12 21:22:51 +00:00
|
|
|
case ResourceIdentity:
|
|
|
|
switch lowerAccess {
|
|
|
|
case "read":
|
|
|
|
return authz.IdentityRead(segment, ctx), nil
|
|
|
|
case "write":
|
|
|
|
return authz.IdentityWrite(segment, ctx), nil
|
|
|
|
}
|
2019-12-06 14:25:26 +00:00
|
|
|
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
|
|
|
|
}
|
2021-08-20 22:11:01 +00:00
|
|
|
case ResourceMesh:
|
|
|
|
switch lowerAccess {
|
|
|
|
case "read":
|
|
|
|
return authz.MeshRead(ctx), nil
|
|
|
|
case "write":
|
|
|
|
return authz.MeshWrite(ctx), nil
|
|
|
|
}
|
2019-12-06 14:25:26 +00:00
|
|
|
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
|
|
|
|
}
|
2022-06-29 20:38:17 +00:00
|
|
|
case ResourcePeering:
|
|
|
|
switch lowerAccess {
|
|
|
|
case "read":
|
2022-07-22 20:42:23 +00:00
|
|
|
return authz.PeeringRead(ctx), nil
|
2022-06-29 20:38:17 +00:00
|
|
|
case "write":
|
2022-07-22 20:42:23 +00:00
|
|
|
return authz.PeeringWrite(ctx), nil
|
2022-06-29 20:38:17 +00:00
|
|
|
}
|
2019-12-06 14:25:26 +00:00
|
|
|
default:
|
2019-12-18 18:44:32 +00:00
|
|
|
if processed, decision, err := enforceEnterprise(authz, rsc, segment, lowerAccess, ctx); processed {
|
2019-12-06 14:25:26 +00:00
|
|
|
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)
|
|
|
|
}
|
2020-01-13 20:51:40 +00:00
|
|
|
|
|
|
|
// NewAuthorizerFromRules is a convenience function to invoke NewPolicyFromSource followed by NewPolicyAuthorizer with
|
|
|
|
// the parse policy.
|
2023-02-06 15:35:52 +00:00
|
|
|
func NewAuthorizerFromRules(rules string, conf *Config, meta *EnterprisePolicyMeta) (Authorizer, error) {
|
|
|
|
policy, err := NewPolicyFromSource(rules, conf, meta)
|
2020-01-13 20:51:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewPolicyAuthorizer([]*Policy{policy}, conf)
|
|
|
|
}
|