1package consul
2
3import (
4	"fmt"
5	"sort"
6	"sync"
7	"time"
8
9	metrics "github.com/armon/go-metrics"
10	"github.com/hashicorp/consul/acl"
11	"github.com/hashicorp/consul/agent/structs"
12	"github.com/hashicorp/consul/logging"
13	"github.com/hashicorp/go-hclog"
14	"golang.org/x/sync/singleflight"
15	"golang.org/x/time/rate"
16)
17
18// These must be kept in sync with the constants in command/agent/acl.go.
19const (
20	// anonymousToken is the token ID we re-write to if there is no token ID
21	// provided.
22	anonymousToken = "anonymous"
23
24	// redactedToken is shown in structures with embedded tokens when they
25	// are not allowed to be displayed.
26	redactedToken = "<hidden>"
27
28	// aclUpgradeBatchSize controls how many tokens we look at during each round of upgrading. Individual raft logs
29	// will be further capped using the aclBatchUpsertSize. This limit just prevents us from creating a single slice
30	// with all tokens in it.
31	aclUpgradeBatchSize = 128
32
33	// aclUpgradeRateLimit is the number of batch upgrade requests per second allowed.
34	aclUpgradeRateLimit rate.Limit = 1.0
35
36	// aclTokenReapingRateLimit is the number of batch token reaping requests per second allowed.
37	aclTokenReapingRateLimit rate.Limit = 1.0
38
39	// aclTokenReapingBurst is the number of batch token reaping requests per second
40	// that can burst after a period of idleness.
41	aclTokenReapingBurst = 5
42
43	// aclBatchDeleteSize is the number of deletions to send in a single batch operation. 4096 should produce a batch that is <150KB
44	// in size but should be sufficiently large to handle 1 replication round in a single batch
45	aclBatchDeleteSize = 4096
46
47	// aclBatchUpsertSize is the target size in bytes we want to submit for a batch upsert request. We estimate the size at runtime
48	// due to the data being more variable in its size.
49	aclBatchUpsertSize = 256 * 1024
50
51	// DEPRECATED (ACL-Legacy-Compat) aclModeCheck* are all only for legacy usage
52	// aclModeCheckMinInterval is the minimum amount of time between checking if the
53	// agent should be using the new or legacy ACL system. All the places it is
54	// currently used will backoff as it detects that it is remaining in legacy mode.
55	// However the initial min value is kept small so that new cluster creation
56	// can enter into new ACL mode quickly.
57	aclModeCheckMinInterval = 50 * time.Millisecond
58
59	// aclModeCheckMaxInterval controls the maximum interval for how often the agent
60	// checks if it should be using the new or legacy ACL system.
61	aclModeCheckMaxInterval = 30 * time.Second
62
63	// Maximum number of re-resolution requests to be made if the token is modified between
64	// resolving the token and resolving its policies that would remove one of its policies.
65	tokenPolicyResolutionMaxRetries = 5
66
67	// Maximum number of re-resolution requests to be made if the token is modified between
68	// resolving the token and resolving its roles that would remove one of its roles.
69	tokenRoleResolutionMaxRetries = 5
70)
71
72// missingIdentity is used to return some identity in the event that the real identity cannot be ascertained
73type missingIdentity struct {
74	reason string
75	token  string
76}
77
78func (id *missingIdentity) ID() string {
79	return id.reason
80}
81
82func (id *missingIdentity) SecretToken() string {
83	return id.token
84}
85
86func (id *missingIdentity) PolicyIDs() []string {
87	return nil
88}
89
90func (id *missingIdentity) RoleIDs() []string {
91	return nil
92}
93
94func (id *missingIdentity) EmbeddedPolicy() *structs.ACLPolicy {
95	return nil
96}
97
98func (id *missingIdentity) ServiceIdentityList() []*structs.ACLServiceIdentity {
99	return nil
100}
101
102func (id *missingIdentity) IsExpired(asOf time.Time) bool {
103	return false
104}
105
106func (id *missingIdentity) EnterpriseMetadata() *structs.EnterpriseMeta {
107	return structs.DefaultEnterpriseMeta()
108}
109
110func minTTL(a time.Duration, b time.Duration) time.Duration {
111	if a < b {
112		return a
113	}
114	return b
115}
116
117type ACLRemoteError struct {
118	Err error
119}
120
121func (e ACLRemoteError) Error() string {
122	return fmt.Sprintf("Error communicating with the ACL Datacenter: %v", e.Err)
123}
124
125func IsACLRemoteError(err error) bool {
126	_, ok := err.(ACLRemoteError)
127	return ok
128}
129
130func tokenSecretCacheID(token string) string {
131	return "token-secret:" + token
132}
133
134type ACLResolverDelegate interface {
135	ACLsEnabled() bool
136	ACLDatacenter(legacy bool) string
137	UseLegacyACLs() bool
138	ResolveIdentityFromToken(token string) (bool, structs.ACLIdentity, error)
139	ResolvePolicyFromID(policyID string) (bool, *structs.ACLPolicy, error)
140	ResolveRoleFromID(roleID string) (bool, *structs.ACLRole, error)
141	RPC(method string, args interface{}, reply interface{}) error
142	EnterpriseACLResolverDelegate
143}
144
145type policyOrRoleTokenError struct {
146	Err   error
147	token string
148}
149
150func (e policyOrRoleTokenError) Error() string {
151	return e.Err.Error()
152}
153
154// ACLResolverConfig holds all the configuration necessary to create an ACLResolver
155type ACLResolverConfig struct {
156	Config *Config
157	Logger hclog.Logger
158
159	// CacheConfig is a pass through configuration for ACL cache limits
160	CacheConfig *structs.ACLCachesConfig
161
162	// Delegate that implements some helper functionality that is server/client specific
163	Delegate ACLResolverDelegate
164
165	// AutoDisable indicates that RPC responses should be checked and if they indicate ACLs are disabled
166	// remotely then disable them locally as well. This is particularly useful for the client agent
167	// so that it can detect when the servers have gotten ACLs enabled.
168	AutoDisable bool
169
170	// ACLConfig is the configuration necessary to pass through to the acl package when creating authorizers
171	// and when authorizing access
172	ACLConfig *acl.Config
173}
174
175// ACLResolver is the type to handle all your token and policy resolution needs.
176//
177// Supports:
178//   - Resolving tokens locally via the ACLResolverDelegate
179//   - Resolving policies locally via the ACLResolverDelegate
180//   - Resolving roles locally via the ACLResolverDelegate
181//   - Resolving legacy tokens remotely via an ACL.GetPolicy RPC
182//   - Resolving tokens remotely via an ACL.TokenRead RPC
183//   - Resolving policies remotely via an ACL.PolicyResolve RPC
184//   - Resolving roles remotely via an ACL.RoleResolve RPC
185//
186// Remote Resolution:
187//   Remote resolution can be done synchronously or asynchronously depending
188//   on the ACLDownPolicy in the Config passed to the resolver.
189//
190//   When the down policy is set to async-cache and we have already cached values
191//   then go routines will be spawned to perform the RPCs in the background
192//   and then will update the cache with either the positive or negative result.
193//
194//   When the down policy is set to extend-cache or the token/policy/role is not already
195//   cached then the same go routines are spawned to do the RPCs in the background.
196//   However in this mode channels are created to receive the results of the RPC
197//   and are registered with the resolver. Those channels are immediately read/blocked
198//   upon.
199//
200type ACLResolver struct {
201	config *Config
202	logger hclog.Logger
203
204	delegate ACLResolverDelegate
205	aclConf  *acl.Config
206
207	cache         *structs.ACLCaches
208	identityGroup singleflight.Group
209	policyGroup   singleflight.Group
210	roleGroup     singleflight.Group
211	legacyGroup   singleflight.Group
212
213	down acl.Authorizer
214
215	autoDisable  bool
216	disabled     time.Time
217	disabledLock sync.RWMutex
218}
219
220func NewACLResolver(config *ACLResolverConfig) (*ACLResolver, error) {
221	if config == nil {
222		return nil, fmt.Errorf("ACL Resolver must be initialized with a config")
223	}
224
225	if config.Config == nil {
226		return nil, fmt.Errorf("ACLResolverConfig.Config must not be nil")
227	}
228
229	if config.Delegate == nil {
230		return nil, fmt.Errorf("ACL Resolver must be initialized with a valid delegate")
231	}
232
233	if config.Logger == nil {
234		config.Logger = hclog.New(&hclog.LoggerOptions{})
235	}
236
237	cache, err := structs.NewACLCaches(config.CacheConfig)
238	if err != nil {
239		return nil, err
240	}
241
242	var down acl.Authorizer
243	switch config.Config.ACLDownPolicy {
244	case "allow":
245		down = acl.AllowAll()
246	case "deny":
247		down = acl.DenyAll()
248	case "async-cache", "extend-cache":
249		// Leave the down policy as nil to signal this.
250	default:
251		return nil, fmt.Errorf("invalid ACL down policy %q", config.Config.ACLDownPolicy)
252	}
253
254	return &ACLResolver{
255		config:      config.Config,
256		logger:      config.Logger.Named(logging.ACL),
257		delegate:    config.Delegate,
258		aclConf:     config.ACLConfig,
259		cache:       cache,
260		autoDisable: config.AutoDisable,
261		down:        down,
262	}, nil
263}
264
265func (r *ACLResolver) Close() {
266	r.aclConf.Close()
267}
268
269func (r *ACLResolver) fetchAndCacheTokenLegacy(token string, cached *structs.AuthorizerCacheEntry) (acl.Authorizer, error) {
270	req := structs.ACLPolicyResolveLegacyRequest{
271		Datacenter: r.delegate.ACLDatacenter(true),
272		ACL:        token,
273	}
274
275	cacheTTL := r.config.ACLTokenTTL
276	if cached != nil {
277		cacheTTL = cached.TTL
278	}
279
280	var reply structs.ACLPolicyResolveLegacyResponse
281	err := r.delegate.RPC("ACL.GetPolicy", &req, &reply)
282	if err == nil {
283		parent := acl.RootAuthorizer(reply.Parent)
284		if parent == nil {
285			var authorizer acl.Authorizer
286			if cached != nil {
287				authorizer = cached.Authorizer
288			}
289			r.cache.PutAuthorizerWithTTL(token, authorizer, cacheTTL)
290			return authorizer, acl.ErrInvalidParent
291		}
292
293		var policies []*acl.Policy
294		policy := reply.Policy
295		if policy != nil {
296			policies = append(policies, policy.ConvertFromLegacy())
297		}
298
299		authorizer, err := acl.NewPolicyAuthorizerWithDefaults(parent, policies, r.aclConf)
300
301		r.cache.PutAuthorizerWithTTL(token, authorizer, reply.TTL)
302		return authorizer, err
303	}
304
305	if acl.IsErrNotFound(err) {
306		// Make sure to remove from the cache if it was deleted
307		r.cache.PutAuthorizerWithTTL(token, nil, cacheTTL)
308		return nil, acl.ErrNotFound
309
310	}
311
312	// some other RPC error
313	switch r.config.ACLDownPolicy {
314	case "allow":
315		r.cache.PutAuthorizerWithTTL(token, acl.AllowAll(), cacheTTL)
316		return acl.AllowAll(), nil
317	case "async-cache", "extend-cache":
318		if cached != nil {
319			r.cache.PutAuthorizerWithTTL(token, cached.Authorizer, cacheTTL)
320			return cached.Authorizer, nil
321		}
322		fallthrough
323	default:
324		r.cache.PutAuthorizerWithTTL(token, acl.DenyAll(), cacheTTL)
325		return acl.DenyAll(), nil
326	}
327}
328
329func (r *ACLResolver) resolveTokenLegacy(token string) (structs.ACLIdentity, acl.Authorizer, error) {
330	defer metrics.MeasureSince([]string{"acl", "resolveTokenLegacy"}, time.Now())
331
332	// Attempt to resolve locally first (local results are not cached)
333	// This is only useful for servers where either legacy replication is being
334	// done or the server is within the primary datacenter.
335	if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done {
336		if err == nil && identity != nil {
337			policies, err := r.resolvePoliciesForIdentity(identity)
338			if err != nil {
339				return identity, nil, err
340			}
341
342			authz, err := policies.Compile(r.cache, r.aclConf)
343			if err != nil {
344				return identity, nil, err
345			}
346
347			return identity, acl.NewChainedAuthorizer([]acl.Authorizer{authz, acl.RootAuthorizer(r.config.ACLDefaultPolicy)}), nil
348		}
349
350		return nil, nil, err
351	}
352
353	identity := &missingIdentity{
354		reason: "legacy-token",
355		token:  token,
356	}
357
358	// Look in the cache prior to making a RPC request
359	entry := r.cache.GetAuthorizer(token)
360
361	if entry != nil && entry.Age() <= minTTL(entry.TTL, r.config.ACLTokenTTL) {
362		metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1)
363		if entry.Authorizer != nil {
364			return identity, entry.Authorizer, nil
365		}
366		return identity, nil, acl.ErrNotFound
367	}
368
369	metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1)
370
371	// Resolve the token in the background and wait on the result if we must
372	waitChan := r.legacyGroup.DoChan(token, func() (interface{}, error) {
373		authorizer, err := r.fetchAndCacheTokenLegacy(token, entry)
374		return authorizer, err
375	})
376
377	waitForResult := entry == nil || r.config.ACLDownPolicy != "async-cache"
378	if !waitForResult {
379		// waitForResult being false requires the cacheEntry to not be nil
380		if entry.Authorizer != nil {
381			return identity, entry.Authorizer, nil
382		}
383		return identity, nil, acl.ErrNotFound
384	}
385
386	// block waiting for the async RPC to finish.
387	res := <-waitChan
388
389	var authorizer acl.Authorizer
390	if res.Val != nil { // avoid a nil-not-nil bug
391		authorizer = res.Val.(acl.Authorizer)
392	}
393
394	return identity, authorizer, res.Err
395}
396
397func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) {
398	cacheID := tokenSecretCacheID(token)
399
400	req := structs.ACLTokenGetRequest{
401		Datacenter:  r.delegate.ACLDatacenter(false),
402		TokenID:     token,
403		TokenIDType: structs.ACLTokenSecret,
404		QueryOptions: structs.QueryOptions{
405			Token:      token,
406			AllowStale: true,
407		},
408	}
409
410	var resp structs.ACLTokenResponse
411	err := r.delegate.RPC("ACL.TokenRead", &req, &resp)
412	if err == nil {
413		if resp.Token == nil {
414			r.cache.PutIdentity(cacheID, nil)
415			return nil, acl.ErrNotFound
416		} else {
417			r.cache.PutIdentity(cacheID, resp.Token)
418			return resp.Token, nil
419		}
420	}
421
422	if acl.IsErrNotFound(err) {
423		// Make sure to remove from the cache if it was deleted
424		r.cache.PutIdentity(cacheID, nil)
425		return nil, acl.ErrNotFound
426
427	}
428
429	// some other RPC error
430	if cached != nil && (r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache") {
431		// extend the cache
432		r.cache.PutIdentity(cacheID, cached.Identity)
433		return cached.Identity, nil
434	}
435
436	r.cache.PutIdentity(cacheID, nil)
437	return nil, err
438}
439
440// resolveIdentityFromToken takes a token secret as a string and returns an ACLIdentity.
441// We read the value from ACLResolver's cache if available, and if the read misses
442// we initiate an RPC for the value.
443func (r *ACLResolver) resolveIdentityFromToken(token string) (structs.ACLIdentity, error) {
444	// Attempt to resolve locally first (local results are not cached)
445	if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done {
446		return identity, err
447	}
448
449	// Check the cache before making any RPC requests
450	cacheEntry := r.cache.GetIdentity(tokenSecretCacheID(token))
451	if cacheEntry != nil && cacheEntry.Age() <= r.config.ACLTokenTTL {
452		metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1)
453		return cacheEntry.Identity, nil
454	}
455
456	metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1)
457
458	// Background a RPC request and wait on it if we must
459	waitChan := r.identityGroup.DoChan(token, func() (interface{}, error) {
460		identity, err := r.fetchAndCacheIdentityFromToken(token, cacheEntry)
461		return identity, err
462	})
463
464	waitForResult := cacheEntry == nil || r.config.ACLDownPolicy != "async-cache"
465	if !waitForResult {
466		// waitForResult being false requires the cacheEntry to not be nil
467		return cacheEntry.Identity, nil
468	}
469
470	// block on the read here, this is why we don't need chan buffering
471	res := <-waitChan
472
473	var identity structs.ACLIdentity
474	if res.Val != nil { // avoid a nil-not-nil bug
475		identity = res.Val.(structs.ACLIdentity)
476	}
477
478	if res.Err != nil && !acl.IsErrNotFound(res.Err) {
479		return identity, ACLRemoteError{Err: res.Err}
480	}
481	return identity, res.Err
482}
483
484func (r *ACLResolver) fetchAndCachePoliciesForIdentity(identity structs.ACLIdentity, policyIDs []string, cached map[string]*structs.PolicyCacheEntry) (map[string]*structs.ACLPolicy, error) {
485	req := structs.ACLPolicyBatchGetRequest{
486		Datacenter: r.delegate.ACLDatacenter(false),
487		PolicyIDs:  policyIDs,
488		QueryOptions: structs.QueryOptions{
489			Token:      identity.SecretToken(),
490			AllowStale: true,
491		},
492	}
493
494	var resp structs.ACLPolicyBatchResponse
495	err := r.delegate.RPC("ACL.PolicyResolve", &req, &resp)
496	if err == nil {
497		out := make(map[string]*structs.ACLPolicy)
498		for _, policy := range resp.Policies {
499			out[policy.ID] = policy
500		}
501
502		for _, policyID := range policyIDs {
503			if policy, ok := out[policyID]; ok {
504				r.cache.PutPolicy(policyID, policy)
505			} else {
506				r.cache.PutPolicy(policyID, nil)
507			}
508		}
509		return out, nil
510	}
511
512	if handledErr := r.maybeHandleIdentityErrorDuringFetch(identity, err); handledErr != nil {
513		return nil, handledErr
514	}
515
516	// other RPC error - use cache if available
517
518	extendCache := r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache"
519
520	out := make(map[string]*structs.ACLPolicy)
521	insufficientCache := false
522	for _, policyID := range policyIDs {
523		if entry, ok := cached[policyID]; extendCache && ok {
524			r.cache.PutPolicy(policyID, entry.Policy)
525			if entry.Policy != nil {
526				out[policyID] = entry.Policy
527			}
528		} else {
529			r.cache.PutPolicy(policyID, nil)
530			insufficientCache = true
531		}
532	}
533	if insufficientCache {
534		return nil, ACLRemoteError{Err: err}
535	}
536	return out, nil
537}
538
539func (r *ACLResolver) fetchAndCacheRolesForIdentity(identity structs.ACLIdentity, roleIDs []string, cached map[string]*structs.RoleCacheEntry) (map[string]*structs.ACLRole, error) {
540	req := structs.ACLRoleBatchGetRequest{
541		Datacenter: r.delegate.ACLDatacenter(false),
542		RoleIDs:    roleIDs,
543		QueryOptions: structs.QueryOptions{
544			Token:      identity.SecretToken(),
545			AllowStale: true,
546		},
547	}
548
549	var resp structs.ACLRoleBatchResponse
550	err := r.delegate.RPC("ACL.RoleResolve", &req, &resp)
551	if err == nil {
552		out := make(map[string]*structs.ACLRole)
553		for _, role := range resp.Roles {
554			out[role.ID] = role
555		}
556
557		for _, roleID := range roleIDs {
558			if role, ok := out[roleID]; ok {
559				r.cache.PutRole(roleID, role)
560			} else {
561				r.cache.PutRole(roleID, nil)
562			}
563		}
564		return out, nil
565	}
566
567	if handledErr := r.maybeHandleIdentityErrorDuringFetch(identity, err); handledErr != nil {
568		return nil, handledErr
569	}
570
571	// other RPC error - use cache if available
572
573	extendCache := r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache"
574
575	out := make(map[string]*structs.ACLRole)
576	insufficientCache := false
577	for _, roleID := range roleIDs {
578		if entry, ok := cached[roleID]; extendCache && ok {
579			r.cache.PutRole(roleID, entry.Role)
580			if entry.Role != nil {
581				out[roleID] = entry.Role
582			}
583		} else {
584			r.cache.PutRole(roleID, nil)
585			insufficientCache = true
586		}
587	}
588
589	if insufficientCache {
590		return nil, ACLRemoteError{Err: err}
591	}
592
593	return out, nil
594}
595
596func (r *ACLResolver) maybeHandleIdentityErrorDuringFetch(identity structs.ACLIdentity, err error) error {
597	if acl.IsErrNotFound(err) {
598		// make sure to indicate that this identity is no longer valid within
599		// the cache
600		r.cache.PutIdentity(tokenSecretCacheID(identity.SecretToken()), nil)
601
602		// Do not touch the cache. Getting a top level ACL not found error
603		// only indicates that the secret token used in the request
604		// no longer exists
605		return &policyOrRoleTokenError{acl.ErrNotFound, identity.SecretToken()}
606	}
607
608	if acl.IsErrPermissionDenied(err) {
609		// invalidate our ID cache so that identity resolution will take place
610		// again in the future
611		r.cache.RemoveIdentity(tokenSecretCacheID(identity.SecretToken()))
612
613		// Do not remove from the cache for permission denied
614		// what this does indicate is that our view of the token is out of date
615		return &policyOrRoleTokenError{acl.ErrPermissionDenied, identity.SecretToken()}
616	}
617
618	return nil
619}
620
621func (r *ACLResolver) filterPoliciesByScope(policies structs.ACLPolicies) structs.ACLPolicies {
622	var out structs.ACLPolicies
623	for _, policy := range policies {
624		if len(policy.Datacenters) == 0 {
625			out = append(out, policy)
626			continue
627		}
628
629		for _, dc := range policy.Datacenters {
630			if dc == r.config.Datacenter {
631				out = append(out, policy)
632				continue
633			}
634		}
635	}
636
637	return out
638}
639
640func (r *ACLResolver) resolvePoliciesForIdentity(identity structs.ACLIdentity) (structs.ACLPolicies, error) {
641	policyIDs := identity.PolicyIDs()
642	roleIDs := identity.RoleIDs()
643	serviceIdentities := identity.ServiceIdentityList()
644
645	if len(policyIDs) == 0 && len(serviceIdentities) == 0 && len(roleIDs) == 0 {
646		policy := identity.EmbeddedPolicy()
647		if policy != nil {
648			return []*structs.ACLPolicy{policy}, nil
649		}
650
651		// In this case the default policy will be all that is in effect.
652		return nil, nil
653	}
654
655	// Collect all of the roles tied to this token.
656	roles, err := r.collectRolesForIdentity(identity, roleIDs)
657	if err != nil {
658		return nil, err
659	}
660
661	// Merge the policies and service identities across Token and Role fields.
662	for _, role := range roles {
663		for _, link := range role.Policies {
664			policyIDs = append(policyIDs, link.ID)
665		}
666		serviceIdentities = append(serviceIdentities, role.ServiceIdentities...)
667	}
668
669	// Now deduplicate any policies or service identities that occur more than once.
670	policyIDs = dedupeStringSlice(policyIDs)
671	serviceIdentities = dedupeServiceIdentities(serviceIdentities)
672
673	// Generate synthetic policies for all service identities in effect.
674	syntheticPolicies := r.synthesizePoliciesForServiceIdentities(serviceIdentities, identity.EnterpriseMetadata())
675
676	// For the new ACLs policy replication is mandatory for correct operation on servers. Therefore
677	// we only attempt to resolve policies locally
678	policies, err := r.collectPoliciesForIdentity(identity, policyIDs, len(syntheticPolicies))
679	if err != nil {
680		return nil, err
681	}
682
683	policies = append(policies, syntheticPolicies...)
684	filtered := r.filterPoliciesByScope(policies)
685	return filtered, nil
686}
687
688func (r *ACLResolver) synthesizePoliciesForServiceIdentities(serviceIdentities []*structs.ACLServiceIdentity, entMeta *structs.EnterpriseMeta) []*structs.ACLPolicy {
689	if len(serviceIdentities) == 0 {
690		return nil
691	}
692
693	syntheticPolicies := make([]*structs.ACLPolicy, 0, len(serviceIdentities))
694	for _, s := range serviceIdentities {
695		syntheticPolicies = append(syntheticPolicies, s.SyntheticPolicy(entMeta))
696	}
697
698	return syntheticPolicies
699}
700
701func dedupeServiceIdentities(in []*structs.ACLServiceIdentity) []*structs.ACLServiceIdentity {
702	// From: https://github.com/golang/go/wiki/SliceTricks#in-place-deduplicate-comparable
703
704	if len(in) <= 1 {
705		return in
706	}
707
708	sort.Slice(in, func(i, j int) bool {
709		return in[i].ServiceName < in[j].ServiceName
710	})
711
712	j := 0
713	for i := 1; i < len(in); i++ {
714		if in[j].ServiceName == in[i].ServiceName {
715			// Prefer increasing scope.
716			if len(in[j].Datacenters) == 0 || len(in[i].Datacenters) == 0 {
717				in[j].Datacenters = nil
718			} else {
719				in[j].Datacenters = mergeStringSlice(in[j].Datacenters, in[i].Datacenters)
720			}
721			continue
722		}
723		j++
724		in[j] = in[i]
725	}
726
727	// Discard the skipped items.
728	for i := j + 1; i < len(in); i++ {
729		in[i] = nil
730	}
731
732	return in[:j+1]
733}
734
735func mergeStringSlice(a, b []string) []string {
736	out := make([]string, 0, len(a)+len(b))
737	out = append(out, a...)
738	out = append(out, b...)
739	return dedupeStringSlice(out)
740}
741
742func dedupeStringSlice(in []string) []string {
743	// From: https://github.com/golang/go/wiki/SliceTricks#in-place-deduplicate-comparable
744
745	if len(in) <= 1 {
746		return in
747	}
748
749	sort.Strings(in)
750
751	j := 0
752	for i := 1; i < len(in); i++ {
753		if in[j] == in[i] {
754			continue
755		}
756		j++
757		in[j] = in[i]
758	}
759
760	return in[:j+1]
761}
762
763func (r *ACLResolver) collectPoliciesForIdentity(identity structs.ACLIdentity, policyIDs []string, extraCap int) ([]*structs.ACLPolicy, error) {
764	policies := make([]*structs.ACLPolicy, 0, len(policyIDs)+extraCap)
765
766	// Get all associated policies
767	var missing []string
768	var expired []*structs.ACLPolicy
769	expCacheMap := make(map[string]*structs.PolicyCacheEntry)
770
771	var accessorID string
772	if identity != nil {
773		accessorID = identity.ID()
774	}
775
776	for _, policyID := range policyIDs {
777		if done, policy, err := r.delegate.ResolvePolicyFromID(policyID); done {
778			if err != nil && !acl.IsErrNotFound(err) {
779				return nil, err
780			}
781
782			if policy != nil {
783				policies = append(policies, policy)
784			} else {
785				r.logger.Warn("policy not found for identity",
786					"policy", policyID,
787					"accessorID", accessorID,
788				)
789			}
790
791			continue
792		}
793
794		// create the missing list which we can execute an RPC to get all the missing policies at once
795		entry := r.cache.GetPolicy(policyID)
796		if entry == nil {
797			missing = append(missing, policyID)
798			continue
799		}
800
801		if entry.Policy == nil {
802			// this happens when we cache a negative response for the policy's existence
803			continue
804		}
805
806		if entry.Age() >= r.config.ACLPolicyTTL {
807			expired = append(expired, entry.Policy)
808			expCacheMap[policyID] = entry
809		} else {
810			policies = append(policies, entry.Policy)
811		}
812	}
813
814	// Hot-path if we have no missing or expired policies
815	if len(missing)+len(expired) == 0 {
816		return policies, nil
817	}
818
819	hasMissing := len(missing) > 0
820
821	fetchIDs := missing
822	for _, policy := range expired {
823		fetchIDs = append(fetchIDs, policy.ID)
824	}
825
826	// Background a RPC request and wait on it if we must
827	waitChan := r.policyGroup.DoChan(identity.SecretToken(), func() (interface{}, error) {
828		policies, err := r.fetchAndCachePoliciesForIdentity(identity, fetchIDs, expCacheMap)
829		return policies, err
830	})
831
832	waitForResult := hasMissing || r.config.ACLDownPolicy != "async-cache"
833	if !waitForResult {
834		// waitForResult being false requires that all the policies were cached already
835		policies = append(policies, expired...)
836		return policies, nil
837	}
838
839	res := <-waitChan
840
841	if res.Err != nil {
842		return nil, res.Err
843	}
844
845	if res.Val != nil {
846		foundPolicies := res.Val.(map[string]*structs.ACLPolicy)
847
848		for _, policy := range foundPolicies {
849			policies = append(policies, policy)
850		}
851	}
852
853	return policies, nil
854}
855
856func (r *ACLResolver) resolveRolesForIdentity(identity structs.ACLIdentity) (structs.ACLRoles, error) {
857	return r.collectRolesForIdentity(identity, identity.RoleIDs())
858}
859
860func (r *ACLResolver) collectRolesForIdentity(identity structs.ACLIdentity, roleIDs []string) (structs.ACLRoles, error) {
861	if len(roleIDs) == 0 {
862		return nil, nil
863	}
864
865	// For the new ACLs policy & role replication is mandatory for correct operation
866	// on servers. Therefore we only attempt to resolve roles locally
867	roles := make([]*structs.ACLRole, 0, len(roleIDs))
868
869	var missing []string
870	var expired []*structs.ACLRole
871	expCacheMap := make(map[string]*structs.RoleCacheEntry)
872
873	for _, roleID := range roleIDs {
874		if done, role, err := r.delegate.ResolveRoleFromID(roleID); done {
875			if err != nil && !acl.IsErrNotFound(err) {
876				return nil, err
877			}
878
879			if role != nil {
880				roles = append(roles, role)
881			} else {
882				var accessorID string
883				if identity != nil {
884					accessorID = identity.ID()
885				}
886				r.logger.Warn("role not found for identity",
887					"role", roleID,
888					"accessorID", accessorID,
889				)
890			}
891
892			continue
893		}
894
895		// create the missing list which we can execute an RPC to get all the missing roles at once
896		entry := r.cache.GetRole(roleID)
897		if entry == nil {
898			missing = append(missing, roleID)
899			continue
900		}
901
902		if entry.Role == nil {
903			// this happens when we cache a negative response for the role's existence
904			continue
905		}
906
907		if entry.Age() >= r.config.ACLRoleTTL {
908			expired = append(expired, entry.Role)
909			expCacheMap[roleID] = entry
910		} else {
911			roles = append(roles, entry.Role)
912		}
913	}
914
915	// Hot-path if we have no missing or expired roles
916	if len(missing)+len(expired) == 0 {
917		return roles, nil
918	}
919
920	hasMissing := len(missing) > 0
921
922	fetchIDs := missing
923	for _, role := range expired {
924		fetchIDs = append(fetchIDs, role.ID)
925	}
926
927	waitChan := r.roleGroup.DoChan(identity.SecretToken(), func() (interface{}, error) {
928		roles, err := r.fetchAndCacheRolesForIdentity(identity, fetchIDs, expCacheMap)
929		return roles, err
930	})
931
932	waitForResult := hasMissing || r.config.ACLDownPolicy != "async-cache"
933	if !waitForResult {
934		// waitForResult being false requires that all the roles were cached already
935		roles = append(roles, expired...)
936		return roles, nil
937	}
938
939	res := <-waitChan
940
941	if res.Err != nil {
942		return nil, res.Err
943	}
944
945	if res.Val != nil {
946		foundRoles := res.Val.(map[string]*structs.ACLRole)
947
948		for _, role := range foundRoles {
949			roles = append(roles, role)
950		}
951	}
952
953	return roles, nil
954}
955
956func (r *ACLResolver) resolveTokenToPolicies(token string) (structs.ACLPolicies, error) {
957	_, policies, err := r.resolveTokenToIdentityAndPolicies(token)
958	return policies, err
959}
960
961func (r *ACLResolver) resolveTokenToIdentityAndPolicies(token string) (structs.ACLIdentity, structs.ACLPolicies, error) {
962	var lastErr error
963	var lastIdentity structs.ACLIdentity
964
965	for i := 0; i < tokenPolicyResolutionMaxRetries; i++ {
966		// Resolve the token to an ACLIdentity
967		identity, err := r.resolveIdentityFromToken(token)
968		if err != nil {
969			return nil, nil, err
970		} else if identity == nil {
971			return nil, nil, acl.ErrNotFound
972		} else if identity.IsExpired(time.Now()) {
973			return nil, nil, acl.ErrNotFound
974		}
975
976		lastIdentity = identity
977
978		policies, err := r.resolvePoliciesForIdentity(identity)
979		if err == nil {
980			return identity, policies, nil
981		}
982		lastErr = err
983
984		if tokenErr, ok := err.(*policyOrRoleTokenError); ok {
985			if acl.IsErrNotFound(err) && tokenErr.token == identity.SecretToken() {
986				// token was deleted while resolving policies
987				return nil, nil, acl.ErrNotFound
988			}
989
990			// other types of policyOrRoleTokenErrors should cause retrying the whole token
991			// resolution process
992		} else {
993			return identity, nil, err
994		}
995	}
996
997	return lastIdentity, nil, lastErr
998}
999
1000func (r *ACLResolver) resolveTokenToIdentityAndRoles(token string) (structs.ACLIdentity, structs.ACLRoles, error) {
1001	var lastErr error
1002	var lastIdentity structs.ACLIdentity
1003
1004	for i := 0; i < tokenRoleResolutionMaxRetries; i++ {
1005		// Resolve the token to an ACLIdentity
1006		identity, err := r.resolveIdentityFromToken(token)
1007		if err != nil {
1008			return nil, nil, err
1009		} else if identity == nil {
1010			return nil, nil, acl.ErrNotFound
1011		} else if identity.IsExpired(time.Now()) {
1012			return nil, nil, acl.ErrNotFound
1013		}
1014
1015		lastIdentity = identity
1016
1017		roles, err := r.resolveRolesForIdentity(identity)
1018		if err == nil {
1019			return identity, roles, nil
1020		}
1021		lastErr = err
1022
1023		if tokenErr, ok := err.(*policyOrRoleTokenError); ok {
1024			if acl.IsErrNotFound(err) && tokenErr.token == identity.SecretToken() {
1025				// token was deleted while resolving roles
1026				return nil, nil, acl.ErrNotFound
1027			}
1028
1029			// other types of policyOrRoleTokenErrors should cause retrying the whole token
1030			// resolution process
1031		} else {
1032			return identity, nil, err
1033		}
1034	}
1035
1036	return lastIdentity, nil, lastErr
1037}
1038
1039func (r *ACLResolver) disableACLsWhenUpstreamDisabled(err error) error {
1040	if !r.autoDisable || err == nil || !acl.IsErrDisabled(err) {
1041		return err
1042	}
1043
1044	r.logger.Debug("ACLs disabled on upstream servers, will retry", "retry_interval", r.config.ACLDisabledTTL)
1045	r.disabledLock.Lock()
1046	r.disabled = time.Now().Add(r.config.ACLDisabledTTL)
1047	r.disabledLock.Unlock()
1048
1049	return err
1050}
1051
1052func (r *ACLResolver) ResolveTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer, error) {
1053	if !r.ACLsEnabled() {
1054		return nil, nil, nil
1055	}
1056
1057	if acl.RootAuthorizer(token) != nil {
1058		return nil, nil, acl.ErrRootDenied
1059	}
1060
1061	// handle the anonymous token
1062	if token == "" {
1063		token = anonymousToken
1064	}
1065
1066	if r.delegate.UseLegacyACLs() {
1067		identity, authorizer, err := r.resolveTokenLegacy(token)
1068		return identity, authorizer, r.disableACLsWhenUpstreamDisabled(err)
1069	}
1070
1071	defer metrics.MeasureSince([]string{"acl", "ResolveToken"}, time.Now())
1072
1073	identity, policies, err := r.resolveTokenToIdentityAndPolicies(token)
1074	if err != nil {
1075		r.disableACLsWhenUpstreamDisabled(err)
1076		if IsACLRemoteError(err) {
1077			r.logger.Error("Error resolving token", "error", err)
1078			return &missingIdentity{reason: "primary-dc-down", token: token}, r.down, nil
1079		}
1080
1081		return nil, nil, err
1082	}
1083
1084	// Build the Authorizer
1085	var chain []acl.Authorizer
1086
1087	authz, err := policies.Compile(r.cache, r.aclConf)
1088	if err != nil {
1089		return nil, nil, err
1090	}
1091	chain = append(chain, authz)
1092
1093	authz, err = r.resolveEnterpriseDefaultsForIdentity(identity)
1094	if err != nil {
1095		if IsACLRemoteError(err) {
1096			r.logger.Error("Error resolving identity defaults", "error", err)
1097			return identity, r.down, nil
1098		}
1099		return nil, nil, err
1100	} else if authz != nil {
1101		chain = append(chain, authz)
1102	}
1103
1104	chain = append(chain, acl.RootAuthorizer(r.config.ACLDefaultPolicy))
1105	return identity, acl.NewChainedAuthorizer(chain), nil
1106}
1107
1108func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) {
1109	_, authz, err := r.ResolveTokenToIdentityAndAuthorizer(token)
1110	return authz, err
1111}
1112
1113func (r *ACLResolver) ACLsEnabled() bool {
1114	// Whether we desire ACLs to be enabled according to configuration
1115	if !r.delegate.ACLsEnabled() {
1116		return false
1117	}
1118
1119	if r.autoDisable {
1120		// Whether ACLs are disabled according to RPCs failing with a ACLs Disabled error
1121		r.disabledLock.RLock()
1122		defer r.disabledLock.RUnlock()
1123		return !time.Now().Before(r.disabled)
1124	}
1125
1126	return true
1127}
1128
1129func (r *ACLResolver) GetMergedPolicyForToken(token string) (*acl.Policy, error) {
1130	policies, err := r.resolveTokenToPolicies(token)
1131	if err != nil {
1132		return nil, err
1133	}
1134	if len(policies) == 0 {
1135		return nil, acl.ErrNotFound
1136	}
1137
1138	return policies.Merge(r.cache, r.aclConf)
1139}
1140
1141// aclFilter is used to filter results from our state store based on ACL rules
1142// configured for the provided token.
1143type aclFilter struct {
1144	authorizer      acl.Authorizer
1145	logger          hclog.Logger
1146	enforceVersion8 bool
1147}
1148
1149// newACLFilter constructs a new aclFilter.
1150func newACLFilter(authorizer acl.Authorizer, logger hclog.Logger, enforceVersion8 bool) *aclFilter {
1151	if logger == nil {
1152		logger = hclog.New(&hclog.LoggerOptions{})
1153	}
1154	return &aclFilter{
1155		authorizer:      authorizer,
1156		logger:          logger,
1157		enforceVersion8: enforceVersion8,
1158	}
1159}
1160
1161// allowNode is used to determine if a node is accessible for an ACL.
1162func (f *aclFilter) allowNode(node string, ent *acl.AuthorizerContext) bool {
1163	if !f.enforceVersion8 {
1164		return true
1165	}
1166
1167	return f.authorizer.NodeRead(node, ent) == acl.Allow
1168}
1169
1170// allowService is used to determine if a service is accessible for an ACL.
1171func (f *aclFilter) allowService(service string, ent *acl.AuthorizerContext) bool {
1172	if service == "" {
1173		return true
1174	}
1175
1176	if !f.enforceVersion8 && service == structs.ConsulServiceID {
1177		return true
1178	}
1179	return f.authorizer.ServiceRead(service, ent) == acl.Allow
1180}
1181
1182// allowSession is used to determine if a session for a node is accessible for
1183// an ACL.
1184func (f *aclFilter) allowSession(node string, ent *acl.AuthorizerContext) bool {
1185	if !f.enforceVersion8 {
1186		return true
1187	}
1188	return f.authorizer.SessionRead(node, ent) == acl.Allow
1189}
1190
1191// filterHealthChecks is used to filter a set of health checks down based on
1192// the configured ACL rules for a token.
1193func (f *aclFilter) filterHealthChecks(checks *structs.HealthChecks) {
1194	hc := *checks
1195	var authzContext acl.AuthorizerContext
1196
1197	for i := 0; i < len(hc); i++ {
1198		check := hc[i]
1199		check.FillAuthzContext(&authzContext)
1200		if f.allowNode(check.Node, &authzContext) && f.allowService(check.ServiceName, &authzContext) {
1201			continue
1202		}
1203
1204		f.logger.Debug("dropping check from result due to ACLs", "check", check.CheckID)
1205		hc = append(hc[:i], hc[i+1:]...)
1206		i--
1207	}
1208	*checks = hc
1209}
1210
1211// filterServices is used to filter a set of services based on ACLs.
1212func (f *aclFilter) filterServices(services structs.Services, entMeta *structs.EnterpriseMeta) {
1213	var authzContext acl.AuthorizerContext
1214	entMeta.FillAuthzContext(&authzContext)
1215
1216	for svc := range services {
1217		if f.allowService(svc, &authzContext) {
1218			continue
1219		}
1220		f.logger.Debug("dropping service from result due to ACLs", "service", svc)
1221		delete(services, svc)
1222	}
1223}
1224
1225// filterServiceNodes is used to filter a set of nodes for a given service
1226// based on the configured ACL rules.
1227func (f *aclFilter) filterServiceNodes(nodes *structs.ServiceNodes) {
1228	sn := *nodes
1229	var authzContext acl.AuthorizerContext
1230
1231	for i := 0; i < len(sn); i++ {
1232		node := sn[i]
1233
1234		node.FillAuthzContext(&authzContext)
1235		if f.allowNode(node.Node, &authzContext) && f.allowService(node.ServiceName, &authzContext) {
1236			continue
1237		}
1238		f.logger.Debug("dropping node from result due to ACLs", "node", node.Node)
1239		sn = append(sn[:i], sn[i+1:]...)
1240		i--
1241	}
1242	*nodes = sn
1243}
1244
1245// filterNodeServices is used to filter services on a given node base on ACLs.
1246func (f *aclFilter) filterNodeServices(services **structs.NodeServices) {
1247	if *services == nil {
1248		return
1249	}
1250
1251	var authzContext acl.AuthorizerContext
1252	structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext)
1253	if !f.allowNode((*services).Node.Node, &authzContext) {
1254		*services = nil
1255		return
1256	}
1257
1258	for svcName, svc := range (*services).Services {
1259		svc.FillAuthzContext(&authzContext)
1260
1261		if f.allowNode((*services).Node.Node, &authzContext) && f.allowService(svcName, &authzContext) {
1262			continue
1263		}
1264		f.logger.Debug("dropping service from result due to ACLs", "service", svc.CompoundServiceID())
1265		delete((*services).Services, svcName)
1266	}
1267}
1268
1269// filterNodeServices is used to filter services on a given node base on ACLs.
1270func (f *aclFilter) filterNodeServiceList(services **structs.NodeServiceList) {
1271	if services == nil || *services == nil {
1272		return
1273	}
1274
1275	var authzContext acl.AuthorizerContext
1276	structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext)
1277	if !f.allowNode((*services).Node.Node, &authzContext) {
1278		*services = nil
1279		return
1280	}
1281
1282	svcs := (*services).Services
1283	modified := false
1284	for i := 0; i < len(svcs); i++ {
1285		svc := svcs[i]
1286		svc.FillAuthzContext(&authzContext)
1287
1288		if f.allowNode((*services).Node.Node, &authzContext) && f.allowService(svc.Service, &authzContext) {
1289			continue
1290		}
1291		f.logger.Debug("dropping service from result due to ACLs", "service", svc.CompoundServiceID())
1292		svcs = append(svcs[:i], svcs[i+1:]...)
1293		i--
1294		modified = true
1295	}
1296
1297	if modified {
1298		*services = &structs.NodeServiceList{
1299			Node:     (*services).Node,
1300			Services: svcs,
1301		}
1302	}
1303}
1304
1305// filterCheckServiceNodes is used to filter nodes based on ACL rules.
1306func (f *aclFilter) filterCheckServiceNodes(nodes *structs.CheckServiceNodes) {
1307	csn := *nodes
1308	var authzContext acl.AuthorizerContext
1309
1310	for i := 0; i < len(csn); i++ {
1311		node := csn[i]
1312		node.Service.FillAuthzContext(&authzContext)
1313		if f.allowNode(node.Node.Node, &authzContext) && f.allowService(node.Service.Service, &authzContext) {
1314			continue
1315		}
1316		f.logger.Debug("dropping node from result due to ACLs", "node", node.Node.Node)
1317		csn = append(csn[:i], csn[i+1:]...)
1318		i--
1319	}
1320	*nodes = csn
1321}
1322
1323// filterSessions is used to filter a set of sessions based on ACLs.
1324func (f *aclFilter) filterSessions(sessions *structs.Sessions) {
1325	s := *sessions
1326	for i := 0; i < len(s); i++ {
1327		session := s[i]
1328
1329		var entCtx acl.AuthorizerContext
1330		session.FillAuthzContext(&entCtx)
1331
1332		if f.allowSession(session.Node, &entCtx) {
1333			continue
1334		}
1335		f.logger.Debug("dropping session from result due to ACLs", "session", session.ID)
1336		s = append(s[:i], s[i+1:]...)
1337		i--
1338	}
1339	*sessions = s
1340}
1341
1342// filterCoordinates is used to filter nodes in a coordinate dump based on ACL
1343// rules.
1344func (f *aclFilter) filterCoordinates(coords *structs.Coordinates) {
1345	c := *coords
1346	var authzContext acl.AuthorizerContext
1347	structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext)
1348
1349	for i := 0; i < len(c); i++ {
1350		node := c[i].Node
1351		if f.allowNode(node, &authzContext) {
1352			continue
1353		}
1354		f.logger.Debug("dropping node from result due to ACLs", "node", node)
1355		c = append(c[:i], c[i+1:]...)
1356		i--
1357	}
1358	*coords = c
1359}
1360
1361// filterIntentions is used to filter intentions based on ACL rules.
1362// We prune entries the user doesn't have access to, and we redact any tokens
1363// if the user doesn't have a management token.
1364func (f *aclFilter) filterIntentions(ixns *structs.Intentions) {
1365	ret := make(structs.Intentions, 0, len(*ixns))
1366	for _, ixn := range *ixns {
1367		if !ixn.CanRead(f.authorizer) {
1368			f.logger.Debug("dropping intention from result due to ACLs", "intention", ixn.ID)
1369			continue
1370		}
1371
1372		ret = append(ret, ixn)
1373	}
1374
1375	*ixns = ret
1376}
1377
1378// filterNodeDump is used to filter through all parts of a node dump and
1379// remove elements the provided ACL token cannot access.
1380func (f *aclFilter) filterNodeDump(dump *structs.NodeDump) {
1381	nd := *dump
1382
1383	var authzContext acl.AuthorizerContext
1384	for i := 0; i < len(nd); i++ {
1385		info := nd[i]
1386
1387		// Filter nodes
1388		structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext)
1389		if node := info.Node; !f.allowNode(node, &authzContext) {
1390			f.logger.Debug("dropping node from result due to ACLs", "node", node)
1391			nd = append(nd[:i], nd[i+1:]...)
1392			i--
1393			continue
1394		}
1395
1396		// Filter services
1397		for j := 0; j < len(info.Services); j++ {
1398			svc := info.Services[j].Service
1399			info.Services[j].FillAuthzContext(&authzContext)
1400			if f.allowNode(info.Node, &authzContext) && f.allowService(svc, &authzContext) {
1401				continue
1402			}
1403			f.logger.Debug("dropping service from result due to ACLs", "service", svc)
1404			info.Services = append(info.Services[:j], info.Services[j+1:]...)
1405			j--
1406		}
1407
1408		// Filter checks
1409		for j := 0; j < len(info.Checks); j++ {
1410			chk := info.Checks[j]
1411			chk.FillAuthzContext(&authzContext)
1412			if f.allowNode(info.Node, &authzContext) && f.allowService(chk.ServiceName, &authzContext) {
1413				continue
1414			}
1415			f.logger.Debug("dropping check from result due to ACLs", "check", chk.CheckID)
1416			info.Checks = append(info.Checks[:j], info.Checks[j+1:]...)
1417			j--
1418		}
1419	}
1420	*dump = nd
1421}
1422
1423// filterNodes is used to filter through all parts of a node list and remove
1424// elements the provided ACL token cannot access.
1425func (f *aclFilter) filterNodes(nodes *structs.Nodes) {
1426	n := *nodes
1427
1428	var authzContext acl.AuthorizerContext
1429	structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext)
1430
1431	for i := 0; i < len(n); i++ {
1432		node := n[i].Node
1433		if f.allowNode(node, &authzContext) {
1434			continue
1435		}
1436		f.logger.Debug("dropping node from result due to ACLs", "node", node)
1437		n = append(n[:i], n[i+1:]...)
1438		i--
1439	}
1440	*nodes = n
1441}
1442
1443// redactPreparedQueryTokens will redact any tokens unless the client has a
1444// management token. This eases the transition to delegated authority over
1445// prepared queries, since it was easy to capture management tokens in Consul
1446// 0.6.3 and earlier, and we don't want to willy-nilly show those. This does
1447// have the limitation of preventing delegated non-management users from seeing
1448// captured tokens, but they can at least see whether or not a token is set.
1449func (f *aclFilter) redactPreparedQueryTokens(query **structs.PreparedQuery) {
1450	// Management tokens can see everything with no filtering.
1451	var authzContext acl.AuthorizerContext
1452	structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext)
1453	if f.authorizer.ACLWrite(&authzContext) == acl.Allow {
1454		return
1455	}
1456
1457	// Let the user see if there's a blank token, otherwise we need
1458	// to redact it, since we know they don't have a management
1459	// token.
1460	if (*query).Token != "" {
1461		// Redact the token, using a copy of the query structure
1462		// since we could be pointed at a live instance from the
1463		// state store so it's not safe to modify it. Note that
1464		// this clone will still point to things like underlying
1465		// arrays in the original, but for modifying just the
1466		// token it will be safe to use.
1467		clone := *(*query)
1468		clone.Token = redactedToken
1469		*query = &clone
1470	}
1471}
1472
1473// filterPreparedQueries is used to filter prepared queries based on ACL rules.
1474// We prune entries the user doesn't have access to, and we redact any tokens
1475// if the user doesn't have a management token.
1476func (f *aclFilter) filterPreparedQueries(queries *structs.PreparedQueries) {
1477	var authzContext acl.AuthorizerContext
1478	structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext)
1479	// Management tokens can see everything with no filtering.
1480	// TODO  is this check even necessary - this looks like a search replace from
1481	// the 1.4 ACL rewrite. The global-management token will provide unrestricted query privileges
1482	// so asking for ACLWrite should be unnecessary.
1483	if f.authorizer.ACLWrite(&authzContext) == acl.Allow {
1484		return
1485	}
1486
1487	// Otherwise, we need to see what the token has access to.
1488	ret := make(structs.PreparedQueries, 0, len(*queries))
1489	for _, query := range *queries {
1490		// If no prefix ACL applies to this query then filter it, since
1491		// we know at this point the user doesn't have a management
1492		// token, otherwise see what the policy says.
1493		prefix, ok := query.GetACLPrefix()
1494		if !ok || f.authorizer.PreparedQueryRead(prefix, &authzContext) != acl.Allow {
1495			f.logger.Debug("dropping prepared query from result due to ACLs", "query", query.ID)
1496			continue
1497		}
1498
1499		// Redact any tokens if necessary. We make a copy of just the
1500		// pointer so we don't mess with the caller's slice.
1501		final := query
1502		f.redactPreparedQueryTokens(&final)
1503		ret = append(ret, final)
1504	}
1505	*queries = ret
1506}
1507
1508func (f *aclFilter) filterToken(token **structs.ACLToken) {
1509	var entCtx acl.AuthorizerContext
1510	if token == nil || *token == nil || f == nil {
1511		return
1512	}
1513
1514	(*token).FillAuthzContext(&entCtx)
1515
1516	if f.authorizer.ACLRead(&entCtx) != acl.Allow {
1517		// no permissions to read
1518		*token = nil
1519	} else if f.authorizer.ACLWrite(&entCtx) != acl.Allow {
1520		// no write permissions - redact secret
1521		clone := *(*token)
1522		clone.SecretID = redactedToken
1523		*token = &clone
1524	}
1525}
1526
1527func (f *aclFilter) filterTokens(tokens *structs.ACLTokens) {
1528	ret := make(structs.ACLTokens, 0, len(*tokens))
1529	for _, token := range *tokens {
1530		final := token
1531		f.filterToken(&final)
1532		if final != nil {
1533			ret = append(ret, final)
1534		}
1535	}
1536	*tokens = ret
1537}
1538
1539func (f *aclFilter) filterTokenStub(token **structs.ACLTokenListStub) {
1540	var entCtx acl.AuthorizerContext
1541	if token == nil || *token == nil || f == nil {
1542		return
1543	}
1544
1545	(*token).FillAuthzContext(&entCtx)
1546
1547	if f.authorizer.ACLRead(&entCtx) != acl.Allow {
1548		*token = nil
1549	}
1550}
1551
1552func (f *aclFilter) filterTokenStubs(tokens *[]*structs.ACLTokenListStub) {
1553	ret := make(structs.ACLTokenListStubs, 0, len(*tokens))
1554	for _, token := range *tokens {
1555		final := token
1556		f.filterTokenStub(&final)
1557		if final != nil {
1558			ret = append(ret, final)
1559		}
1560	}
1561	*tokens = ret
1562}
1563
1564func (f *aclFilter) filterPolicy(policy **structs.ACLPolicy) {
1565	var entCtx acl.AuthorizerContext
1566	if policy == nil || *policy == nil || f == nil {
1567		return
1568	}
1569
1570	(*policy).FillAuthzContext(&entCtx)
1571
1572	if f.authorizer.ACLRead(&entCtx) != acl.Allow {
1573		// no permissions to read
1574		*policy = nil
1575	}
1576}
1577
1578func (f *aclFilter) filterPolicies(policies *structs.ACLPolicies) {
1579	ret := make(structs.ACLPolicies, 0, len(*policies))
1580	for _, policy := range *policies {
1581		final := policy
1582		f.filterPolicy(&final)
1583		if final != nil {
1584			ret = append(ret, final)
1585		}
1586	}
1587	*policies = ret
1588}
1589
1590func (f *aclFilter) filterRole(role **structs.ACLRole) {
1591	var entCtx acl.AuthorizerContext
1592	if role == nil || *role == nil || f == nil {
1593		return
1594	}
1595
1596	(*role).FillAuthzContext(&entCtx)
1597
1598	if f.authorizer.ACLRead(&entCtx) != acl.Allow {
1599		// no permissions to read
1600		*role = nil
1601	}
1602}
1603
1604func (f *aclFilter) filterRoles(roles *structs.ACLRoles) {
1605	ret := make(structs.ACLRoles, 0, len(*roles))
1606	for _, role := range *roles {
1607		final := role
1608		f.filterRole(&final)
1609		if final != nil {
1610			ret = append(ret, final)
1611		}
1612	}
1613	*roles = ret
1614}
1615
1616func (f *aclFilter) filterBindingRule(rule **structs.ACLBindingRule) {
1617	var entCtx acl.AuthorizerContext
1618	if rule == nil || *rule == nil || f == nil {
1619		return
1620	}
1621
1622	(*rule).FillAuthzContext(&entCtx)
1623
1624	if f.authorizer.ACLRead(&entCtx) != acl.Allow {
1625		// no permissions to read
1626		*rule = nil
1627	}
1628}
1629
1630func (f *aclFilter) filterBindingRules(rules *structs.ACLBindingRules) {
1631	ret := make(structs.ACLBindingRules, 0, len(*rules))
1632	for _, rule := range *rules {
1633		final := rule
1634		f.filterBindingRule(&final)
1635		if final != nil {
1636			ret = append(ret, final)
1637		}
1638	}
1639	*rules = ret
1640}
1641
1642func (f *aclFilter) filterAuthMethod(method **structs.ACLAuthMethod) {
1643	var entCtx acl.AuthorizerContext
1644	if method == nil || *method == nil || f == nil {
1645		return
1646	}
1647
1648	(*method).FillAuthzContext(&entCtx)
1649
1650	if f.authorizer.ACLRead(&entCtx) != acl.Allow {
1651		// no permissions to read
1652		*method = nil
1653	}
1654}
1655
1656func (f *aclFilter) filterAuthMethods(methods *structs.ACLAuthMethods) {
1657	ret := make(structs.ACLAuthMethods, 0, len(*methods))
1658	for _, method := range *methods {
1659		final := method
1660		f.filterAuthMethod(&final)
1661		if final != nil {
1662			ret = append(ret, final)
1663		}
1664	}
1665	*methods = ret
1666}
1667
1668func (f *aclFilter) filterServiceList(services *structs.ServiceList) {
1669	ret := make(structs.ServiceList, 0, len(*services))
1670	for _, svc := range *services {
1671		var authzContext acl.AuthorizerContext
1672
1673		svc.FillAuthzContext(&authzContext)
1674
1675		if f.authorizer.ServiceRead(svc.Name, &authzContext) != acl.Allow {
1676			sid := structs.NewServiceID(svc.Name, &svc.EnterpriseMeta)
1677			f.logger.Debug("dropping service from result due to ACLs", "service", sid.String())
1678			continue
1679		}
1680
1681		ret = append(ret, svc)
1682	}
1683
1684	*services = ret
1685}
1686
1687func (r *ACLResolver) filterACLWithAuthorizer(authorizer acl.Authorizer, subj interface{}) error {
1688	if authorizer == nil {
1689		return nil
1690	}
1691	// Create the filter
1692	filt := newACLFilter(authorizer, r.logger, r.config.ACLEnforceVersion8)
1693
1694	switch v := subj.(type) {
1695	case *structs.CheckServiceNodes:
1696		filt.filterCheckServiceNodes(v)
1697
1698	case *structs.IndexedCheckServiceNodes:
1699		filt.filterCheckServiceNodes(&v.Nodes)
1700
1701	case *structs.IndexedCoordinates:
1702		filt.filterCoordinates(&v.Coordinates)
1703
1704	case *structs.IndexedHealthChecks:
1705		filt.filterHealthChecks(&v.HealthChecks)
1706
1707	case *structs.IndexedIntentions:
1708		filt.filterIntentions(&v.Intentions)
1709
1710	case *structs.IndexedNodeDump:
1711		filt.filterNodeDump(&v.Dump)
1712
1713	case *structs.IndexedNodes:
1714		filt.filterNodes(&v.Nodes)
1715
1716	case *structs.IndexedNodeServices:
1717		filt.filterNodeServices(&v.NodeServices)
1718
1719	case **structs.NodeServiceList:
1720		filt.filterNodeServiceList(v)
1721
1722	case *structs.IndexedServiceNodes:
1723		filt.filterServiceNodes(&v.ServiceNodes)
1724
1725	case *structs.IndexedServices:
1726		filt.filterServices(v.Services, &v.EnterpriseMeta)
1727
1728	case *structs.IndexedSessions:
1729		filt.filterSessions(&v.Sessions)
1730
1731	case *structs.IndexedPreparedQueries:
1732		filt.filterPreparedQueries(&v.Queries)
1733
1734	case **structs.PreparedQuery:
1735		filt.redactPreparedQueryTokens(v)
1736
1737	case *structs.ACLTokens:
1738		filt.filterTokens(v)
1739	case **structs.ACLToken:
1740		filt.filterToken(v)
1741	case *[]*structs.ACLTokenListStub:
1742		filt.filterTokenStubs(v)
1743	case **structs.ACLTokenListStub:
1744		filt.filterTokenStub(v)
1745
1746	case *structs.ACLPolicies:
1747		filt.filterPolicies(v)
1748	case **structs.ACLPolicy:
1749		filt.filterPolicy(v)
1750
1751	case *structs.ACLRoles:
1752		filt.filterRoles(v)
1753	case **structs.ACLRole:
1754		filt.filterRole(v)
1755
1756	case *structs.ACLBindingRules:
1757		filt.filterBindingRules(v)
1758	case **structs.ACLBindingRule:
1759		filt.filterBindingRule(v)
1760
1761	case *structs.ACLAuthMethods:
1762		filt.filterAuthMethods(v)
1763	case **structs.ACLAuthMethod:
1764		filt.filterAuthMethod(v)
1765
1766	case *structs.IndexedServiceList:
1767		filt.filterServiceList(&v.Services)
1768	default:
1769		panic(fmt.Errorf("Unhandled type passed to ACL filter: %T %#v", subj, subj))
1770	}
1771
1772	return nil
1773}
1774
1775// filterACL is used to filter results from our service catalog based on the
1776// rules configured for the provided token.
1777func (r *ACLResolver) filterACL(token string, subj interface{}) error {
1778	// Get the ACL from the token
1779	authorizer, err := r.ResolveToken(token)
1780	if err != nil {
1781		return err
1782	}
1783
1784	// Fast path if ACLs are not enabled
1785	if authorizer == nil {
1786		return nil
1787	}
1788
1789	return r.filterACLWithAuthorizer(authorizer, subj)
1790}
1791
1792// vetRegisterWithACL applies the given ACL's policy to the catalog update and
1793// determines if it is allowed. Since the catalog register request is so
1794// dynamic, this is a pretty complex algorithm and was worth breaking out of the
1795// endpoint. The NodeServices record for the node must be supplied, and can be
1796// nil.
1797//
1798// This is a bit racy because we have to check the state store outside of a
1799// transaction. It's the best we can do because we don't want to flow ACL
1800// checking down there. The node information doesn't change in practice, so this
1801// will be fine. If we expose ways to change node addresses in a later version,
1802// then we should split the catalog API at the node and service level so we can
1803// address this race better (even then it would be super rare, and would at
1804// worst let a service update revert a recent node update, so it doesn't open up
1805// too much abuse).
1806func vetRegisterWithACL(rule acl.Authorizer, subj *structs.RegisterRequest,
1807	ns *structs.NodeServices) error {
1808	// Fast path if ACLs are not enabled.
1809	if rule == nil {
1810		return nil
1811	}
1812
1813	var authzContext acl.AuthorizerContext
1814	subj.FillAuthzContext(&authzContext)
1815
1816	// Vet the node info. This allows service updates to re-post the required
1817	// node info for each request without having to have node "write"
1818	// privileges.
1819	needsNode := ns == nil || subj.ChangesNode(ns.Node)
1820
1821	if needsNode && rule.NodeWrite(subj.Node, &authzContext) != acl.Allow {
1822		return acl.ErrPermissionDenied
1823	}
1824
1825	// Vet the service change. This includes making sure they can register
1826	// the given service, and that we can write to any existing service that
1827	// is being modified by id (if any).
1828	if subj.Service != nil {
1829		if rule.ServiceWrite(subj.Service.Service, &authzContext) != acl.Allow {
1830			return acl.ErrPermissionDenied
1831		}
1832
1833		if ns != nil {
1834			other, ok := ns.Services[subj.Service.ID]
1835
1836			if ok {
1837				// This is effectively a delete, so we DO NOT apply the
1838				// sentinel scope to the service we are overwriting, just
1839				// the regular ACL policy.
1840				var secondaryCtx acl.AuthorizerContext
1841				other.FillAuthzContext(&secondaryCtx)
1842
1843				if rule.ServiceWrite(other.Service, &secondaryCtx) != acl.Allow {
1844					return acl.ErrPermissionDenied
1845				}
1846			}
1847		}
1848	}
1849
1850	// Make sure that the member was flattened before we got there. This
1851	// keeps us from having to verify this check as well.
1852	if subj.Check != nil {
1853		return fmt.Errorf("check member must be nil")
1854	}
1855
1856	// Vet the checks. Node-level checks require node write, and
1857	// service-level checks require service write.
1858	for _, check := range subj.Checks {
1859		// Make sure that the node matches - we don't allow you to mix
1860		// checks from other nodes because we'd have to pull a bunch
1861		// more state store data to check this. If ACLs are enabled then
1862		// we simply require them to match in a given request. There's a
1863		// note in state_store.go to ban this down there in Consul 0.8,
1864		// but it's good to leave this here because it's required for
1865		// correctness wrt. ACLs.
1866		if check.Node != subj.Node {
1867			return fmt.Errorf("Node '%s' for check '%s' doesn't match register request node '%s'",
1868				check.Node, check.CheckID, subj.Node)
1869		}
1870
1871		// Node-level check.
1872		if check.ServiceID == "" {
1873			if rule.NodeWrite(subj.Node, &authzContext) != acl.Allow {
1874				return acl.ErrPermissionDenied
1875			}
1876			continue
1877		}
1878
1879		// Service-level check, check the common case where it
1880		// matches the service part of this request, which has
1881		// already been vetted above, and might be being registered
1882		// along with its checks.
1883		if subj.Service != nil && subj.Service.ID == check.ServiceID {
1884			continue
1885		}
1886
1887		// Service-level check for some other service. Make sure they've
1888		// got write permissions for that service.
1889		if ns == nil {
1890			return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID)
1891		}
1892
1893		other, ok := ns.Services[check.ServiceID]
1894		if !ok {
1895			return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID)
1896		}
1897
1898		// We are only adding a check here, so we don't add the scope,
1899		// since the sentinel policy doesn't apply to adding checks at
1900		// this time.
1901		var secondaryCtx acl.AuthorizerContext
1902		other.FillAuthzContext(&secondaryCtx)
1903
1904		if rule.ServiceWrite(other.Service, &secondaryCtx) != acl.Allow {
1905			return acl.ErrPermissionDenied
1906		}
1907	}
1908
1909	return nil
1910}
1911
1912// vetDeregisterWithACL applies the given ACL's policy to the catalog update and
1913// determines if it is allowed. Since the catalog deregister request is so
1914// dynamic, this is a pretty complex algorithm and was worth breaking out of the
1915// endpoint. The NodeService for the referenced service must be supplied, and can
1916// be nil; similar for the HealthCheck for the referenced health check.
1917func vetDeregisterWithACL(rule acl.Authorizer, subj *structs.DeregisterRequest,
1918	ns *structs.NodeService, nc *structs.HealthCheck) error {
1919
1920	// Fast path if ACLs are not enabled.
1921	if rule == nil {
1922		return nil
1923	}
1924
1925	// We don't apply sentinel in this path, since at this time sentinel
1926	// only applies to create and update operations.
1927
1928	var authzContext acl.AuthorizerContext
1929	// fill with the defaults for use with the NodeWrite check
1930	subj.FillAuthzContext(&authzContext)
1931
1932	// Allow service deregistration if the token has write permission for the node.
1933	// This accounts for cases where the agent no longer has a token with write permission
1934	// on the service to deregister it.
1935	if rule.NodeWrite(subj.Node, &authzContext) == acl.Allow {
1936		return nil
1937	}
1938
1939	// This order must match the code in applyDeregister() in
1940	// fsm/commands_oss.go since it also evaluates things in this order,
1941	// and will ignore fields based on this precedence. This lets us also
1942	// ignore them from an ACL perspective.
1943	if subj.ServiceID != "" {
1944		if ns == nil {
1945			return fmt.Errorf("Unknown service '%s'", subj.ServiceID)
1946		}
1947
1948		ns.FillAuthzContext(&authzContext)
1949
1950		if rule.ServiceWrite(ns.Service, &authzContext) != acl.Allow {
1951			return acl.ErrPermissionDenied
1952		}
1953	} else if subj.CheckID != "" {
1954		if nc == nil {
1955			return fmt.Errorf("Unknown check '%s'", subj.CheckID)
1956		}
1957
1958		nc.FillAuthzContext(&authzContext)
1959
1960		if nc.ServiceID != "" {
1961			if rule.ServiceWrite(nc.ServiceName, &authzContext) != acl.Allow {
1962				return acl.ErrPermissionDenied
1963			}
1964		} else {
1965			if rule.NodeWrite(subj.Node, &authzContext) != acl.Allow {
1966				return acl.ErrPermissionDenied
1967			}
1968		}
1969	} else {
1970		// Since NodeWrite is not given - otherwise the earlier check
1971		// would've returned already - we can deny here.
1972		return acl.ErrPermissionDenied
1973	}
1974
1975	return nil
1976}
1977
1978// vetNodeTxnOp applies the given ACL policy to a node transaction operation.
1979func vetNodeTxnOp(op *structs.TxnNodeOp, rule acl.Authorizer) error {
1980	// Fast path if ACLs are not enabled.
1981	if rule == nil {
1982		return nil
1983	}
1984
1985	var authzContext acl.AuthorizerContext
1986	op.FillAuthzContext(&authzContext)
1987
1988	if rule != nil && rule.NodeWrite(op.Node.Node, &authzContext) != acl.Allow {
1989		return acl.ErrPermissionDenied
1990	}
1991
1992	return nil
1993}
1994
1995// vetServiceTxnOp applies the given ACL policy to a service transaction operation.
1996func vetServiceTxnOp(op *structs.TxnServiceOp, rule acl.Authorizer) error {
1997	// Fast path if ACLs are not enabled.
1998	if rule == nil {
1999		return nil
2000	}
2001
2002	var authzContext acl.AuthorizerContext
2003	op.FillAuthzContext(&authzContext)
2004
2005	if rule.ServiceWrite(op.Service.Service, &authzContext) != acl.Allow {
2006		return acl.ErrPermissionDenied
2007	}
2008
2009	return nil
2010}
2011
2012// vetCheckTxnOp applies the given ACL policy to a check transaction operation.
2013func vetCheckTxnOp(op *structs.TxnCheckOp, rule acl.Authorizer) error {
2014	// Fast path if ACLs are not enabled.
2015	if rule == nil {
2016		return nil
2017	}
2018
2019	var authzContext acl.AuthorizerContext
2020	op.FillAuthzContext(&authzContext)
2021
2022	if op.Check.ServiceID == "" {
2023		// Node-level check.
2024		if rule.NodeWrite(op.Check.Node, &authzContext) != acl.Allow {
2025			return acl.ErrPermissionDenied
2026		}
2027	} else {
2028		// Service-level check.
2029		if rule.ServiceWrite(op.Check.ServiceName, &authzContext) != acl.Allow {
2030			return acl.ErrPermissionDenied
2031		}
2032	}
2033
2034	return nil
2035}
2036