OSS changes for implementing token based namespace inferencing

remove debug log
This commit is contained in:
Matt Keeler 2019-12-18 13:46:53 -05:00
parent be9ba707ba
commit a78f7d7a34
No known key found for this signature in database
GPG Key ID: 04DBAE1857E0081B
14 changed files with 644 additions and 423 deletions

View File

@ -13,6 +13,13 @@ import (
// clients. Some of the enforcement is normative (e.g. self and monitor) // clients. Some of the enforcement is normative (e.g. self and monitor)
// and some is informative (e.g. catalog and health). // and some is informative (e.g. catalog and health).
func (a *Agent) resolveToken(id string) (acl.Authorizer, error) { func (a *Agent) resolveToken(id string) (acl.Authorizer, error) {
return a.resolveTokenAndDefaultMeta(id, nil, nil)
}
// resolveTokenAndDefaultMeta is used to resolve an ACL token secret to an
// acl.Authorizer and to default any enterprise specific metadata for the request.
// The defaulted metadata is then used to fill in an acl.AuthorizationContext.
func (a *Agent) resolveTokenAndDefaultMeta(id string, entMeta *structs.EnterpriseMeta, authzContext *acl.AuthorizerContext) (acl.Authorizer, error) {
// ACLs are disabled // ACLs are disabled
if !a.delegate.ACLsEnabled() { if !a.delegate.ACLsEnabled() {
return nil, nil return nil, nil
@ -30,7 +37,8 @@ func (a *Agent) resolveToken(id string) (acl.Authorizer, error) {
if a.tokens.IsAgentMasterToken(id) { if a.tokens.IsAgentMasterToken(id) {
return a.aclMasterAuthorizer, nil return a.aclMasterAuthorizer, nil
} }
return a.delegate.ResolveToken(id)
return a.delegate.ResolveTokenAndDefaultMeta(id, entMeta, authzContext)
} }
func (a *Agent) initializeACLs() error { func (a *Agent) initializeACLs() error {
@ -67,25 +75,30 @@ func (a *Agent) initializeACLs() error {
// the given token. // the given token.
func (a *Agent) vetServiceRegister(token string, service *structs.NodeService) error { func (a *Agent) vetServiceRegister(token string, service *structs.NodeService) error {
// Resolve the token and bail if ACLs aren't enabled. // Resolve the token and bail if ACLs aren't enabled.
rule, err := a.resolveToken(token) authz, err := a.resolveToken(token)
if err != nil { if err != nil {
return err return err
} }
if rule == nil {
return a.vetServiceRegisterWithAuthorizer(authz, service)
}
func (a *Agent) vetServiceRegisterWithAuthorizer(authz acl.Authorizer, service *structs.NodeService) error {
if authz == nil {
return nil return nil
} }
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
service.FillAuthzContext(&authzContext) service.FillAuthzContext(&authzContext)
// Vet the service itself. // Vet the service itself.
if rule.ServiceWrite(service.Service, &authzContext) != acl.Allow { if authz.ServiceWrite(service.Service, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
// Vet any service that might be getting overwritten. // Vet any service that might be getting overwritten.
if existing := a.State.Service(service.CompoundServiceID()); existing != nil { if existing := a.State.Service(service.CompoundServiceID()); existing != nil {
existing.FillAuthzContext(&authzContext) existing.FillAuthzContext(&authzContext)
if rule.ServiceWrite(existing.Service, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.Service, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
@ -94,7 +107,7 @@ func (a *Agent) vetServiceRegister(token string, service *structs.NodeService) e
// since it can be discovered as an instance of that service. // since it can be discovered as an instance of that service.
if service.Kind == structs.ServiceKindConnectProxy { if service.Kind == structs.ServiceKindConnectProxy {
service.FillAuthzContext(&authzContext) service.FillAuthzContext(&authzContext)
if rule.ServiceWrite(service.Proxy.DestinationServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(service.Proxy.DestinationServiceName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
@ -106,11 +119,16 @@ func (a *Agent) vetServiceRegister(token string, service *structs.NodeService) e
// token. // token.
func (a *Agent) vetServiceUpdate(token string, serviceID structs.ServiceID) error { func (a *Agent) vetServiceUpdate(token string, serviceID structs.ServiceID) error {
// Resolve the token and bail if ACLs aren't enabled. // Resolve the token and bail if ACLs aren't enabled.
rule, err := a.resolveToken(token) authz, err := a.resolveToken(token)
if err != nil { if err != nil {
return err return err
} }
if rule == nil {
return a.vetServiceUpdateWithAuthorizer(authz, serviceID)
}
func (a *Agent) vetServiceUpdateWithAuthorizer(authz acl.Authorizer, serviceID structs.ServiceID) error {
if authz == nil {
return nil return nil
} }
@ -119,7 +137,7 @@ func (a *Agent) vetServiceUpdate(token string, serviceID structs.ServiceID) erro
// Vet any changes based on the existing services's info. // Vet any changes based on the existing services's info.
if existing := a.State.Service(serviceID); existing != nil { if existing := a.State.Service(serviceID); existing != nil {
existing.FillAuthzContext(&authzContext) existing.FillAuthzContext(&authzContext)
if rule.ServiceWrite(existing.Service, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.Service, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} else { } else {
@ -133,11 +151,16 @@ func (a *Agent) vetServiceUpdate(token string, serviceID structs.ServiceID) erro
// given token. // given token.
func (a *Agent) vetCheckRegister(token string, check *structs.HealthCheck) error { func (a *Agent) vetCheckRegister(token string, check *structs.HealthCheck) error {
// Resolve the token and bail if ACLs aren't enabled. // Resolve the token and bail if ACLs aren't enabled.
rule, err := a.resolveToken(token) authz, err := a.resolveToken(token)
if err != nil { if err != nil {
return err return err
} }
if rule == nil {
return a.vetCheckRegisterWithAuthorizer(authz, check)
}
func (a *Agent) vetCheckRegisterWithAuthorizer(authz acl.Authorizer, check *structs.HealthCheck) error {
if authz == nil {
return nil return nil
} }
@ -145,11 +168,11 @@ func (a *Agent) vetCheckRegister(token string, check *structs.HealthCheck) error
check.FillAuthzContext(&authzContext) check.FillAuthzContext(&authzContext)
// Vet the check itself. // Vet the check itself.
if len(check.ServiceName) > 0 { if len(check.ServiceName) > 0 {
if rule.ServiceWrite(check.ServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(check.ServiceName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} else { } else {
if rule.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow { if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
@ -157,11 +180,11 @@ func (a *Agent) vetCheckRegister(token string, check *structs.HealthCheck) error
// Vet any check that might be getting overwritten. // Vet any check that might be getting overwritten.
if existing := a.State.Check(check.CompoundCheckID()); existing != nil { if existing := a.State.Check(check.CompoundCheckID()); existing != nil {
if len(existing.ServiceName) > 0 { if len(existing.ServiceName) > 0 {
if rule.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} else { } else {
if rule.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow { if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
@ -173,11 +196,16 @@ func (a *Agent) vetCheckRegister(token string, check *structs.HealthCheck) error
// vetCheckUpdate makes sure that a check update is allowed by the given token. // vetCheckUpdate makes sure that a check update is allowed by the given token.
func (a *Agent) vetCheckUpdate(token string, checkID structs.CheckID) error { func (a *Agent) vetCheckUpdate(token string, checkID structs.CheckID) error {
// Resolve the token and bail if ACLs aren't enabled. // Resolve the token and bail if ACLs aren't enabled.
rule, err := a.resolveToken(token) authz, err := a.resolveToken(token)
if err != nil { if err != nil {
return err return err
} }
if rule == nil {
return a.vetCheckUpdateWithAuthorizer(authz, checkID)
}
func (a *Agent) vetCheckUpdateWithAuthorizer(authz acl.Authorizer, checkID structs.CheckID) error {
if authz == nil {
return nil return nil
} }
@ -187,11 +215,11 @@ func (a *Agent) vetCheckUpdate(token string, checkID structs.CheckID) error {
// Vet any changes based on the existing check's info. // Vet any changes based on the existing check's info.
if existing := a.State.Check(checkID); existing != nil { if existing := a.State.Check(checkID); existing != nil {
if len(existing.ServiceName) > 0 { if len(existing.ServiceName) > 0 {
if rule.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} else { } else {
if rule.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow { if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
@ -233,19 +261,23 @@ func (a *Agent) filterMembers(token string, members *[]serf.Member) error {
// filterServices redacts services that the token doesn't have access to. // filterServices redacts services that the token doesn't have access to.
func (a *Agent) filterServices(token string, services *map[structs.ServiceID]*structs.NodeService) error { func (a *Agent) filterServices(token string, services *map[structs.ServiceID]*structs.NodeService) error {
// Resolve the token and bail if ACLs aren't enabled. // Resolve the token and bail if ACLs aren't enabled.
rule, err := a.resolveToken(token) authz, err := a.resolveToken(token)
if err != nil { if err != nil {
return err return err
} }
if rule == nil {
return a.filterServicesWithAuthorizer(authz, services)
}
func (a *Agent) filterServicesWithAuthorizer(authz acl.Authorizer, services *map[structs.ServiceID]*structs.NodeService) error {
if authz == nil {
return nil return nil
} }
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
// Filter out services based on the service policy. // Filter out services based on the service policy.
for id, service := range *services { for id, service := range *services {
service.FillAuthzContext(&authzContext) service.FillAuthzContext(&authzContext)
if rule.ServiceRead(service.Service, &authzContext) == acl.Allow { if authz.ServiceRead(service.Service, &authzContext) == acl.Allow {
continue continue
} }
a.logger.Printf("[DEBUG] agent: dropping service %q from result due to ACLs", id.String()) a.logger.Printf("[DEBUG] agent: dropping service %q from result due to ACLs", id.String())
@ -257,11 +289,16 @@ func (a *Agent) filterServices(token string, services *map[structs.ServiceID]*st
// filterChecks redacts checks that the token doesn't have access to. // filterChecks redacts checks that the token doesn't have access to.
func (a *Agent) filterChecks(token string, checks *map[structs.CheckID]*structs.HealthCheck) error { func (a *Agent) filterChecks(token string, checks *map[structs.CheckID]*structs.HealthCheck) error {
// Resolve the token and bail if ACLs aren't enabled. // Resolve the token and bail if ACLs aren't enabled.
rule, err := a.resolveToken(token) authz, err := a.resolveToken(token)
if err != nil { if err != nil {
return err return err
} }
if rule == nil {
return a.filterChecksWithAuthorizer(authz, checks)
}
func (a *Agent) filterChecksWithAuthorizer(authz acl.Authorizer, checks *map[structs.CheckID]*structs.HealthCheck) error {
if authz == nil {
return nil return nil
} }
@ -270,12 +307,12 @@ func (a *Agent) filterChecks(token string, checks *map[structs.CheckID]*structs.
for id, check := range *checks { for id, check := range *checks {
if len(check.ServiceName) > 0 { if len(check.ServiceName) > 0 {
check.FillAuthzContext(&authzContext) check.FillAuthzContext(&authzContext)
if rule.ServiceRead(check.ServiceName, &authzContext) == acl.Allow { if authz.ServiceRead(check.ServiceName, &authzContext) == acl.Allow {
continue continue
} }
} else { } else {
structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext) structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext)
if rule.NodeRead(a.config.NodeName, &authzContext) == acl.Allow { if authz.NodeRead(a.config.NodeName, &authzContext) == acl.Allow {
continue continue
} }
} }

View File

@ -47,7 +47,7 @@ type TestACLAgent struct {
// Shutdown() is called. // Shutdown() is called.
DataDir string DataDir string
resolveTokenFn func(string) (acl.Authorizer, error) resolveTokenFn func(string) (structs.ACLIdentity, acl.Authorizer, error)
*Agent *Agent
} }
@ -55,7 +55,7 @@ type TestACLAgent struct {
// NewTestACLAGent does just enough so that all the code within agent/acl.go can work // NewTestACLAGent does just enough so that all the code within agent/acl.go can work
// Basically it needs a local state for some of the vet* functions, a logger and a delegate. // Basically it needs a local state for some of the vet* functions, a logger and a delegate.
// The key is that we are the delegate so we can control the ResolveToken responses // The key is that we are the delegate so we can control the ResolveToken responses
func NewTestACLAgent(t *testing.T, name string, hcl string, resolveFn func(string) (acl.Authorizer, error)) *TestACLAgent { func NewTestACLAgent(t *testing.T, name string, hcl string, resolveFn func(string) (structs.ACLIdentity, acl.Authorizer, error)) *TestACLAgent {
a := &TestACLAgent{Name: name, HCL: hcl, resolveTokenFn: resolveFn} a := &TestACLAgent{Name: name, HCL: hcl, resolveTokenFn: resolveFn}
hclDataDir := `data_dir = "acl-agent"` hclDataDir := `data_dir = "acl-agent"`
@ -98,9 +98,38 @@ func (a *TestACLAgent) ResolveToken(secretID string) (acl.Authorizer, error) {
panic("This agent is useless without providing a token resolution function") panic("This agent is useless without providing a token resolution function")
} }
_, authz, err := a.resolveTokenFn(secretID)
return authz, err
}
func (a *TestACLAgent) ResolveTokenToIdentityAndAuthorizer(secretID string) (structs.ACLIdentity, acl.Authorizer, error) {
if a.resolveTokenFn == nil {
panic("This agent is useless without providing a token resolution function")
}
return a.resolveTokenFn(secretID) return a.resolveTokenFn(secretID)
} }
func (a *TestACLAgent) ResolveTokenAndDefaultMeta(secretID string, entMeta *structs.EnterpriseMeta, authzContext *acl.AuthorizerContext) (acl.Authorizer, error) {
identity, authz, err := a.ResolveTokenToIdentityAndAuthorizer(secretID)
if err != nil {
return nil, err
}
// Default the EnterpriseMeta based on the Tokens meta or actual defaults
// in the case of unknown identity
if identity != nil {
entMeta.Merge(identity.EnterpriseMetadata())
} else {
entMeta.Merge(structs.DefaultEnterpriseMeta())
}
// Use the meta to fill in the ACL authorization context
entMeta.FillAuthzContext(authzContext)
return authz, err
}
// All of these are stubs to satisfy the interface // All of these are stubs to satisfy the interface
func (a *TestACLAgent) Encrypted() bool { func (a *TestACLAgent) Encrypted() bool {
return false return false
@ -150,9 +179,9 @@ func TestACL_Version8(t *testing.T) {
t.Parallel() t.Parallel()
t.Run("version 8 disabled", func(t *testing.T) { t.Run("version 8 disabled", func(t *testing.T) {
resolveFn := func(string) (acl.Authorizer, error) { resolveFn := func(string) (structs.ACLIdentity, acl.Authorizer, error) {
require.Fail(t, "should not have called delegate.ResolveToken") require.Fail(t, "should not have called delegate.ResolveToken")
return nil, fmt.Errorf("should not have called delegate.ResolveToken") return nil, nil, fmt.Errorf("should not have called delegate.ResolveToken")
} }
a := NewTestACLAgent(t, t.Name(), TestACLConfig()+` a := NewTestACLAgent(t, t.Name(), TestACLConfig()+`
@ -166,9 +195,9 @@ func TestACL_Version8(t *testing.T) {
t.Run("version 8 enabled", func(t *testing.T) { t.Run("version 8 enabled", func(t *testing.T) {
called := false called := false
resolveFn := func(string) (acl.Authorizer, error) { resolveFn := func(string) (structs.ACLIdentity, acl.Authorizer, error) {
called = true called = true
return nil, acl.ErrNotFound return nil, nil, acl.ErrNotFound
} }
a := NewTestACLAgent(t, t.Name(), TestACLConfig()+` a := NewTestACLAgent(t, t.Name(), TestACLConfig()+`
acl_enforce_version_8 = true acl_enforce_version_8 = true
@ -183,9 +212,9 @@ func TestACL_Version8(t *testing.T) {
func TestACL_AgentMasterToken(t *testing.T) { func TestACL_AgentMasterToken(t *testing.T) {
t.Parallel() t.Parallel()
resolveFn := func(string) (acl.Authorizer, error) { resolveFn := func(string) (structs.ACLIdentity, acl.Authorizer, error) {
require.Fail(t, "should not have called delegate.ResolveToken") require.Fail(t, "should not have called delegate.ResolveToken")
return nil, fmt.Errorf("should not have called delegate.ResolveToken") return nil, nil, fmt.Errorf("should not have called delegate.ResolveToken")
} }
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), resolveFn) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), resolveFn)
@ -203,9 +232,9 @@ func TestACL_AgentMasterToken(t *testing.T) {
func TestACL_RootAuthorizersDenied(t *testing.T) { func TestACL_RootAuthorizersDenied(t *testing.T) {
t.Parallel() t.Parallel()
resolveFn := func(string) (acl.Authorizer, error) { resolveFn := func(string) (structs.ACLIdentity, acl.Authorizer, error) {
require.Fail(t, "should not have called delegate.ResolveToken") require.Fail(t, "should not have called delegate.ResolveToken")
return nil, fmt.Errorf("should not have called delegate.ResolveToken") return nil, nil, fmt.Errorf("should not have called delegate.ResolveToken")
} }
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), resolveFn) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), resolveFn)
@ -227,54 +256,72 @@ func authzFromPolicy(policy *acl.Policy, cfg *acl.Config) (acl.Authorizer, error
return acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{policy}, cfg) return acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{policy}, cfg)
} }
// catalogPolicy supplies some standard policies to help with testing the type testToken struct {
// catalog-related vet and filter functions. token structs.ACLToken
func catalogPolicy(token string) (acl.Authorizer, error) { // yes the rules can exist on the token itself but that is legacy behavior
switch token { // that I would prefer these tests not rely on
rules string
}
case "node-ro": var (
return authzFromPolicy(&acl.Policy{ nodeROSecret = "7e80d017-bccc-492f-8dec-65f03aeaebf3"
PolicyRules: acl.PolicyRules{ nodeRWSecret = "e3586ee5-02a2-4bf4-9ec3-9c4be7606e8c"
NodePrefixes: []*acl.NodeRule{ serviceROSecret = "3d2c8552-df3b-4da7-9890-36885cbf56ac"
&acl.NodeRule{Name: "Node", Policy: "read"}, serviceRWSecret = "4a1017a2-f788-4be3-93f2-90566f1340bb"
otherRWSecret = "a38e8016-91b6-4876-b3e7-a307abbb2002"
testTokens = map[string]testToken{
nodeROSecret: testToken{
token: structs.ACLToken{
AccessorID: "9df2d1a4-2d07-414e-8ead-6053f56ed2eb",
SecretID: nodeROSecret,
}, },
rules: `node_prefix "Node" { policy = "read" }`,
}, },
}, nil) nodeRWSecret: testToken{
case "node-rw": token: structs.ACLToken{
return authzFromPolicy(&acl.Policy{ AccessorID: "efb6b7d5-d343-47c1-b4cb-aa6b94d2f490",
PolicyRules: acl.PolicyRules{ SecretID: nodeROSecret,
NodePrefixes: []*acl.NodeRule{
&acl.NodeRule{Name: "Node", Policy: "write"},
}, },
rules: `node_prefix "Node" { policy = "write" }`,
}, },
}, nil) serviceROSecret: testToken{
case "service-ro": token: structs.ACLToken{
return authzFromPolicy(&acl.Policy{ AccessorID: "0da53edb-36e5-4603-9c31-79965bad45f5",
PolicyRules: acl.PolicyRules{ SecretID: serviceROSecret,
ServicePrefixes: []*acl.ServiceRule{
&acl.ServiceRule{Name: "service", Policy: "read"},
}, },
rules: `service_prefix "service" { policy = "read" }`,
}, },
}, nil) serviceRWSecret: testToken{
case "service-rw": token: structs.ACLToken{
return authzFromPolicy(&acl.Policy{ AccessorID: "52504258-137a-41e6-9326-01f40e80872e",
PolicyRules: acl.PolicyRules{ SecretID: serviceRWSecret,
ServicePrefixes: []*acl.ServiceRule{
&acl.ServiceRule{Name: "service", Policy: "write"},
}, },
rules: `service_prefix "service" { policy = "write" }`,
}, },
}, nil) otherRWSecret: testToken{
case "other-rw": token: structs.ACLToken{
return authzFromPolicy(&acl.Policy{ AccessorID: "5e032c5b-c39e-4552-b5ad-8a9365b099c4",
PolicyRules: acl.PolicyRules{ SecretID: otherRWSecret,
ServicePrefixes: []*acl.ServiceRule{
&acl.ServiceRule{Name: "other", Policy: "write"},
}, },
rules: `service_prefix "other" { policy = "write" }`,
}, },
}, nil)
default:
return nil, fmt.Errorf("unknown token %q", token)
} }
)
func catalogPolicy(token string) (structs.ACLIdentity, acl.Authorizer, error) {
tok, ok := testTokens[token]
if !ok {
return nil, nil, acl.ErrNotFound
}
policy, err := acl.NewPolicyFromSource("", 0, tok.rules, acl.SyntaxCurrent, nil, nil)
if err != nil {
return nil, nil, err
}
authz, err := authzFromPolicy(policy, nil)
return &tok.token, authz, err
} }
func TestACL_vetServiceRegister(t *testing.T) { func TestACL_vetServiceRegister(t *testing.T) {
@ -282,14 +329,14 @@ func TestACL_vetServiceRegister(t *testing.T) {
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy)
// Register a new service, with permission. // Register a new service, with permission.
err := a.vetServiceRegister("service-rw", &structs.NodeService{ err := a.vetServiceRegister(serviceRWSecret, &structs.NodeService{
ID: "my-service", ID: "my-service",
Service: "service", Service: "service",
}) })
require.NoError(t, err) require.NoError(t, err)
// Register a new service without write privs. // Register a new service without write privs.
err = a.vetServiceRegister("service-ro", &structs.NodeService{ err = a.vetServiceRegister(serviceROSecret, &structs.NodeService{
ID: "my-service", ID: "my-service",
Service: "service", Service: "service",
}) })
@ -301,7 +348,7 @@ func TestACL_vetServiceRegister(t *testing.T) {
ID: "my-service", ID: "my-service",
Service: "other", Service: "other",
}, "") }, "")
err = a.vetServiceRegister("service-rw", &structs.NodeService{ err = a.vetServiceRegister(serviceRWSecret, &structs.NodeService{
ID: "my-service", ID: "my-service",
Service: "service", Service: "service",
}) })
@ -313,7 +360,7 @@ func TestACL_vetServiceUpdate(t *testing.T) {
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy)
// Update a service that doesn't exist. // Update a service that doesn't exist.
err := a.vetServiceUpdate("service-rw", structs.NewServiceID("my-service", nil)) err := a.vetServiceUpdate(serviceRWSecret, structs.NewServiceID("my-service", nil))
require.Error(t, err) require.Error(t, err)
require.Contains(t, err.Error(), "Unknown service") require.Contains(t, err.Error(), "Unknown service")
@ -322,11 +369,11 @@ func TestACL_vetServiceUpdate(t *testing.T) {
ID: "my-service", ID: "my-service",
Service: "service", Service: "service",
}, "") }, "")
err = a.vetServiceUpdate("service-rw", structs.NewServiceID("my-service", nil)) err = a.vetServiceUpdate(serviceRWSecret, structs.NewServiceID("my-service", nil))
require.NoError(t, err) require.NoError(t, err)
// Update without write privs. // Update without write privs.
err = a.vetServiceUpdate("service-ro", structs.NewServiceID("my-service", nil)) err = a.vetServiceUpdate(serviceROSecret, structs.NewServiceID("my-service", nil))
require.Error(t, err) require.Error(t, err)
require.True(t, acl.IsErrPermissionDenied(err)) require.True(t, acl.IsErrPermissionDenied(err))
} }
@ -336,7 +383,7 @@ func TestACL_vetCheckRegister(t *testing.T) {
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy)
// Register a new service check with write privs. // Register a new service check with write privs.
err := a.vetCheckRegister("service-rw", &structs.HealthCheck{ err := a.vetCheckRegister(serviceRWSecret, &structs.HealthCheck{
CheckID: types.CheckID("my-check"), CheckID: types.CheckID("my-check"),
ServiceID: "my-service", ServiceID: "my-service",
ServiceName: "service", ServiceName: "service",
@ -344,7 +391,7 @@ func TestACL_vetCheckRegister(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Register a new service check without write privs. // Register a new service check without write privs.
err = a.vetCheckRegister("service-ro", &structs.HealthCheck{ err = a.vetCheckRegister(serviceROSecret, &structs.HealthCheck{
CheckID: types.CheckID("my-check"), CheckID: types.CheckID("my-check"),
ServiceID: "my-service", ServiceID: "my-service",
ServiceName: "service", ServiceName: "service",
@ -353,13 +400,13 @@ func TestACL_vetCheckRegister(t *testing.T) {
require.True(t, acl.IsErrPermissionDenied(err)) require.True(t, acl.IsErrPermissionDenied(err))
// Register a new node check with write privs. // Register a new node check with write privs.
err = a.vetCheckRegister("node-rw", &structs.HealthCheck{ err = a.vetCheckRegister(nodeRWSecret, &structs.HealthCheck{
CheckID: types.CheckID("my-check"), CheckID: types.CheckID("my-check"),
}) })
require.NoError(t, err) require.NoError(t, err)
// Register a new node check without write privs. // Register a new node check without write privs.
err = a.vetCheckRegister("node-ro", &structs.HealthCheck{ err = a.vetCheckRegister(nodeROSecret, &structs.HealthCheck{
CheckID: types.CheckID("my-check"), CheckID: types.CheckID("my-check"),
}) })
require.Error(t, err) require.Error(t, err)
@ -376,7 +423,7 @@ func TestACL_vetCheckRegister(t *testing.T) {
ServiceID: "my-service", ServiceID: "my-service",
ServiceName: "other", ServiceName: "other",
}, "") }, "")
err = a.vetCheckRegister("service-rw", &structs.HealthCheck{ err = a.vetCheckRegister(serviceRWSecret, &structs.HealthCheck{
CheckID: types.CheckID("my-check"), CheckID: types.CheckID("my-check"),
ServiceID: "my-service", ServiceID: "my-service",
ServiceName: "service", ServiceName: "service",
@ -388,7 +435,7 @@ func TestACL_vetCheckRegister(t *testing.T) {
a.State.AddCheck(&structs.HealthCheck{ a.State.AddCheck(&structs.HealthCheck{
CheckID: types.CheckID("my-node-check"), CheckID: types.CheckID("my-node-check"),
}, "") }, "")
err = a.vetCheckRegister("service-rw", &structs.HealthCheck{ err = a.vetCheckRegister(serviceRWSecret, &structs.HealthCheck{
CheckID: types.CheckID("my-node-check"), CheckID: types.CheckID("my-node-check"),
ServiceID: "my-service", ServiceID: "my-service",
ServiceName: "service", ServiceName: "service",
@ -402,7 +449,7 @@ func TestACL_vetCheckUpdate(t *testing.T) {
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy)
// Update a check that doesn't exist. // Update a check that doesn't exist.
err := a.vetCheckUpdate("node-rw", structs.NewCheckID("my-check", nil)) err := a.vetCheckUpdate(nodeRWSecret, structs.NewCheckID("my-check", nil))
require.Error(t, err) require.Error(t, err)
require.Contains(t, err.Error(), "Unknown check") require.Contains(t, err.Error(), "Unknown check")
@ -416,11 +463,11 @@ func TestACL_vetCheckUpdate(t *testing.T) {
ServiceID: "my-service", ServiceID: "my-service",
ServiceName: "service", ServiceName: "service",
}, "") }, "")
err = a.vetCheckUpdate("service-rw", structs.NewCheckID("my-service-check", nil)) err = a.vetCheckUpdate(serviceRWSecret, structs.NewCheckID("my-service-check", nil))
require.NoError(t, err) require.NoError(t, err)
// Update service check without write privs. // Update service check without write privs.
err = a.vetCheckUpdate("service-ro", structs.NewCheckID("my-service-check", nil)) err = a.vetCheckUpdate(serviceROSecret, structs.NewCheckID("my-service-check", nil))
require.Error(t, err) require.Error(t, err)
require.True(t, acl.IsErrPermissionDenied(err), "not permission denied: %s", err.Error()) require.True(t, acl.IsErrPermissionDenied(err), "not permission denied: %s", err.Error())
@ -428,11 +475,11 @@ func TestACL_vetCheckUpdate(t *testing.T) {
a.State.AddCheck(&structs.HealthCheck{ a.State.AddCheck(&structs.HealthCheck{
CheckID: types.CheckID("my-node-check"), CheckID: types.CheckID("my-node-check"),
}, "") }, "")
err = a.vetCheckUpdate("node-rw", structs.NewCheckID("my-node-check", nil)) err = a.vetCheckUpdate(nodeRWSecret, structs.NewCheckID("my-node-check", nil))
require.NoError(t, err) require.NoError(t, err)
// Update without write privs. // Update without write privs.
err = a.vetCheckUpdate("node-ro", structs.NewCheckID("my-node-check", nil)) err = a.vetCheckUpdate(nodeROSecret, structs.NewCheckID("my-node-check", nil))
require.Error(t, err) require.Error(t, err)
require.True(t, acl.IsErrPermissionDenied(err)) require.True(t, acl.IsErrPermissionDenied(err))
} }
@ -442,7 +489,7 @@ func TestACL_filterMembers(t *testing.T) {
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy)
var members []serf.Member var members []serf.Member
require.NoError(t, a.filterMembers("node-ro", &members)) require.NoError(t, a.filterMembers(nodeROSecret, &members))
require.Len(t, members, 0) require.Len(t, members, 0)
members = []serf.Member{ members = []serf.Member{
@ -450,7 +497,7 @@ func TestACL_filterMembers(t *testing.T) {
serf.Member{Name: "Nope"}, serf.Member{Name: "Nope"},
serf.Member{Name: "Node 2"}, serf.Member{Name: "Node 2"},
} }
require.NoError(t, a.filterMembers("node-ro", &members)) require.NoError(t, a.filterMembers(nodeROSecret, &members))
require.Len(t, members, 2) require.Len(t, members, 2)
require.Equal(t, members[0].Name, "Node 1") require.Equal(t, members[0].Name, "Node 1")
require.Equal(t, members[1].Name, "Node 2") require.Equal(t, members[1].Name, "Node 2")
@ -461,11 +508,11 @@ func TestACL_filterServices(t *testing.T) {
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy)
services := make(map[structs.ServiceID]*structs.NodeService) services := make(map[structs.ServiceID]*structs.NodeService)
require.NoError(t, a.filterServices("node-ro", &services)) require.NoError(t, a.filterServices(nodeROSecret, &services))
services[structs.NewServiceID("my-service", nil)] = &structs.NodeService{ID: "my-service", Service: "service"} services[structs.NewServiceID("my-service", nil)] = &structs.NodeService{ID: "my-service", Service: "service"}
services[structs.NewServiceID("my-other", nil)] = &structs.NodeService{ID: "my-other", Service: "other"} services[structs.NewServiceID("my-other", nil)] = &structs.NodeService{ID: "my-other", Service: "other"}
require.NoError(t, a.filterServices("service-ro", &services)) require.NoError(t, a.filterServices(serviceROSecret, &services))
require.Contains(t, services, structs.NewServiceID("my-service", nil)) require.Contains(t, services, structs.NewServiceID("my-service", nil))
require.NotContains(t, services, structs.NewServiceID("my-other", nil)) require.NotContains(t, services, structs.NewServiceID("my-other", nil))
} }
@ -475,12 +522,12 @@ func TestACL_filterChecks(t *testing.T) {
a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy)
checks := make(map[structs.CheckID]*structs.HealthCheck) checks := make(map[structs.CheckID]*structs.HealthCheck)
require.NoError(t, a.filterChecks("node-ro", &checks)) require.NoError(t, a.filterChecks(nodeROSecret, &checks))
checks[structs.NewCheckID("my-node", nil)] = &structs.HealthCheck{} checks[structs.NewCheckID("my-node", nil)] = &structs.HealthCheck{}
checks[structs.NewCheckID("my-service", nil)] = &structs.HealthCheck{ServiceName: "service"} checks[structs.NewCheckID("my-service", nil)] = &structs.HealthCheck{ServiceName: "service"}
checks[structs.NewCheckID("my-other", nil)] = &structs.HealthCheck{ServiceName: "other"} checks[structs.NewCheckID("my-other", nil)] = &structs.HealthCheck{ServiceName: "other"}
require.NoError(t, a.filterChecks("service-ro", &checks)) require.NoError(t, a.filterChecks(serviceROSecret, &checks))
_, ok := checks[structs.NewCheckID("my-node", nil)] _, ok := checks[structs.NewCheckID("my-node", nil)]
require.False(t, ok) require.False(t, ok)
_, ok = checks[structs.NewCheckID("my-service", nil)] _, ok = checks[structs.NewCheckID("my-service", nil)]
@ -491,7 +538,7 @@ func TestACL_filterChecks(t *testing.T) {
checks[structs.NewCheckID("my-node", nil)] = &structs.HealthCheck{} checks[structs.NewCheckID("my-node", nil)] = &structs.HealthCheck{}
checks[structs.NewCheckID("my-service", nil)] = &structs.HealthCheck{ServiceName: "service"} checks[structs.NewCheckID("my-service", nil)] = &structs.HealthCheck{ServiceName: "service"}
checks[structs.NewCheckID("my-other", nil)] = &structs.HealthCheck{ServiceName: "other"} checks[structs.NewCheckID("my-other", nil)] = &structs.HealthCheck{ServiceName: "other"}
require.NoError(t, a.filterChecks("node-ro", &checks)) require.NoError(t, a.filterChecks(nodeROSecret, &checks))
_, ok = checks[structs.NewCheckID("my-node", nil)] _, ok = checks[structs.NewCheckID("my-node", nil)]
require.True(t, ok) require.True(t, ok)
_, ok = checks[structs.NewCheckID("my-service", nil)] _, ok = checks[structs.NewCheckID("my-service", nil)]

View File

@ -136,6 +136,7 @@ type delegate interface {
JoinLAN(addrs []string) (n int, err error) JoinLAN(addrs []string) (n int, err error)
RemoveFailedNode(node string, prune bool) error RemoveFailedNode(node string, prune bool) error
ResolveToken(secretID string) (acl.Authorizer, error) ResolveToken(secretID string) (acl.Authorizer, error)
ResolveTokenAndDefaultMeta(secretID string, entMeta *structs.EnterpriseMeta, authzContext *acl.AuthorizerContext) (acl.Authorizer, error)
RPC(method string, args interface{}, reply interface{}) error RPC(method string, args interface{}, reply interface{}) error
ACLsEnabled() bool ACLsEnabled() bool
UseLegacyACLs() bool UseLegacyACLs() bool
@ -2700,8 +2701,6 @@ func (a *Agent) addCheck(check *structs.HealthCheck, chkType *structs.CheckType,
ttl.Start() ttl.Start()
a.checkTTLs[cid] = ttl a.checkTTLs[cid] = ttl
a.logger.Printf("[DEBUG] ttl checks: %+v", a.checkTTLs)
case chkType.IsHTTP(): case chkType.IsHTTP():
if existing, ok := a.checkHTTPs[cid]; ok { if existing, ok := a.checkHTTPs[cid]; ok {
existing.Stop() existing.Stop()
@ -3160,7 +3159,7 @@ func (a *Agent) loadCheckState(check *structs.HealthCheck) error {
// Check if the state has expired // Check if the state has expired
if time.Now().Unix() >= p.Expires { if time.Now().Unix() >= p.Expires {
a.logger.Printf("[DEBUG] agent: check state expired for %q, not restoring", cid) a.logger.Printf("[DEBUG] agent: check state expired for %q, not restoring", cid.String())
return a.purgeCheckState(cid) return a.purgeCheckState(cid)
} }

View File

@ -220,8 +220,13 @@ func (s *HTTPServer) AgentServices(resp http.ResponseWriter, req *http.Request)
var filterExpression string var filterExpression string
s.parseFilter(req, &filterExpression) s.parseFilter(req, &filterExpression)
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &entMeta, nil)
if err != nil {
return nil, err
}
services := s.agent.State.Services(&entMeta) services := s.agent.State.Services(&entMeta)
if err := s.agent.filterServices(token, &services); err != nil { if err := s.agent.filterServicesWithAuthorizer(authz, &services); err != nil {
return nil, err return nil, err
} }
@ -269,6 +274,12 @@ func (s *HTTPServer) AgentService(resp http.ResponseWriter, req *http.Request) (
return nil, err return nil, err
} }
// need to resolve to default the meta
_, err := s.agent.resolveTokenAndDefaultMeta(token, &entMeta, nil)
if err != nil {
return nil, err
}
// Parse hash specially. Eventually this should happen in parseWait and end up // Parse hash specially. Eventually this should happen in parseWait and end up
// in QueryOptions but I didn't want to make very general changes right away. // in QueryOptions but I didn't want to make very general changes right away.
hash := req.URL.Query().Get("hash") hash := req.URL.Query().Get("hash")
@ -291,13 +302,13 @@ func (s *HTTPServer) AgentService(resp http.ResponseWriter, req *http.Request) (
ws.Add(svcState.WatchCh) ws.Add(svcState.WatchCh)
// Check ACLs. // Check ACLs.
rule, err := s.agent.resolveToken(token) authz, err := s.agent.resolveToken(token)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
svc.FillAuthzContext(&authzContext) svc.FillAuthzContext(&authzContext)
if rule != nil && rule.ServiceRead(svc.Service, &authzContext) != acl.Allow { if authz != nil && authz.ServiceRead(svc.Service, &authzContext) != acl.Allow {
return "", nil, acl.ErrPermissionDenied return "", nil, acl.ErrPermissionDenied
} }
@ -332,6 +343,11 @@ func (s *HTTPServer) AgentChecks(resp http.ResponseWriter, req *http.Request) (i
return nil, err return nil, err
} }
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &entMeta, nil)
if err != nil {
return nil, err
}
var filterExpression string var filterExpression string
s.parseFilter(req, &filterExpression) s.parseFilter(req, &filterExpression)
filter, err := bexpr.CreateFilter(filterExpression, nil, nil) filter, err := bexpr.CreateFilter(filterExpression, nil, nil)
@ -340,7 +356,7 @@ func (s *HTTPServer) AgentChecks(resp http.ResponseWriter, req *http.Request) (i
} }
checks := s.agent.State.Checks(&entMeta) checks := s.agent.State.Checks(&entMeta)
if err := s.agent.filterChecks(token, &checks); err != nil { if err := s.agent.filterChecksWithAuthorizer(authz, &checks); err != nil {
return nil, err return nil, err
} }
@ -480,6 +496,9 @@ func (s *HTTPServer) syncChanges() {
} }
func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) { func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
var token string
s.parseToken(req, &token)
var args structs.CheckDefinition var args structs.CheckDefinition
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err return nil, err
@ -504,12 +523,17 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
return nil, nil return nil, nil
} }
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &args.EnterpriseMeta, nil)
if err != nil {
return nil, err
}
// Construct the health check. // Construct the health check.
health := args.HealthCheck(s.agent.config.NodeName) health := args.HealthCheck(s.agent.config.NodeName)
// Verify the check type. // Verify the check type.
chkType := args.CheckType() chkType := args.CheckType()
err := chkType.Validate() err = chkType.Validate()
if err != nil { if err != nil {
resp.WriteHeader(http.StatusBadRequest) resp.WriteHeader(http.StatusBadRequest)
fmt.Fprint(resp, fmt.Errorf("Invalid check: %v", err)) fmt.Fprint(resp, fmt.Errorf("Invalid check: %v", err))
@ -528,9 +552,7 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
} }
// Get the provided token, if any, and vet against any ACL policies. // Get the provided token, if any, and vet against any ACL policies.
var token string if err := s.agent.vetCheckRegisterWithAuthorizer(authz, health); err != nil {
s.parseToken(req, &token)
if err := s.agent.vetCheckRegister(token, health); err != nil {
return nil, err return nil, err
} }
@ -553,9 +575,14 @@ func (s *HTTPServer) AgentDeregisterCheck(resp http.ResponseWriter, req *http.Re
return nil, err return nil, err
} }
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &checkID.EnterpriseMeta, nil)
if err != nil {
return nil, err
}
checkID.Normalize() checkID.Normalize()
if err := s.agent.vetCheckUpdate(token, checkID); err != nil { if err := s.agent.vetCheckUpdateWithAuthorizer(authz, checkID); err != nil {
return nil, err return nil, err
} }
@ -636,9 +663,14 @@ func (s *HTTPServer) agentCheckUpdate(resp http.ResponseWriter, req *http.Reques
return nil, err return nil, err
} }
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &cid.EnterpriseMeta, nil)
if err != nil {
return nil, err
}
cid.Normalize() cid.Normalize()
if err := s.agent.vetCheckUpdate(token, cid); err != nil { if err := s.agent.vetCheckUpdateWithAuthorizer(authz, cid); err != nil {
return nil, err return nil, err
} }
@ -808,6 +840,14 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
return nil, nil return nil, nil
} }
var token string
s.parseToken(req, &token)
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &args.EnterpriseMeta, nil)
if err != nil {
return nil, err
}
// Get the node service. // Get the node service.
ns := args.NodeService() ns := args.NodeService()
if ns.Weights != nil { if ns.Weights != nil {
@ -864,9 +904,7 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
} }
// Get the provided token, if any, and vet against any ACL policies. // Get the provided token, if any, and vet against any ACL policies.
var token string if err := s.agent.vetServiceRegisterWithAuthorizer(authz, ns); err != nil {
s.parseToken(req, &token)
if err := s.agent.vetServiceRegister(token, ns); err != nil {
return nil, err return nil, err
} }
@ -934,9 +972,14 @@ func (s *HTTPServer) AgentDeregisterService(resp http.ResponseWriter, req *http.
return nil, err return nil, err
} }
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &sid.EnterpriseMeta, nil)
if err != nil {
return nil, err
}
sid.Normalize() sid.Normalize()
if err := s.agent.vetServiceUpdate(token, sid); err != nil { if err := s.agent.vetServiceUpdateWithAuthorizer(authz, sid); err != nil {
return nil, err return nil, err
} }
@ -982,9 +1025,14 @@ func (s *HTTPServer) AgentServiceMaintenance(resp http.ResponseWriter, req *http
return nil, err return nil, err
} }
authz, err := s.agent.resolveTokenAndDefaultMeta(token, &sid.EnterpriseMeta, nil)
if err != nil {
return nil, err
}
sid.Normalize() sid.Normalize()
if err := s.agent.vetServiceUpdate(token, sid); err != nil { if err := s.agent.vetServiceUpdateWithAuthorizer(authz, sid); err != nil {
return nil, err return nil, err
} }

View File

@ -121,7 +121,7 @@ func (c *CheckMonitor) check() {
cmd, err = exec.Script(c.Script) cmd, err = exec.Script(c.Script)
} }
if err != nil { if err != nil {
c.Logger.Printf("[ERR] agent: Check %q failed to setup: %s", c.CheckID, err) c.Logger.Printf("[ERR] agent: Check %q failed to setup: %s", c.CheckID.String(), err)
c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, err.Error()) c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, err.Error())
return return
} }
@ -138,13 +138,13 @@ func (c *CheckMonitor) check() {
outputStr = fmt.Sprintf("Captured %d of %d bytes\n...\n%s", outputStr = fmt.Sprintf("Captured %d of %d bytes\n...\n%s",
output.Size(), output.TotalWritten(), outputStr) output.Size(), output.TotalWritten(), outputStr)
} }
c.Logger.Printf("[TRACE] agent: Check %q output: %s", c.CheckID, outputStr) c.Logger.Printf("[TRACE] agent: Check %q output: %s", c.CheckID.String(), outputStr)
return outputStr return outputStr
} }
// Start the check // Start the check
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
c.Logger.Printf("[ERR] agent: Check %q failed to invoke: %s", c.CheckID, err) c.Logger.Printf("[ERR] agent: Check %q failed to invoke: %s", c.CheckID.String(), err)
c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, err.Error()) c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, err.Error())
return return
} }
@ -162,11 +162,11 @@ func (c *CheckMonitor) check() {
select { select {
case <-time.After(timeout): case <-time.After(timeout):
if err := exec.KillCommandSubtree(cmd); err != nil { if err := exec.KillCommandSubtree(cmd); err != nil {
c.Logger.Printf("[WARN] agent: Check %q failed to kill after timeout: %s", c.CheckID, err) c.Logger.Printf("[WARN] agent: Check %q failed to kill after timeout: %s", c.CheckID.String(), err)
} }
msg := fmt.Sprintf("Timed out (%s) running check", timeout.String()) msg := fmt.Sprintf("Timed out (%s) running check", timeout.String())
c.Logger.Printf("[WARN] agent: Check %q: %s", c.CheckID, msg) c.Logger.Printf("[WARN] agent: Check %q: %s", c.CheckID.String(), msg)
outputStr := truncateAndLogOutput() outputStr := truncateAndLogOutput()
if len(outputStr) > 0 { if len(outputStr) > 0 {
@ -259,7 +259,7 @@ func (c *CheckTTL) run() {
select { select {
case <-c.timer.C: case <-c.timer.C:
c.Logger.Printf("[WARN] agent: Check %q missed TTL, is now critical", c.Logger.Printf("[WARN] agent: Check %q missed TTL, is now critical",
c.CheckID) c.CheckID.String())
c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, c.getExpiredOutput()) c.Notify.UpdateCheck(c.CheckID, api.HealthCritical, c.getExpiredOutput())
case <-c.stopCh: case <-c.stopCh:
@ -285,7 +285,7 @@ func (c *CheckTTL) getExpiredOutput() string {
// and to renew the TTL. If expired, TTL is restarted. // and to renew the TTL. If expired, TTL is restarted.
// output is returned (might be truncated) // output is returned (might be truncated)
func (c *CheckTTL) SetStatus(status, output string) string { func (c *CheckTTL) SetStatus(status, output string) string {
c.Logger.Printf("[DEBUG] agent: Check %q status is now %s", c.CheckID, status) c.Logger.Printf("[DEBUG] agent: Check %q status is now %s", c.CheckID.String(), status)
total := len(output) total := len(output)
if total > c.OutputMaxSize { if total > c.OutputMaxSize {
output = fmt.Sprintf("%s ... (captured %d of %d bytes)", output = fmt.Sprintf("%s ... (captured %d of %d bytes)",
@ -450,7 +450,7 @@ func (c *CheckHTTP) check() {
// Read the response into a circular buffer to limit the size // Read the response into a circular buffer to limit the size
output, _ := circbuf.NewBuffer(int64(c.OutputMaxSize)) output, _ := circbuf.NewBuffer(int64(c.OutputMaxSize))
if _, err := io.Copy(output, resp.Body); err != nil { if _, err := io.Copy(output, resp.Body); err != nil {
c.Logger.Printf("[WARN] agent: Check %q error while reading body: %s", c.CheckID, err) c.Logger.Printf("[WARN] agent: Check %q error while reading body: %s", c.CheckID.String(), err)
} }
// Format the response body // Format the response body
@ -542,7 +542,7 @@ func (c *CheckTCP) run() {
func (c *CheckTCP) check() { func (c *CheckTCP) check() {
conn, err := c.dialer.Dial(`tcp`, c.TCP) conn, err := c.dialer.Dial(`tcp`, c.TCP)
if err != nil { if err != nil {
c.Logger.Printf("[WARN] agent: Check %q socket connection failed: %s", c.CheckID, err) c.Logger.Printf("[WARN] agent: Check %q socket connection failed: %s", c.CheckID.String(), err)
c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error()) c.StatusHandler.updateCheck(c.CheckID, api.HealthCritical, err.Error())
return return
} }
@ -615,7 +615,7 @@ func (c *CheckDocker) check() {
var out string var out string
status, b, err := c.doCheck() status, b, err := c.doCheck()
if err != nil { if err != nil {
c.Logger.Printf("[DEBUG] agent: Check %q: %s", c.CheckID, err) c.Logger.Printf("[DEBUG] agent: Check %q: %s", c.CheckID.String(), err)
out = err.Error() out = err.Error()
} else { } else {
// out is already limited to CheckBufSize since we're getting a // out is already limited to CheckBufSize since we're getting a
@ -625,7 +625,7 @@ func (c *CheckDocker) check() {
if int(b.TotalWritten()) > len(out) { if int(b.TotalWritten()) > len(out) {
out = fmt.Sprintf("Captured %d of %d bytes\n...\n%s", len(out), b.TotalWritten(), out) out = fmt.Sprintf("Captured %d of %d bytes\n...\n%s", len(out), b.TotalWritten(), out)
} }
c.Logger.Printf("[TRACE] agent: Check %q output: %s", c.CheckID, out) c.Logger.Printf("[TRACE] agent: Check %q output: %s", c.CheckID.String(), out)
} }
c.StatusHandler.updateCheck(c.CheckID, status, out) c.StatusHandler.updateCheck(c.CheckID, status, out)
} }
@ -657,10 +657,10 @@ func (c *CheckDocker) doCheck() (string, *circbuf.Buffer, error) {
case 0: case 0:
return api.HealthPassing, buf, nil return api.HealthPassing, buf, nil
case 1: case 1:
c.Logger.Printf("[DEBUG] agent: Check %q failed with exit code: %d", c.CheckID, exitCode) c.Logger.Printf("[DEBUG] agent: Check %q failed with exit code: %d", c.CheckID.String(), exitCode)
return api.HealthWarning, buf, nil return api.HealthWarning, buf, nil
default: default:
c.Logger.Printf("[DEBUG] agent: Check %q failed with exit code: %d", c.CheckID, exitCode) c.Logger.Printf("[DEBUG] agent: Check %q failed with exit code: %d", c.CheckID.String(), exitCode)
return api.HealthCritical, buf, nil return api.HealthCritical, buf, nil
} }
} }
@ -782,19 +782,19 @@ func (s *StatusHandler) updateCheck(checkID structs.CheckID, status, output stri
s.successCounter++ s.successCounter++
s.failuresCounter = 0 s.failuresCounter = 0
if s.successCounter >= s.successBeforePassing { if s.successCounter >= s.successBeforePassing {
s.logger.Printf("[DEBUG] agent: Check %q is %q", checkID, status) s.logger.Printf("[DEBUG] agent: Check %q is %q", checkID.String(), status)
s.inner.UpdateCheck(checkID, status, output) s.inner.UpdateCheck(checkID, status, output)
return return
} }
s.logger.Printf("[WARN] agent: Check %q was %q but has not reached success threshold %d/%d", checkID, status, s.successCounter, s.successBeforePassing) s.logger.Printf("[WARN] agent: Check %q was %q but has not reached success threshold %d/%d", checkID.String(), status, s.successCounter, s.successBeforePassing)
} else { } else {
s.failuresCounter++ s.failuresCounter++
s.successCounter = 0 s.successCounter = 0
if s.failuresCounter >= s.failuresBeforeCritical { if s.failuresCounter >= s.failuresBeforeCritical {
s.logger.Printf("[WARN] agent: Check %q is now critical", checkID) s.logger.Printf("[WARN] agent: Check %q is now critical", checkID.String())
s.inner.UpdateCheck(checkID, status, output) s.inner.UpdateCheck(checkID, status, output)
return return
} }
s.logger.Printf("[WARN] agent: Check %q failed but has not reached failure threshold %d/%d", checkID, s.failuresCounter, s.failuresBeforeCritical) s.logger.Printf("[WARN] agent: Check %q failed but has not reached failure threshold %d/%d", checkID.String(), s.failuresCounter, s.failuresBeforeCritical)
} }
} }

View File

@ -69,6 +69,44 @@ const (
tokenRoleResolutionMaxRetries = 5 tokenRoleResolutionMaxRetries = 5
) )
// missingIdentity is used to return some identity in the event that the real identity cannot be ascertained
type missingIdentity struct {
reason string
token string
}
func (id *missingIdentity) ID() string {
return id.reason
}
func (id *missingIdentity) SecretToken() string {
return id.token
}
func (id *missingIdentity) PolicyIDs() []string {
return nil
}
func (id *missingIdentity) RoleIDs() []string {
return nil
}
func (id *missingIdentity) EmbeddedPolicy() *structs.ACLPolicy {
return nil
}
func (id *missingIdentity) ServiceIdentityList() []*structs.ACLServiceIdentity {
return nil
}
func (id *missingIdentity) IsExpired(asOf time.Time) bool {
return false
}
func (id *missingIdentity) EnterpriseMetadata() *structs.EnterpriseMeta {
return structs.DefaultEnterpriseMeta()
}
func minTTL(a time.Duration, b time.Duration) time.Duration { func minTTL(a time.Duration, b time.Duration) time.Duration {
if a < b { if a < b {
return a return a
@ -287,7 +325,7 @@ func (r *ACLResolver) fetchAndCacheTokenLegacy(token string, cached *structs.Aut
} }
} }
func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) { func (r *ACLResolver) resolveTokenLegacy(token string) (structs.ACLIdentity, acl.Authorizer, error) {
defer metrics.MeasureSince([]string{"acl", "resolveTokenLegacy"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "resolveTokenLegacy"}, time.Now())
// Attempt to resolve locally first (local results are not cached) // Attempt to resolve locally first (local results are not cached)
@ -297,18 +335,23 @@ func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) {
if err == nil && identity != nil { if err == nil && identity != nil {
policies, err := r.resolvePoliciesForIdentity(identity) policies, err := r.resolvePoliciesForIdentity(identity)
if err != nil { if err != nil {
return nil, err return identity, nil, err
} }
authz, err := policies.Compile(r.cache, r.entConf) authz, err := policies.Compile(r.cache, r.entConf)
if err != nil { if err != nil {
return nil, err return identity, nil, err
} }
return acl.NewChainedAuthorizer([]acl.Authorizer{authz, acl.RootAuthorizer(r.config.ACLDefaultPolicy)}), nil return identity, acl.NewChainedAuthorizer([]acl.Authorizer{authz, acl.RootAuthorizer(r.config.ACLDefaultPolicy)}), nil
} }
return nil, err return nil, nil, err
}
identity := &missingIdentity{
reason: "legacy-token",
token: token,
} }
// Look in the cache prior to making a RPC request // Look in the cache prior to making a RPC request
@ -317,9 +360,9 @@ func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) {
if entry != nil && entry.Age() <= minTTL(entry.TTL, r.config.ACLTokenTTL) { if entry != nil && entry.Age() <= minTTL(entry.TTL, r.config.ACLTokenTTL) {
metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1) metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1)
if entry.Authorizer != nil { if entry.Authorizer != nil {
return entry.Authorizer, nil return identity, entry.Authorizer, nil
} }
return nil, acl.ErrNotFound return identity, nil, acl.ErrNotFound
} }
metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1) metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1)
@ -334,9 +377,9 @@ func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) {
if !waitForResult { if !waitForResult {
// waitForResult being false requires the cacheEntry to not be nil // waitForResult being false requires the cacheEntry to not be nil
if entry.Authorizer != nil { if entry.Authorizer != nil {
return entry.Authorizer, nil return identity, entry.Authorizer, nil
} }
return nil, acl.ErrNotFound return identity, nil, acl.ErrNotFound
} }
// block waiting for the async RPC to finish. // block waiting for the async RPC to finish.
@ -347,7 +390,7 @@ func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) {
authorizer = res.Val.(acl.Authorizer) authorizer = res.Val.(acl.Authorizer)
} }
return authorizer, res.Err return identity, authorizer, res.Err
} }
func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) { func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) {
@ -987,13 +1030,13 @@ func (r *ACLResolver) disableACLsWhenUpstreamDisabled(err error) error {
return err return err
} }
func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) { func (r *ACLResolver) ResolveTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer, error) {
if !r.ACLsEnabled() { if !r.ACLsEnabled() {
return nil, nil return nil, nil, nil
} }
if acl.RootAuthorizer(token) != nil { if acl.RootAuthorizer(token) != nil {
return nil, acl.ErrRootDenied return nil, nil, acl.ErrRootDenied
} }
// handle the anonymous token // handle the anonymous token
@ -1002,8 +1045,8 @@ func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) {
} }
if r.delegate.UseLegacyACLs() { if r.delegate.UseLegacyACLs() {
authorizer, err := r.resolveTokenLegacy(token) identity, authorizer, err := r.resolveTokenLegacy(token)
return authorizer, r.disableACLsWhenUpstreamDisabled(err) return identity, authorizer, r.disableACLsWhenUpstreamDisabled(err)
} }
defer metrics.MeasureSince([]string{"acl", "ResolveToken"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "ResolveToken"}, time.Now())
@ -1013,10 +1056,10 @@ func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) {
r.disableACLsWhenUpstreamDisabled(err) r.disableACLsWhenUpstreamDisabled(err)
if IsACLRemoteError(err) { if IsACLRemoteError(err) {
r.logger.Printf("[ERR] consul.acl: %v", err) r.logger.Printf("[ERR] consul.acl: %v", err)
return r.down, nil return &missingIdentity{reason: "primary-dc-down", token: token}, r.down, nil
} }
return nil, err return nil, nil, err
} }
// Build the Authorizer // Build the Authorizer
@ -1024,7 +1067,7 @@ func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) {
authz, err := policies.Compile(r.cache, r.entConf) authz, err := policies.Compile(r.cache, r.entConf)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
chain = append(chain, authz) chain = append(chain, authz)
@ -1032,15 +1075,20 @@ func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) {
if err != nil { if err != nil {
if IsACLRemoteError(err) { if IsACLRemoteError(err) {
r.logger.Printf("[ERR] consul.acl: %v", err) r.logger.Printf("[ERR] consul.acl: %v", err)
return r.down, nil return identity, r.down, nil
} }
return nil, err return nil, nil, err
} else if authz != nil { } else if authz != nil {
chain = append(chain, authz) chain = append(chain, authz)
} }
chain = append(chain, acl.RootAuthorizer(r.config.ACLDefaultPolicy)) chain = append(chain, acl.RootAuthorizer(r.config.ACLDefaultPolicy))
return acl.NewChainedAuthorizer(chain), nil return identity, acl.NewChainedAuthorizer(chain), nil
}
func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) {
_, authz, err := r.ResolveTokenToIdentityAndAuthorizer(token)
return authz, err
} }
func (r *ACLResolver) ACLsEnabled() bool { func (r *ACLResolver) ACLsEnabled() bool {

View File

@ -106,3 +106,27 @@ func (c *Client) ResolveRoleFromID(roleID string) (bool, *structs.ACLRole, error
func (c *Client) ResolveToken(token string) (acl.Authorizer, error) { func (c *Client) ResolveToken(token string) (acl.Authorizer, error) {
return c.acls.ResolveToken(token) return c.acls.ResolveToken(token)
} }
func (c *Client) ResolveTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer, error) {
return c.acls.ResolveTokenToIdentityAndAuthorizer(token)
}
func (c *Client) ResolveTokenAndDefaultMeta(token string, entMeta *structs.EnterpriseMeta, authzContext *acl.AuthorizerContext) (acl.Authorizer, error) {
identity, authz, err := c.acls.ResolveTokenToIdentityAndAuthorizer(token)
if err != nil {
return nil, err
}
// Default the EnterpriseMeta based on the Tokens meta or actual defaults
// in the case of unknown identity
if identity != nil {
entMeta.Merge(identity.EnterpriseMetadata())
} else {
entMeta.Merge(structs.DefaultEnterpriseMeta())
}
// Use the meta to fill in the ACL authorization context
entMeta.FillAuthzContext(authzContext)
return authz, err
}

View File

@ -205,19 +205,17 @@ func (a *ACL) TokenRead(args *structs.ACLTokenGetRequest, reply *structs.ACLToke
return err return err
} }
var rule acl.Authorizer var authz acl.Authorizer
if args.TokenIDType == structs.ACLTokenAccessor { if args.TokenIDType == structs.ACLTokenAccessor {
var entCtx acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
var err error var err error
var authzContext acl.AuthorizerContext
// Only ACLRead privileges are required to list tokens // Only ACLRead privileges are required to list tokens
// However if you do not have ACLWrite as well the token // However if you do not have ACLWrite as well the token
// secrets will be redacted // secrets will be redacted
if rule, err = a.srv.ResolveToken(args.Token); err != nil { if authz, err = a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
@ -231,7 +229,7 @@ func (a *ACL) TokenRead(args *structs.ACLTokenGetRequest, reply *structs.ACLToke
if args.TokenIDType == structs.ACLTokenAccessor { if args.TokenIDType == structs.ACLTokenAccessor {
index, token, err = state.ACLTokenGetByAccessor(ws, args.TokenID, &args.EnterpriseMeta) index, token, err = state.ACLTokenGetByAccessor(ws, args.TokenID, &args.EnterpriseMeta)
if token != nil { if token != nil {
a.srv.filterACLWithAuthorizer(rule, &token) a.srv.filterACLWithAuthorizer(authz, &token)
// token secret was redacted // token secret was redacted
if token.SecretID == redactedToken { if token.SecretID == redactedToken {
@ -277,12 +275,11 @@ func (a *ACL) TokenClone(args *structs.ACLTokenSetRequest, reply *structs.ACLTok
defer metrics.MeasureSince([]string{"acl", "token", "clone"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "token", "clone"}, time.Now())
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.ACLToken.FillAuthzContext(&entCtx) authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.ACLToken.EnterpriseMeta, &authzContext)
if err != nil {
if rule, err := a.srv.ResolveToken(args.Token); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -348,11 +345,10 @@ func (a *ACL) TokenSet(args *structs.ACLTokenSetRequest, reply *structs.ACLToken
defer metrics.MeasureSince([]string{"acl", "token", "upsert"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "token", "upsert"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.ACLToken.FillAuthzContext(&entCtx) if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.ACLToken.EnterpriseMeta, &authzContext); err != nil {
if rule, err := a.srv.ResolveToken(args.Token); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -737,12 +733,10 @@ func (a *ACL) TokenDelete(args *structs.ACLTokenDeleteRequest, reply *string) er
defer metrics.MeasureSince([]string{"acl", "token", "delete"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "token", "delete"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx) if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
if rule, err := a.srv.ResolveToken(args.Token); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -826,13 +820,11 @@ func (a *ACL) TokenList(args *structs.ACLTokenListRequest, reply *structs.ACLTok
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx) authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
rule, err := a.srv.ResolveToken(args.Token)
if err != nil { if err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -854,7 +846,7 @@ func (a *ACL) TokenList(args *structs.ACLTokenListRequest, reply *structs.ACLTok
} }
// filter down to just the tokens that the requester has permissions to read // filter down to just the tokens that the requester has permissions to read
if err := a.srv.filterACLWithAuthorizer(rule, &stubs); err != nil { if err := a.srv.filterACLWithAuthorizer(authz, &stubs); err != nil {
return err return err
} }
@ -876,10 +868,10 @@ func (a *ACL) TokenBatchRead(args *structs.ACLTokenBatchGetRequest, reply *struc
return err return err
} }
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveToken(args.Token)
if err != nil { if err != nil {
return err return err
} else if rule == nil { } else if authz == nil {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -901,7 +893,7 @@ func (a *ACL) TokenBatchRead(args *structs.ACLTokenBatchGetRequest, reply *struc
ret := make(structs.ACLTokens, 0, len(tokens)) ret := make(structs.ACLTokens, 0, len(tokens))
for _, token := range tokens { for _, token := range tokens {
final := token final := token
a.srv.filterACLWithAuthorizer(rule, &final) a.srv.filterACLWithAuthorizer(authz, &final)
if final != nil { if final != nil {
ret = append(ret, final) ret = append(ret, final)
if final.SecretID == redactedToken { if final.SecretID == redactedToken {
@ -930,12 +922,10 @@ func (a *ACL) PolicyRead(args *structs.ACLPolicyGetRequest, reply *structs.ACLPo
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx) if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
if rule, err := a.srv.ResolveToken(args.Token); err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -961,10 +951,10 @@ func (a *ACL) PolicyBatchRead(args *structs.ACLPolicyBatchGetRequest, reply *str
return err return err
} }
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveToken(args.Token)
if err != nil { if err != nil {
return err return err
} else if rule == nil { } else if authz == nil {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -975,7 +965,7 @@ func (a *ACL) PolicyBatchRead(args *structs.ACLPolicyBatchGetRequest, reply *str
return err return err
} }
a.srv.filterACLWithAuthorizer(rule, &policies) a.srv.filterACLWithAuthorizer(authz, &policies)
reply.Index, reply.Policies = index, policies reply.Index, reply.Policies = index, policies
return nil return nil
@ -1002,12 +992,11 @@ func (a *ACL) PolicySet(args *structs.ACLPolicySetRequest, reply *structs.ACLPol
defer metrics.MeasureSince([]string{"acl", "policy", "upsert"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "policy", "upsert"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.Policy.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.Policy.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1138,12 +1127,11 @@ func (a *ACL) PolicyDelete(args *structs.ACLPolicyDeleteRequest, reply *string)
defer metrics.MeasureSince([]string{"acl", "policy", "delete"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "policy", "delete"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1195,13 +1183,12 @@ func (a *ACL) PolicyList(args *structs.ACLPolicyListRequest, reply *structs.ACLP
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil { if err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1213,7 +1200,7 @@ func (a *ACL) PolicyList(args *structs.ACLPolicyListRequest, reply *structs.ACLP
} }
// filter down to just what the requester has permissions to see // filter down to just what the requester has permissions to see
a.srv.filterACLWithAuthorizer(rule, &policies) a.srv.filterACLWithAuthorizer(authz, &policies)
var stubs structs.ACLPolicyListStubs var stubs structs.ACLPolicyListStubs
for _, policy := range policies { for _, policy := range policies {
@ -1351,12 +1338,11 @@ func (a *ACL) RoleRead(args *structs.ACLRoleGetRequest, reply *structs.ACLRoleRe
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1391,10 +1377,10 @@ func (a *ACL) RoleBatchRead(args *structs.ACLRoleBatchGetRequest, reply *structs
return err return err
} }
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveToken(args.Token)
if err != nil { if err != nil {
return err return err
} else if rule == nil { } else if authz == nil {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1405,7 +1391,7 @@ func (a *ACL) RoleBatchRead(args *structs.ACLRoleBatchGetRequest, reply *structs
return err return err
} }
a.srv.filterACLWithAuthorizer(rule, &roles) a.srv.filterACLWithAuthorizer(authz, &roles)
reply.Index, reply.Roles = index, roles reply.Index, reply.Roles = index, roles
return nil return nil
@ -1432,12 +1418,11 @@ func (a *ACL) RoleSet(args *structs.ACLRoleSetRequest, reply *structs.ACLRole) e
defer metrics.MeasureSince([]string{"acl", "role", "upsert"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "role", "upsert"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.Role.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.Role.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1582,12 +1567,11 @@ func (a *ACL) RoleDelete(args *structs.ACLRoleDeleteRequest, reply *string) erro
defer metrics.MeasureSince([]string{"acl", "role", "delete"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "role", "delete"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1635,13 +1619,12 @@ func (a *ACL) RoleList(args *structs.ACLRoleListRequest, reply *structs.ACLRoleL
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil { if err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1652,7 +1635,7 @@ func (a *ACL) RoleList(args *structs.ACLRoleListRequest, reply *structs.ACLRoleL
return err return err
} }
a.srv.filterACLWithAuthorizer(rule, &roles) a.srv.filterACLWithAuthorizer(authz, &roles)
reply.Index, reply.Roles = index, roles reply.Index, reply.Roles = index, roles
return nil return nil
@ -1721,13 +1704,12 @@ func (a *ACL) BindingRuleRead(args *structs.ACLBindingRuleGetRequest, reply *str
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil { if err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1763,13 +1745,12 @@ func (a *ACL) BindingRuleSet(args *structs.ACLBindingRuleSetRequest, reply *stru
defer metrics.MeasureSince([]string{"acl", "bindingrule", "upsert"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "bindingrule", "upsert"}, time.Now())
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.BindingRule.FillAuthzContext(&entCtx)
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.BindingRule.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1792,6 +1773,7 @@ func (a *ACL) BindingRuleSet(args *structs.ACLBindingRuleSetRequest, reply *stru
// Verify the role exists // Verify the role exists
var err error var err error
// specifically disregarding the enterprise meta here
_, existing, err = state.ACLBindingRuleGetByID(nil, rule.ID, nil) _, existing, err = state.ACLBindingRuleGetByID(nil, rule.ID, nil)
if err != nil { if err != nil {
return fmt.Errorf("acl binding rule lookup failed: %v", err) return fmt.Errorf("acl binding rule lookup failed: %v", err)
@ -1894,13 +1876,12 @@ func (a *ACL) BindingRuleDelete(args *structs.ACLBindingRuleDeleteRequest, reply
defer metrics.MeasureSince([]string{"acl", "bindingrule", "delete"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "bindingrule", "delete"}, time.Now())
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1948,13 +1929,12 @@ func (a *ACL) BindingRuleList(args *structs.ACLBindingRuleListRequest, reply *st
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil { if err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -1965,7 +1945,7 @@ func (a *ACL) BindingRuleList(args *structs.ACLBindingRuleListRequest, reply *st
return err return err
} }
a.srv.filterACLWithAuthorizer(rule, &rules) a.srv.filterACLWithAuthorizer(authz, &rules)
reply.Index, reply.BindingRules = index, rules reply.Index, reply.BindingRules = index, rules
return nil return nil
@ -1989,12 +1969,11 @@ func (a *ACL) AuthMethodRead(args *structs.ACLAuthMethodGetRequest, reply *struc
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -2031,12 +2010,11 @@ func (a *ACL) AuthMethodSet(args *structs.ACLAuthMethodSetRequest, reply *struct
defer metrics.MeasureSince([]string{"acl", "authmethod", "upsert"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "authmethod", "upsert"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.AuthMethod.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.AuthMethod.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -2119,12 +2097,11 @@ func (a *ACL) AuthMethodDelete(args *structs.ACLAuthMethodDeleteRequest, reply *
defer metrics.MeasureSince([]string{"acl", "authmethod", "delete"}, time.Now()) defer metrics.MeasureSince([]string{"acl", "authmethod", "delete"}, time.Now())
// Verify token is permitted to modify ACLs // Verify token is permitted to modify ACLs
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
if rule, err := a.srv.ResolveToken(args.Token); err != nil { if authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext); err != nil {
return err return err
} else if rule == nil || rule.ACLWrite(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLWrite(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -2173,13 +2150,12 @@ func (a *ACL) AuthMethodList(args *structs.ACLAuthMethodListRequest, reply *stru
return err return err
} }
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := a.srv.ResolveToken(args.Token) authz, err := a.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil { if err != nil {
return err return err
} else if rule == nil || rule.ACLRead(&entCtx) != acl.Allow { } else if authz == nil || authz.ACLRead(&authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -2190,7 +2166,7 @@ func (a *ACL) AuthMethodList(args *structs.ACLAuthMethodListRequest, reply *stru
return err return err
} }
a.srv.filterACLWithAuthorizer(rule, &methods) a.srv.filterACLWithAuthorizer(authz, &methods)
var stubs structs.ACLAuthMethodListStubs var stubs structs.ACLAuthMethodListStubs
for _, method := range methods { for _, method := range methods {

View File

@ -213,6 +213,30 @@ func (s *Server) ResolveToken(token string) (acl.Authorizer, error) {
return s.acls.ResolveToken(token) return s.acls.ResolveToken(token)
} }
func (s *Server) ResolveTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer, error) {
return s.acls.ResolveTokenToIdentityAndAuthorizer(token)
}
func (s *Server) ResolveTokenAndDefaultMeta(token string, entMeta *structs.EnterpriseMeta, authzContext *acl.AuthorizerContext) (acl.Authorizer, error) {
identity, authz, err := s.acls.ResolveTokenToIdentityAndAuthorizer(token)
if err != nil {
return nil, err
}
// Default the EnterpriseMeta based on the Tokens meta or actual defaults
// in the case of unknown identity
if identity != nil {
entMeta.Merge(identity.EnterpriseMetadata())
} else {
entMeta.Merge(structs.DefaultEnterpriseMeta())
}
// Use the meta to fill in the ACL authorization context
entMeta.FillAuthzContext(authzContext)
return authz, err
}
func (s *Server) filterACL(token string, subj interface{}) error { func (s *Server) filterACL(token string, subj interface{}) error {
return s.acls.filterACL(token, subj) return s.acls.filterACL(token, subj)
} }

View File

@ -35,7 +35,7 @@ func nodePreApply(nodeName, nodeID string) error {
return nil return nil
} }
func servicePreApply(service *structs.NodeService, rule acl.Authorizer) error { func servicePreApply(service *structs.NodeService, authz acl.Authorizer) error {
// Validate the service. This is in addition to the below since // Validate the service. This is in addition to the below since
// the above just hasn't been moved over yet. We should move it over // the above just hasn't been moved over yet. We should move it over
// in time. // in time.
@ -68,14 +68,14 @@ func servicePreApply(service *structs.NodeService, rule acl.Authorizer) error {
// later if version 0.8 is enabled, so we can eventually just // later if version 0.8 is enabled, so we can eventually just
// delete this and do all the ACL checks down there. // delete this and do all the ACL checks down there.
if service.Service != structs.ConsulServiceName { if service.Service != structs.ConsulServiceName {
if rule != nil && rule.ServiceWrite(service.Service, &authzContext) != acl.Allow { if authz != nil && authz.ServiceWrite(service.Service, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
// Proxies must have write permission on their destination // Proxies must have write permission on their destination
if service.Kind == structs.ServiceKindConnectProxy { if service.Kind == structs.ServiceKindConnectProxy {
if rule != nil && rule.ServiceWrite(service.Proxy.DestinationServiceName, &authzContext) != acl.Allow { if authz != nil && authz.ServiceWrite(service.Proxy.DestinationServiceName, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
} }
@ -92,17 +92,25 @@ func checkPreApply(check *structs.HealthCheck) {
// Register is used register that a node is providing a given service. // Register is used register that a node is providing a given service.
func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error { func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error {
if err := c.srv.validateEnterpriseRequest(args.GetEnterpriseMeta(), true); err != nil {
return err
}
if done, err := c.srv.forward("Catalog.Register", args, args, reply); done { if done, err := c.srv.forward("Catalog.Register", args, args, reply); done {
return err return err
} }
defer metrics.MeasureSince([]string{"catalog", "register"}, time.Now()) defer metrics.MeasureSince([]string{"catalog", "register"}, time.Now())
// Fetch the ACL token, if any. // Fetch the ACL token, if any.
rule, err := c.srv.ResolveToken(args.Token) authz, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := c.srv.validateEnterpriseRequest(args.GetEnterpriseMeta(), true); err != nil {
return err
}
// This needs to happen before the other preapply checks as it will fixup some of the
// internal enterprise metas on the services and checks
state := c.srv.fsm.State()
entMeta, err := state.ValidateRegisterRequest(args)
if err != nil { if err != nil {
return err return err
} }
@ -117,7 +125,7 @@ func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error
// Handle a service registration. // Handle a service registration.
if args.Service != nil { if args.Service != nil {
if err := servicePreApply(args.Service, rule); err != nil { if err := servicePreApply(args.Service, authz); err != nil {
return err return err
} }
} }
@ -141,20 +149,14 @@ func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error
} }
} }
state := c.srv.fsm.State()
entMeta, err := state.ValidateRegisterRequest(args)
if err != nil {
return err
}
// Check the complete register request against the given ACL policy. // Check the complete register request against the given ACL policy.
if rule != nil && c.srv.config.ACLEnforceVersion8 { if authz != nil && c.srv.config.ACLEnforceVersion8 {
state := c.srv.fsm.State() state := c.srv.fsm.State()
_, ns, err := state.NodeServices(nil, args.Node, entMeta) _, ns, err := state.NodeServices(nil, args.Node, entMeta)
if err != nil { if err != nil {
return fmt.Errorf("Node lookup failed: %v", err) return fmt.Errorf("Node lookup failed: %v", err)
} }
if err := vetRegisterWithACL(rule, args, ns); err != nil { if err := vetRegisterWithACL(authz, args, ns); err != nil {
return err return err
} }
} }
@ -171,10 +173,6 @@ func (c *Catalog) Register(args *structs.RegisterRequest, reply *struct{}) error
// Deregister is used to remove a service registration for a given node. // Deregister is used to remove a service registration for a given node.
func (c *Catalog) Deregister(args *structs.DeregisterRequest, reply *struct{}) error { func (c *Catalog) Deregister(args *structs.DeregisterRequest, reply *struct{}) error {
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, true); err != nil {
return err
}
if done, err := c.srv.forward("Catalog.Deregister", args, args, reply); done { if done, err := c.srv.forward("Catalog.Deregister", args, args, reply); done {
return err return err
} }
@ -186,13 +184,17 @@ func (c *Catalog) Deregister(args *structs.DeregisterRequest, reply *struct{}) e
} }
// Fetch the ACL token, if any. // Fetch the ACL token, if any.
rule, err := c.srv.ResolveToken(args.Token) authz, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil { if err != nil {
return err return err
} }
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, true); err != nil {
return err
}
// Check the complete deregister request against the given ACL policy. // Check the complete deregister request against the given ACL policy.
if rule != nil && c.srv.config.ACLEnforceVersion8 { if authz != nil && c.srv.config.ACLEnforceVersion8 {
state := c.srv.fsm.State() state := c.srv.fsm.State()
var ns *structs.NodeService var ns *structs.NodeService
@ -211,7 +213,7 @@ func (c *Catalog) Deregister(args *structs.DeregisterRequest, reply *struct{}) e
} }
} }
if err := vetDeregisterWithACL(rule, args, ns, nc); err != nil { if err := vetDeregisterWithACL(authz, args, ns, nc); err != nil {
return err return err
} }
@ -282,16 +284,21 @@ func (c *Catalog) ListNodes(args *structs.DCSpecificRequest, reply *structs.Inde
// ListServices is used to query the services in a DC // ListServices is used to query the services in a DC
func (c *Catalog) ListServices(args *structs.DCSpecificRequest, reply *structs.IndexedServices) error { func (c *Catalog) ListServices(args *structs.DCSpecificRequest, reply *structs.IndexedServices) error {
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
if done, err := c.srv.forward("Catalog.ListServices", args, args, reply); done { if done, err := c.srv.forward("Catalog.ListServices", args, args, reply); done {
return err return err
} }
(*reply).EnterpriseMeta = args.EnterpriseMeta (*reply).EnterpriseMeta = args.EnterpriseMeta
authz, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
return c.srv.blockingQuery( return c.srv.blockingQuery(
&args.QueryOptions, &args.QueryOptions,
&reply.QueryMeta, &reply.QueryMeta,
@ -308,17 +315,13 @@ func (c *Catalog) ListServices(args *structs.DCSpecificRequest, reply *structs.I
return err return err
} }
reply.Index, reply.Services = index, services reply.Index, reply.Services, reply.EnterpriseMeta = index, services, args.EnterpriseMeta
return c.srv.filterACL(args.Token, reply) return c.srv.filterACLWithAuthorizer(authz, reply)
}) })
} }
// ServiceNodes returns all the nodes registered as part of a service // ServiceNodes returns all the nodes registered as part of a service
func (c *Catalog) ServiceNodes(args *structs.ServiceSpecificRequest, reply *structs.IndexedServiceNodes) error { func (c *Catalog) ServiceNodes(args *structs.ServiceSpecificRequest, reply *structs.IndexedServiceNodes) error {
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
if done, err := c.srv.forward("Catalog.ServiceNodes", args, args, reply); done { if done, err := c.srv.forward("Catalog.ServiceNodes", args, args, reply); done {
return err return err
} }
@ -360,17 +363,19 @@ func (c *Catalog) ServiceNodes(args *structs.ServiceSpecificRequest, reply *stru
} }
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.FillAuthzContext(&authzContext) authz, err := c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
// If we're doing a connect query, we need read access to the service
// we're trying to find proxies for, so check that.
if args.Connect {
// Fetch the ACL token, if any.
rule, err := c.srv.ResolveToken(args.Token)
if err != nil { if err != nil {
return err return err
} }
if rule != nil && rule.ServiceRead(args.ServiceName, &authzContext) != acl.Allow { if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
// If we're doing a connect query, we need read access to the service
// we're trying to find proxies for, so check that.
if args.Connect {
if authz != nil && authz.ServiceRead(args.ServiceName, &authzContext) != acl.Allow {
// Just return nil, which will return an empty response (tested) // Just return nil, which will return an empty response (tested)
return nil return nil
} }
@ -455,10 +460,6 @@ func (c *Catalog) ServiceNodes(args *structs.ServiceSpecificRequest, reply *stru
// NodeServices returns all the services registered as part of a node // NodeServices returns all the services registered as part of a node
func (c *Catalog) NodeServices(args *structs.NodeSpecificRequest, reply *structs.IndexedNodeServices) error { func (c *Catalog) NodeServices(args *structs.NodeSpecificRequest, reply *structs.IndexedNodeServices) error {
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
if done, err := c.srv.forward("Catalog.NodeServices", args, args, reply); done { if done, err := c.srv.forward("Catalog.NodeServices", args, args, reply); done {
return err return err
} }
@ -474,6 +475,15 @@ func (c *Catalog) NodeServices(args *structs.NodeSpecificRequest, reply *structs
return err return err
} }
_, err = c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
return c.srv.blockingQuery( return c.srv.blockingQuery(
&args.QueryOptions, &args.QueryOptions,
&reply.QueryMeta, &reply.QueryMeta,
@ -501,10 +511,6 @@ func (c *Catalog) NodeServices(args *structs.NodeSpecificRequest, reply *structs
} }
func (c *Catalog) NodeServiceList(args *structs.NodeSpecificRequest, reply *structs.IndexedNodeServiceList) error { func (c *Catalog) NodeServiceList(args *structs.NodeSpecificRequest, reply *structs.IndexedNodeServiceList) error {
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
if done, err := c.srv.forward("Catalog.NodeServiceList", args, args, reply); done { if done, err := c.srv.forward("Catalog.NodeServiceList", args, args, reply); done {
return err return err
} }
@ -520,6 +526,15 @@ func (c *Catalog) NodeServiceList(args *structs.NodeSpecificRequest, reply *stru
return err return err
} }
_, err = c.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := c.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
return c.srv.blockingQuery( return c.srv.blockingQuery(
&args.QueryOptions, &args.QueryOptions,
&reply.QueryMeta, &reply.QueryMeta,

View File

@ -20,10 +20,6 @@ type Health struct {
// ChecksInState is used to get all the checks in a given state // ChecksInState is used to get all the checks in a given state
func (h *Health) ChecksInState(args *structs.ChecksInStateRequest, func (h *Health) ChecksInState(args *structs.ChecksInStateRequest,
reply *structs.IndexedHealthChecks) error { reply *structs.IndexedHealthChecks) error {
if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
if done, err := h.srv.forward("Health.ChecksInState", args, args, reply); done { if done, err := h.srv.forward("Health.ChecksInState", args, args, reply); done {
return err return err
} }
@ -33,6 +29,15 @@ func (h *Health) ChecksInState(args *structs.ChecksInStateRequest,
return err return err
} }
_, err = h.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
return h.srv.blockingQuery( return h.srv.blockingQuery(
&args.QueryOptions, &args.QueryOptions,
&reply.QueryMeta, &reply.QueryMeta,
@ -66,10 +71,6 @@ func (h *Health) ChecksInState(args *structs.ChecksInStateRequest,
// NodeChecks is used to get all the checks for a node // NodeChecks is used to get all the checks for a node
func (h *Health) NodeChecks(args *structs.NodeSpecificRequest, func (h *Health) NodeChecks(args *structs.NodeSpecificRequest,
reply *structs.IndexedHealthChecks) error { reply *structs.IndexedHealthChecks) error {
if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
if done, err := h.srv.forward("Health.NodeChecks", args, args, reply); done { if done, err := h.srv.forward("Health.NodeChecks", args, args, reply); done {
return err return err
} }
@ -79,6 +80,15 @@ func (h *Health) NodeChecks(args *structs.NodeSpecificRequest,
return err return err
} }
_, err = h.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
return h.srv.blockingQuery( return h.srv.blockingQuery(
&args.QueryOptions, &args.QueryOptions,
&reply.QueryMeta, &reply.QueryMeta,
@ -105,10 +115,6 @@ func (h *Health) NodeChecks(args *structs.NodeSpecificRequest,
func (h *Health) ServiceChecks(args *structs.ServiceSpecificRequest, func (h *Health) ServiceChecks(args *structs.ServiceSpecificRequest,
reply *structs.IndexedHealthChecks) error { reply *structs.IndexedHealthChecks) error {
if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
// Reject if tag filtering is on // Reject if tag filtering is on
if args.TagFilter { if args.TagFilter {
return fmt.Errorf("Tag filtering is not supported") return fmt.Errorf("Tag filtering is not supported")
@ -124,6 +130,15 @@ func (h *Health) ServiceChecks(args *structs.ServiceSpecificRequest,
return err return err
} }
_, err = h.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
return h.srv.blockingQuery( return h.srv.blockingQuery(
&args.QueryOptions, &args.QueryOptions,
&reply.QueryMeta, &reply.QueryMeta,
@ -156,10 +171,6 @@ func (h *Health) ServiceChecks(args *structs.ServiceSpecificRequest,
// ServiceNodes returns all the nodes registered as part of a service including health info // ServiceNodes returns all the nodes registered as part of a service including health info
func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *structs.IndexedCheckServiceNodes) error { func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *structs.IndexedCheckServiceNodes) error {
if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
if done, err := h.srv.forward("Health.ServiceNodes", args, args, reply); done { if done, err := h.srv.forward("Health.ServiceNodes", args, args, reply); done {
return err return err
} }
@ -180,16 +191,20 @@ func (h *Health) ServiceNodes(args *structs.ServiceSpecificRequest, reply *struc
f = h.serviceNodesDefault f = h.serviceNodesDefault
} }
// If we're doing a connect query, we need read access to the service var authzContext acl.AuthorizerContext
// we're trying to find proxies for, so check that. authz, err := h.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if args.Connect {
// Fetch the ACL token, if any.
rule, err := h.srv.ResolveToken(args.Token)
if err != nil { if err != nil {
return err return err
} }
if rule != nil && rule.ServiceRead(args.ServiceName, nil) != acl.Allow { if err := h.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err
}
// If we're doing a connect query, we need read access to the service
// we're trying to find proxies for, so check that.
if args.Connect {
if authz != nil && authz.ServiceRead(args.ServiceName, &authzContext) != acl.Allow {
// Just return nil, which will return an empty response (tested) // Just return nil, which will return an empty response (tested)
return nil return nil
} }

View File

@ -21,20 +21,20 @@ type KVS struct {
// preApply does all the verification of a KVS update that is performed BEFORE // preApply does all the verification of a KVS update that is performed BEFORE
// we submit as a Raft log entry. This includes enforcing the lock delay which // we submit as a Raft log entry. This includes enforcing the lock delay which
// must only be done on the leader. // must only be done on the leader.
func kvsPreApply(srv *Server, rule acl.Authorizer, op api.KVOp, dirEnt *structs.DirEntry) (bool, error) { func kvsPreApply(srv *Server, authz acl.Authorizer, op api.KVOp, dirEnt *structs.DirEntry) (bool, error) {
// Verify the entry. // Verify the entry.
if dirEnt.Key == "" && op != api.KVDeleteTree { if dirEnt.Key == "" && op != api.KVDeleteTree {
return false, fmt.Errorf("Must provide key") return false, fmt.Errorf("Must provide key")
} }
// Apply the ACL policy if any. // Apply the ACL policy if any.
if rule != nil { if authz != nil {
switch op { switch op {
case api.KVDeleteTree: case api.KVDeleteTree:
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
dirEnt.FillAuthzContext(&authzContext) dirEnt.FillAuthzContext(&authzContext)
if rule.KeyWritePrefix(dirEnt.Key, &authzContext) != acl.Allow { if authz.KeyWritePrefix(dirEnt.Key, &authzContext) != acl.Allow {
return false, acl.ErrPermissionDenied return false, acl.ErrPermissionDenied
} }
@ -48,7 +48,7 @@ func kvsPreApply(srv *Server, rule acl.Authorizer, op api.KVOp, dirEnt *structs.
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
dirEnt.FillAuthzContext(&authzContext) dirEnt.FillAuthzContext(&authzContext)
if rule.KeyRead(dirEnt.Key, &authzContext) != acl.Allow { if authz.KeyRead(dirEnt.Key, &authzContext) != acl.Allow {
return false, acl.ErrPermissionDenied return false, acl.ErrPermissionDenied
} }
@ -56,7 +56,7 @@ func kvsPreApply(srv *Server, rule acl.Authorizer, op api.KVOp, dirEnt *structs.
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
dirEnt.FillAuthzContext(&authzContext) dirEnt.FillAuthzContext(&authzContext)
if rule.KeyWrite(dirEnt.Key, &authzContext) != acl.Allow { if authz.KeyWrite(dirEnt.Key, &authzContext) != acl.Allow {
return false, acl.ErrPermissionDenied return false, acl.ErrPermissionDenied
} }
} }
@ -88,16 +88,17 @@ func (k *KVS) Apply(args *structs.KVSRequest, reply *bool) error {
} }
defer metrics.MeasureSince([]string{"kvs", "apply"}, time.Now()) defer metrics.MeasureSince([]string{"kvs", "apply"}, time.Now())
// Perform the pre-apply checks.
authz, err := k.srv.ResolveTokenAndDefaultMeta(args.Token, &args.DirEnt.EnterpriseMeta, nil)
if err != nil {
return err
}
if err := k.srv.validateEnterpriseRequest(&args.DirEnt.EnterpriseMeta, true); err != nil { if err := k.srv.validateEnterpriseRequest(&args.DirEnt.EnterpriseMeta, true); err != nil {
return err return err
} }
// Perform the pre-apply checks. ok, err := kvsPreApply(k.srv, authz, args.Op, &args.DirEnt)
rule, err := k.srv.ResolveToken(args.Token)
if err != nil {
return err
}
ok, err := kvsPreApply(k.srv, rule, args.Op, &args.DirEnt)
if err != nil { if err != nil {
return err return err
} }
@ -128,15 +129,14 @@ func (k *KVS) Get(args *structs.KeyRequest, reply *structs.IndexedDirEntries) er
if done, err := k.srv.forward("KVS.Get", args, args, reply); done { if done, err := k.srv.forward("KVS.Get", args, args, reply); done {
return err return err
} }
if err := k.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
var authzContext acl.AuthorizerContext
authz, err := k.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil {
return err return err
} }
var entCtx acl.AuthorizerContext if err := k.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
args.FillAuthzContext(&entCtx)
rule, err := k.srv.ResolveToken(args.Token)
if err != nil {
return err return err
} }
@ -148,7 +148,7 @@ func (k *KVS) Get(args *structs.KeyRequest, reply *structs.IndexedDirEntries) er
if err != nil { if err != nil {
return err return err
} }
if rule != nil && rule.KeyRead(args.Key, &entCtx) != acl.Allow { if authz != nil && authz.KeyRead(args.Key, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -174,18 +174,18 @@ func (k *KVS) List(args *structs.KeyRequest, reply *structs.IndexedDirEntries) e
if done, err := k.srv.forward("KVS.List", args, args, reply); done { if done, err := k.srv.forward("KVS.List", args, args, reply); done {
return err return err
} }
var authzContext acl.AuthorizerContext
authz, err := k.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil {
return err
}
if err := k.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil { if err := k.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err return err
} }
var entCtx acl.AuthorizerContext if authz != nil && k.srv.config.ACLEnableKeyListPolicy && authz.KeyList(args.Key, &authzContext) != acl.Allow {
args.FillAuthzContext(&entCtx)
rule, err := k.srv.ResolveToken(args.Token)
if err != nil {
return err
}
if rule != nil && k.srv.config.ACLEnableKeyListPolicy && rule.KeyList(args.Key, &entCtx) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -197,8 +197,8 @@ func (k *KVS) List(args *structs.KeyRequest, reply *structs.IndexedDirEntries) e
if err != nil { if err != nil {
return err return err
} }
if rule != nil { if authz != nil {
ent = FilterDirEnt(rule, ent) ent = FilterDirEnt(authz, ent)
} }
if len(ent) == 0 { if len(ent) == 0 {
@ -226,18 +226,18 @@ func (k *KVS) ListKeys(args *structs.KeyListRequest, reply *structs.IndexedKeyLi
if done, err := k.srv.forward("KVS.ListKeys", args, args, reply); done { if done, err := k.srv.forward("KVS.ListKeys", args, args, reply); done {
return err return err
} }
var authzContext acl.AuthorizerContext
authz, err := k.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil {
return err
}
if err := k.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil { if err := k.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
return err return err
} }
var entCtx acl.AuthorizerContext if authz != nil && k.srv.config.ACLEnableKeyListPolicy && authz.KeyList(args.Prefix, &authzContext) != acl.Allow {
args.FillAuthzContext(&entCtx)
rule, err := k.srv.ResolveToken(args.Token)
if err != nil {
return err
}
if rule != nil && k.srv.config.ACLEnableKeyListPolicy && rule.KeyList(args.Prefix, &entCtx) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -258,8 +258,8 @@ func (k *KVS) ListKeys(args *structs.KeyListRequest, reply *structs.IndexedKeyLi
reply.Index = index reply.Index = index
} }
if rule != nil { if authz != nil {
entries = FilterDirEnt(rule, entries) entries = FilterDirEnt(authz, entries)
} }
// Collect the keys from the filtered entries // Collect the keys from the filtered entries

View File

@ -25,10 +25,6 @@ func (s *Session) Apply(args *structs.SessionRequest, reply *string) error {
} }
defer metrics.MeasureSince([]string{"session", "apply"}, time.Now()) defer metrics.MeasureSince([]string{"session", "apply"}, time.Now())
if err := s.srv.validateEnterpriseRequest(&args.Session.EnterpriseMeta, true); err != nil {
return err
}
// Verify the args // Verify the args
if args.Session.ID == "" && args.Op == structs.SessionDestroy { if args.Session.ID == "" && args.Op == structs.SessionDestroy {
return fmt.Errorf("Must provide ID") return fmt.Errorf("Must provide ID")
@ -37,20 +33,21 @@ func (s *Session) Apply(args *structs.SessionRequest, reply *string) error {
return fmt.Errorf("Must provide Node") return fmt.Errorf("Must provide Node")
} }
// TODO (namespaces) (acls) infer entmeta if not provided.
// The entMeta to populate is the one in the Session struct, not SessionRequest // The entMeta to populate is the one in the Session struct, not SessionRequest
// This is because the Session is what is passed to downstream functions like raftApply // This is because the Session is what is passed to downstream functions like raftApply
var entCtx acl.AuthorizerContext var authzContext acl.AuthorizerContext
args.Session.FillAuthzContext(&entCtx)
// Fetch the ACL token, if any, and apply the policy. // Fetch the ACL token, if any, and apply the policy.
rule, err := s.srv.ResolveToken(args.Token) authz, err := s.srv.ResolveTokenAndDefaultMeta(args.Token, &args.Session.EnterpriseMeta, &authzContext)
if err != nil { if err != nil {
return err return err
} }
if rule != nil && s.srv.config.ACLEnforceVersion8 { if err := s.srv.validateEnterpriseRequest(&args.Session.EnterpriseMeta, true); err != nil {
return err
}
if authz != nil && s.srv.config.ACLEnforceVersion8 {
switch args.Op { switch args.Op {
case structs.SessionDestroy: case structs.SessionDestroy:
state := s.srv.fsm.State() state := s.srv.fsm.State()
@ -61,12 +58,12 @@ func (s *Session) Apply(args *structs.SessionRequest, reply *string) error {
if existing == nil { if existing == nil {
return fmt.Errorf("Unknown session %q", args.Session.ID) return fmt.Errorf("Unknown session %q", args.Session.ID)
} }
if rule.SessionWrite(existing.Node, &entCtx) != acl.Allow { if authz.SessionWrite(existing.Node, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
case structs.SessionCreate: case structs.SessionCreate:
if rule.SessionWrite(args.Session.Node, &entCtx) != acl.Allow { if authz.SessionWrite(args.Session.Node, &authzContext) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -157,16 +154,13 @@ func (s *Session) Get(args *structs.SessionSpecificRequest,
return err return err
} }
if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil { var authzContext acl.AuthorizerContext
authz, err := s.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil {
return err return err
} }
// TODO (namespaces) TODO (acls) infer args.entmeta if not provided if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
var entCtx acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := s.srv.ResolveToken(args.Token)
if err != nil {
return err return err
} }
@ -185,7 +179,7 @@ func (s *Session) Get(args *structs.SessionSpecificRequest,
} else { } else {
reply.Sessions = nil reply.Sessions = nil
} }
if err := s.srv.filterACLWithAuthorizer(rule, reply); err != nil { if err := s.srv.filterACLWithAuthorizer(authz, reply); err != nil {
return err return err
} }
return nil return nil
@ -199,16 +193,13 @@ func (s *Session) List(args *structs.SessionSpecificRequest,
return err return err
} }
if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil { var authzContext acl.AuthorizerContext
authz, err := s.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil {
return err return err
} }
// TODO (namespaces) TODO (acls) infer args.entmeta if not provided if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
var entCtx acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := s.srv.ResolveToken(args.Token)
if err != nil {
return err return err
} }
@ -222,7 +213,7 @@ func (s *Session) List(args *structs.SessionSpecificRequest,
} }
reply.Index, reply.Sessions = index, sessions reply.Index, reply.Sessions = index, sessions
if err := s.srv.filterACLWithAuthorizer(rule, reply); err != nil { if err := s.srv.filterACLWithAuthorizer(authz, reply); err != nil {
return err return err
} }
return nil return nil
@ -236,16 +227,13 @@ func (s *Session) NodeSessions(args *structs.NodeSpecificRequest,
return err return err
} }
if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil { var authzContext acl.AuthorizerContext
authz, err := s.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil {
return err return err
} }
// TODO (namespaces) TODO (acls) infer args.entmeta if not provided if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, false); err != nil {
var entCtx acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := s.srv.ResolveToken(args.Token)
if err != nil {
return err return err
} }
@ -259,7 +247,7 @@ func (s *Session) NodeSessions(args *structs.NodeSpecificRequest,
} }
reply.Index, reply.Sessions = index, sessions reply.Index, reply.Sessions = index, sessions
if err := s.srv.filterACLWithAuthorizer(rule, reply); err != nil { if err := s.srv.filterACLWithAuthorizer(authz, reply); err != nil {
return err return err
} }
return nil return nil
@ -274,6 +262,13 @@ func (s *Session) Renew(args *structs.SessionSpecificRequest,
} }
defer metrics.MeasureSince([]string{"session", "renew"}, time.Now()) defer metrics.MeasureSince([]string{"session", "renew"}, time.Now())
// Fetch the ACL token, if any, and apply the policy.
var authzContext acl.AuthorizerContext
authz, err := s.srv.ResolveTokenAndDefaultMeta(args.Token, &args.EnterpriseMeta, &authzContext)
if err != nil {
return err
}
if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, true); err != nil { if err := s.srv.validateEnterpriseRequest(&args.EnterpriseMeta, true); err != nil {
return err return err
} }
@ -290,20 +285,9 @@ func (s *Session) Renew(args *structs.SessionSpecificRequest,
return nil return nil
} }
// TODO (namespaces) (freddy):infer args.entmeta if not provided if authz != nil && s.srv.config.ACLEnforceVersion8 && authz.SessionWrite(session.Node, &authzContext) != acl.Allow {
// Fetch the ACL token, if any, and apply the policy.
var entCtx acl.AuthorizerContext
args.FillAuthzContext(&entCtx)
rule, err := s.srv.ResolveToken(args.Token)
if err != nil {
return err
}
if rule != nil && s.srv.config.ACLEnforceVersion8 {
if rule.SessionWrite(session.Node, &entCtx) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
}
// Reset the session TTL timer. // Reset the session TTL timer.
reply.Sessions = structs.Sessions{session} reply.Sessions = structs.Sessions{session}

View File

@ -21,6 +21,10 @@ func (m *EnterpriseMeta) addToHash(_ hash.Hash, _ bool) {
// do nothing // do nothing
} }
func (m *EnterpriseMeta) Merge(_ *EnterpriseMeta) {
// do nothing
}
func (m *EnterpriseMeta) Matches(_ *EnterpriseMeta) bool { func (m *EnterpriseMeta) Matches(_ *EnterpriseMeta) bool {
return true return true
} }