Add managed service provider token (#7218)

Stubs for enterprise-only ACL token to be used by managed service providers.
pull/7230/head
Freddy 2020-02-04 13:58:56 -07:00 committed by GitHub
parent f6ec8ed92b
commit cb77fc6d01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 115 additions and 22 deletions

View File

@ -16,8 +16,6 @@ var (
// manageAll is a singleton policy which allows all // manageAll is a singleton policy which allows all
// actions, including management // actions, including management
// TODO (acls) - Do we need to keep this around? Our config parsing doesn't allow
// specifying a default "manage" policy so I believe nothing will every use this.
manageAll Authorizer = &staticAuthorizer{ manageAll Authorizer = &staticAuthorizer{
allowManage: true, allowManage: true,
defaultAllow: true, defaultAllow: true,

View File

@ -400,6 +400,7 @@ func (a *Agent) Start() error {
// load the tokens - this requires the logger to be setup // load the tokens - this requires the logger to be setup
// which is why we can't do this in New // which is why we can't do this in New
a.loadTokens(a.config) a.loadTokens(a.config)
a.loadEnterpriseTokens(a.config)
// create the local state // create the local state
a.State = local.NewState(LocalConfig(c), a.logger, a.tokens) a.State = local.NewState(LocalConfig(c), a.logger, a.tokens)
@ -3991,6 +3992,7 @@ func (a *Agent) ReloadConfig(newCfg *config.RuntimeConfig) error {
// to ensure the correct tokens are available for attaching to // to ensure the correct tokens are available for attaching to
// the checks and service registrations. // the checks and service registrations.
a.loadTokens(newCfg) a.loadTokens(newCfg)
a.loadEnterpriseTokens(newCfg)
if err := a.tlsConfigurator.Update(newCfg.ToTLSUtilConfig()); err != nil { if err := a.tlsConfigurator.Update(newCfg.ToTLSUtilConfig()); err != nil {
return fmt.Errorf("Failed reloading tls configuration: %s", err) return fmt.Errorf("Failed reloading tls configuration: %s", err)

View File

@ -3,6 +3,7 @@
package agent package agent
import ( import (
"github.com/hashicorp/consul/agent/config"
"github.com/hashicorp/consul/agent/consul" "github.com/hashicorp/consul/agent/consul"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
@ -16,3 +17,6 @@ func fillHealthCheckEnterpriseMeta(_ *api.HealthCheck, _ *structs.EnterpriseMeta
func (a *Agent) initEnterprise(consulCfg *consul.Config) { func (a *Agent) initEnterprise(consulCfg *consul.Config) {
} }
func (a *Agent) loadEnterpriseTokens(conf *config.RuntimeConfig) {
}

View File

@ -1197,12 +1197,6 @@ func (b *Builder) Validate(rt RuntimeConfig) error {
} }
} }
if rt.AutoEncryptAllowTLS {
if !rt.VerifyIncoming && !rt.VerifyIncomingRPC {
b.warn("if auto_encrypt.allow_tls is turned on, either verify_incoming or verify_incoming_rpc should be enabled. It is necessary to turn it off during a migration to TLS, but it should definitely be turned on afterwards.")
}
}
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// warnings // warnings
// //
@ -1223,6 +1217,12 @@ func (b *Builder) Validate(rt RuntimeConfig) error {
b.warn("bootstrap_expect > 0: expecting %d servers", rt.BootstrapExpect) b.warn("bootstrap_expect > 0: expecting %d servers", rt.BootstrapExpect)
} }
if rt.AutoEncryptAllowTLS {
if !rt.VerifyIncoming && !rt.VerifyIncomingRPC {
b.warn("if auto_encrypt.allow_tls is turned on, either verify_incoming or verify_incoming_rpc should be enabled. It is necessary to turn it off during a migration to TLS, but it should definitely be turned on afterwards.")
}
}
return nil return nil
} }

View File

@ -95,6 +95,7 @@ func Parse(data string, format string) (c Config, err error) {
"services.proxy.upstreams", "services.proxy.upstreams",
"service.proxy.expose.paths", "service.proxy.expose.paths",
"services.proxy.expose.paths", "services.proxy.expose.paths",
"acl.tokens.managed_service_provider",
// Need all the service(s) exceptions also for nested sidecar service. // Need all the service(s) exceptions also for nested sidecar service.
"service.connect.sidecar_service.checks", "service.connect.sidecar_service.checks",
@ -712,6 +713,12 @@ type Tokens struct {
AgentMaster *string `json:"agent_master,omitempty" hcl:"agent_master" mapstructure:"agent_master"` AgentMaster *string `json:"agent_master,omitempty" hcl:"agent_master" mapstructure:"agent_master"`
Default *string `json:"default,omitempty" hcl:"default" mapstructure:"default"` Default *string `json:"default,omitempty" hcl:"default" mapstructure:"default"`
Agent *string `json:"agent,omitempty" hcl:"agent" mapstructure:"agent"` Agent *string `json:"agent,omitempty" hcl:"agent" mapstructure:"agent"`
ManagedServiceProvider []ServiceProviderToken `json:"managed_service_provider,omitempty" hcl:"managed_service_provider" mapstructure:"managed_service_provider"`
}
type ServiceProviderToken struct {
AccessorID *string `json:"accessor_id,omitempty" hcl:"accessor_id" mapstructure:"accessor_id"`
SecretID *string `json:"secret_id,omitempty" hcl:"secret_id" mapstructure:"secret_id"`
} }
type ConfigEntries struct { type ConfigEntries struct {

View File

@ -3694,7 +3694,17 @@ func TestFullConfig(t *testing.T) {
"agent_master" : "64fd0e08", "agent_master" : "64fd0e08",
"replication" : "5795983a", "replication" : "5795983a",
"agent" : "bed2377c", "agent" : "bed2377c",
"default" : "418fdff1" "default" : "418fdff1",
"managed_service_provider": [
{
"accessor_id": "first",
"secret_id": "fb0cee1f-2847-467c-99db-a897cff5fd4d"
},
{
"accessor_id": "second",
"secret_id": "1046c8da-e166-4667-897a-aefb343db9db"
}
]
} }
}, },
"addresses": { "addresses": {
@ -4302,7 +4312,17 @@ func TestFullConfig(t *testing.T) {
agent_master = "64fd0e08", agent_master = "64fd0e08",
replication = "5795983a", replication = "5795983a",
agent = "bed2377c", agent = "bed2377c",
default = "418fdff1" default = "418fdff1",
managed_service_provider = [
{
accessor_id = "first",
secret_id = "fb0cee1f-2847-467c-99db-a897cff5fd4d"
},
{
accessor_id = "second",
secret_id = "1046c8da-e166-4667-897a-aefb343db9db"
}
]
} }
} }
addresses = { addresses = {

View File

@ -211,10 +211,14 @@ func (s *Server) ResolveRoleFromID(roleID string) (bool, *structs.ACLRole, error
} }
func (s *Server) ResolveToken(token string) (acl.Authorizer, error) { func (s *Server) ResolveToken(token string) (acl.Authorizer, error) {
return s.acls.ResolveToken(token) _, authz, err := s.ResolveTokenToIdentityAndAuthorizer(token)
return authz, err
} }
func (s *Server) ResolveTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer, error) { func (s *Server) ResolveTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer, error) {
if id, authz := s.ResolveEntTokenToIdentityAndAuthorizer(token); id != nil && authz != nil {
return id, authz, nil
}
return s.acls.ResolveTokenToIdentityAndAuthorizer(token) return s.acls.ResolveTokenToIdentityAndAuthorizer(token)
} }

View File

@ -0,0 +1,18 @@
// +build !consulent
package consul
import (
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs"
)
// Consul-enterprise only
func (s *Server) ResolveEntTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer) {
return nil, nil
}
// Consul-enterprise only
func (s *Server) validateEnterpriseToken(identity structs.ACLIdentity) error {
return nil
}

View File

@ -158,10 +158,13 @@ func (m *Internal) KeyringOperation(
reply *structs.KeyringResponses) error { reply *structs.KeyringResponses) error {
// Check ACLs // Check ACLs
rule, err := m.srv.ResolveToken(args.Token) identity, rule, err := m.srv.ResolveTokenToIdentityAndAuthorizer(args.Token)
if err != nil { if err != nil {
return err return err
} }
if err := m.srv.validateEnterpriseToken(identity); err != nil {
return err
}
if rule != nil { if rule != nil {
switch args.Operation { switch args.Operation {
case structs.KeyringList: case structs.KeyringList:

View File

@ -15,10 +15,13 @@ func (op *Operator) AutopilotGetConfiguration(args *structs.DCSpecificRequest, r
} }
// This action requires operator read access. // This action requires operator read access.
rule, err := op.srv.ResolveToken(args.Token) identity, rule, err := op.srv.ResolveTokenToIdentityAndAuthorizer(args.Token)
if err != nil { if err != nil {
return err return err
} }
if err := op.srv.validateEnterpriseToken(identity); err != nil {
return err
}
if rule != nil && rule.OperatorRead(nil) != acl.Allow { if rule != nil && rule.OperatorRead(nil) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -44,10 +47,13 @@ func (op *Operator) AutopilotSetConfiguration(args *structs.AutopilotSetConfigRe
} }
// This action requires operator write access. // This action requires operator write access.
rule, err := op.srv.ResolveToken(args.Token) identity, rule, err := op.srv.ResolveTokenToIdentityAndAuthorizer(args.Token)
if err != nil { if err != nil {
return err return err
} }
if err := op.srv.validateEnterpriseToken(identity); err != nil {
return err
}
if rule != nil && rule.OperatorWrite(nil) != acl.Allow { if rule != nil && rule.OperatorWrite(nil) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -80,10 +86,13 @@ func (op *Operator) ServerHealth(args *structs.DCSpecificRequest, reply *autopil
} }
// This action requires operator read access. // This action requires operator read access.
rule, err := op.srv.ResolveToken(args.Token) identity, rule, err := op.srv.ResolveTokenToIdentityAndAuthorizer(args.Token)
if err != nil { if err != nil {
return err return err
} }
if err := op.srv.validateEnterpriseToken(identity); err != nil {
return err
}
if rule != nil && rule.OperatorRead(nil) != acl.Allow { if rule != nil && rule.OperatorRead(nil) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }

View File

@ -80,10 +80,13 @@ func (op *Operator) RaftRemovePeerByAddress(args *structs.RaftRemovePeerRequest,
// This is a super dangerous operation that requires operator write // This is a super dangerous operation that requires operator write
// access. // access.
rule, err := op.srv.ResolveToken(args.Token) identity, rule, err := op.srv.ResolveTokenToIdentityAndAuthorizer(args.Token)
if err != nil { if err != nil {
return err return err
} }
if err := op.srv.validateEnterpriseToken(identity); err != nil {
return err
}
if rule != nil && rule.OperatorWrite(nil) != acl.Allow { if rule != nil && rule.OperatorWrite(nil) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }
@ -149,10 +152,13 @@ func (op *Operator) RaftRemovePeerByID(args *structs.RaftRemovePeerRequest, repl
// This is a super dangerous operation that requires operator write // This is a super dangerous operation that requires operator write
// access. // access.
rule, err := op.srv.ResolveToken(args.Token) identity, rule, err := op.srv.ResolveTokenToIdentityAndAuthorizer(args.Token)
if err != nil { if err != nil {
return err return err
} }
if err := op.srv.validateEnterpriseToken(identity); err != nil {
return err
}
if rule != nil && rule.OperatorWrite(nil) != acl.Allow { if rule != nil && rule.OperatorWrite(nil) != acl.Allow {
return acl.ErrPermissionDenied return acl.ErrPermissionDenied
} }

View File

@ -51,6 +51,9 @@ type Store struct {
// replicationTokenSource indicates where this token originated from // replicationTokenSource indicates where this token originated from
replicationTokenSource TokenSource replicationTokenSource TokenSource
// enterpriseTokens contains tokens only used in consul-enterprise
enterpriseTokens
} }
// UpdateUserToken replaces the current user token in the store. // UpdateUserToken replaces the current user token in the store.

7
agent/token/store_oss.go Normal file
View File

@ -0,0 +1,7 @@
// +build !consulent
package token
// Stub for enterpriseTokens
type enterpriseTokens struct {
}

View File

@ -663,6 +663,18 @@ default will automatically work with some tooling.
Connect replication, for which the token will require both operator Connect replication, for which the token will require both operator
"write" and intention "read" permissions for replicating CA and Intention data. "write" and intention "read" permissions for replicating CA and Intention data.
* <a name="acl_tokens_managed_service_provider"></a><a href="#acl_tokens_managed_service_provider">`managed_service_provider`</a> -
**(Enterprise Only)** An array of ACL tokens used by Consul managed service providers for cluster operations.
```javascript
"managed_service_provider": [
{
"accessor_id": "ed22003b-0832-4e48-ac65-31de64e5c2ff",
"secret_id": "cb6be010-bba8-4f30-a9ed-d347128dde17"
}
]
```
* <a name="acl_datacenter"></a><a href="#acl_datacenter">`acl_datacenter`</a> - **This field is * <a name="acl_datacenter"></a><a href="#acl_datacenter">`acl_datacenter`</a> - **This field is
deprecated in Consul 1.4.0. See the [`primary_datacenter`](#primary_datacenter) field instead.** deprecated in Consul 1.4.0. See the [`primary_datacenter`](#primary_datacenter) field instead.**