github.com/DerekStrickland/consul@v1.4.5/agent/consul/acl.go (about)

     1  package consul
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/armon/go-metrics"
    11  	"github.com/hashicorp/consul/acl"
    12  	"github.com/hashicorp/consul/agent/structs"
    13  	"github.com/hashicorp/consul/api"
    14  	"github.com/hashicorp/consul/sentinel"
    15  	"golang.org/x/sync/singleflight"
    16  	"golang.org/x/time/rate"
    17  )
    18  
    19  // These must be kept in sync with the constants in command/agent/acl.go.
    20  const (
    21  	// anonymousToken is the token ID we re-write to if there is no token ID
    22  	// provided.
    23  	anonymousToken = "anonymous"
    24  
    25  	// redactedToken is shown in structures with embedded tokens when they
    26  	// are not allowed to be displayed.
    27  	redactedToken = "<hidden>"
    28  
    29  	// aclUpgradeBatchSize controls how many tokens we look at during each round of upgrading. Individual raft logs
    30  	// will be further capped using the aclBatchUpsertSize. This limit just prevents us from creating a single slice
    31  	// with all tokens in it.
    32  	aclUpgradeBatchSize = 128
    33  
    34  	// aclUpgradeRateLimit is the number of batch upgrade requests per second.
    35  	aclUpgradeRateLimit rate.Limit = 1.0
    36  
    37  	// aclBatchDeleteSize is the number of deletions to send in a single batch operation. 4096 should produce a batch that is <150KB
    38  	// in size but should be sufficiently large to handle 1 replication round in a single batch
    39  	aclBatchDeleteSize = 4096
    40  
    41  	// aclBatchUpsertSize is the target size in bytes we want to submit for a batch upsert request. We estimate the size at runtime
    42  	// due to the data being more variable in its size.
    43  	aclBatchUpsertSize = 256 * 1024
    44  
    45  	// DEPRECATED (ACL-Legacy-Compat) aclModeCheck* are all only for legacy usage
    46  	// aclModeCheckMinInterval is the minimum amount of time between checking if the
    47  	// agent should be using the new or legacy ACL system. All the places it is
    48  	// currently used will backoff as it detects that it is remaining in legacy mode.
    49  	// However the initial min value is kept small so that new cluster creation
    50  	// can enter into new ACL mode quickly.
    51  	aclModeCheckMinInterval = 50 * time.Millisecond
    52  
    53  	// aclModeCheckMaxInterval controls the maximum interval for how often the agent
    54  	// checks if it should be using the new or legacy ACL system.
    55  	aclModeCheckMaxInterval = 30 * time.Second
    56  
    57  	// Maximum number of re-resolution requests to be made if the token is modified between
    58  	// resolving the token and resolving its policies that would remove one of its policies.
    59  	tokenPolicyResolutionMaxRetries = 5
    60  )
    61  
    62  func minTTL(a time.Duration, b time.Duration) time.Duration {
    63  	if a < b {
    64  		return a
    65  	}
    66  	return b
    67  }
    68  
    69  type ACLRemoteError struct {
    70  	Err error
    71  }
    72  
    73  func (e ACLRemoteError) Error() string {
    74  	return fmt.Sprintf("Error communicating with the ACL Datacenter: %v", e.Err)
    75  }
    76  
    77  func IsACLRemoteError(err error) bool {
    78  	_, ok := err.(ACLRemoteError)
    79  	return ok
    80  }
    81  
    82  type ACLResolverDelegate interface {
    83  	ACLsEnabled() bool
    84  	ACLDatacenter(legacy bool) string
    85  	UseLegacyACLs() bool
    86  	ResolveIdentityFromToken(token string) (bool, structs.ACLIdentity, error)
    87  	ResolvePolicyFromID(policyID string) (bool, *structs.ACLPolicy, error)
    88  	RPC(method string, args interface{}, reply interface{}) error
    89  }
    90  
    91  type policyTokenError struct {
    92  	Err   error
    93  	token string
    94  }
    95  
    96  func (e policyTokenError) Error() string {
    97  	return e.Err.Error()
    98  }
    99  
   100  // ACLResolverConfig holds all the configuration necessary to create an ACLResolver
   101  type ACLResolverConfig struct {
   102  	Config *Config
   103  	Logger *log.Logger
   104  
   105  	// CacheConfig is a pass through configuration for ACL cache limits
   106  	CacheConfig *structs.ACLCachesConfig
   107  
   108  	// Delegate that implements some helper functionality that is server/client specific
   109  	Delegate ACLResolverDelegate
   110  
   111  	// AutoDisable indicates that RPC responses should be checked and if they indicate ACLs are disabled
   112  	// remotely then disable them locally as well. This is particularly useful for the client agent
   113  	// so that it can detect when the servers have gotten ACLs enabled.
   114  	AutoDisable bool
   115  
   116  	Sentinel sentinel.Evaluator
   117  }
   118  
   119  // ACLResolver is the type to handle all your token and policy resolution needs.
   120  //
   121  // Supports:
   122  //   - Resolving tokens locally via the ACLResolverDelegate
   123  //   - Resolving policies locally via the ACLResolverDelegate
   124  //   - Resolving legacy tokens remotely via a ACL.GetPolicy RPC
   125  //   - Resolving tokens remotely via an ACL.TokenRead RPC
   126  //   - Resolving policies remotely via an ACL.PolicyResolve RPC
   127  //
   128  // Remote Resolution:
   129  //   Remote resolution can be done syncrhonously or asynchronously depending
   130  //   on the ACLDownPolicy in the Config passed to the resolver.
   131  //
   132  //   When the down policy is set to async-cache and we have already cached values
   133  //   then go routines will be spawned to perform the RPCs in the background
   134  //   and then will update the cache with either the positive or negative result.
   135  //
   136  //   When the down policy is set to extend-cache or the token/policy is not already
   137  //   cached then the same go routines are spawned to do the RPCs in the background.
   138  //   However in this mode channels are created to receive the results of the RPC
   139  //   and are registered with the resolver. Those channels are immediately read/blocked
   140  //   upon.
   141  //
   142  type ACLResolver struct {
   143  	config *Config
   144  	logger *log.Logger
   145  
   146  	delegate ACLResolverDelegate
   147  	sentinel sentinel.Evaluator
   148  
   149  	cache         *structs.ACLCaches
   150  	identityGroup singleflight.Group
   151  	policyGroup   singleflight.Group
   152  	legacyGroup   singleflight.Group
   153  
   154  	down acl.Authorizer
   155  
   156  	autoDisable  bool
   157  	disabled     time.Time
   158  	disabledLock sync.RWMutex
   159  }
   160  
   161  func NewACLResolver(config *ACLResolverConfig) (*ACLResolver, error) {
   162  	if config == nil {
   163  		return nil, fmt.Errorf("ACL Resolver must be initialized with a config")
   164  	}
   165  
   166  	if config.Config == nil {
   167  		return nil, fmt.Errorf("ACLResolverConfig.Config must not be nil")
   168  	}
   169  
   170  	if config.Delegate == nil {
   171  		return nil, fmt.Errorf("ACL Resolver must be initialized with a valid delegate")
   172  	}
   173  
   174  	if config.Logger == nil {
   175  		config.Logger = log.New(os.Stderr, "", log.LstdFlags)
   176  	}
   177  
   178  	cache, err := structs.NewACLCaches(config.CacheConfig)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	var down acl.Authorizer
   184  	switch config.Config.ACLDownPolicy {
   185  	case "allow":
   186  		down = acl.AllowAll()
   187  	case "deny":
   188  		down = acl.DenyAll()
   189  	case "async-cache", "extend-cache":
   190  		// Leave the down policy as nil to signal this.
   191  	default:
   192  		return nil, fmt.Errorf("invalid ACL down policy %q", config.Config.ACLDownPolicy)
   193  	}
   194  
   195  	return &ACLResolver{
   196  		config:      config.Config,
   197  		logger:      config.Logger,
   198  		delegate:    config.Delegate,
   199  		sentinel:    config.Sentinel,
   200  		cache:       cache,
   201  		autoDisable: config.AutoDisable,
   202  		down:        down,
   203  	}, nil
   204  }
   205  
   206  func (r *ACLResolver) fetchAndCacheTokenLegacy(token string, cached *structs.AuthorizerCacheEntry) (acl.Authorizer, error) {
   207  	req := structs.ACLPolicyResolveLegacyRequest{
   208  		Datacenter: r.delegate.ACLDatacenter(true),
   209  		ACL:        token,
   210  	}
   211  
   212  	cacheTTL := r.config.ACLTokenTTL
   213  	if cached != nil {
   214  		cacheTTL = cached.TTL
   215  	}
   216  
   217  	var reply structs.ACLPolicyResolveLegacyResponse
   218  	err := r.delegate.RPC("ACL.GetPolicy", &req, &reply)
   219  	if err == nil {
   220  		parent := acl.RootAuthorizer(reply.Parent)
   221  		if parent == nil {
   222  			var authorizer acl.Authorizer
   223  			if cached != nil {
   224  				authorizer = cached.Authorizer
   225  			}
   226  			r.cache.PutAuthorizerWithTTL(token, authorizer, cacheTTL)
   227  			return authorizer, acl.ErrInvalidParent
   228  		}
   229  
   230  		var policies []*acl.Policy
   231  		policy := reply.Policy
   232  		if policy != nil {
   233  			policies = append(policies, policy.ConvertFromLegacy())
   234  		}
   235  
   236  		authorizer, err := acl.NewPolicyAuthorizer(parent, policies, r.sentinel)
   237  
   238  		r.cache.PutAuthorizerWithTTL(token, authorizer, reply.TTL)
   239  		return authorizer, err
   240  	}
   241  
   242  	if acl.IsErrNotFound(err) {
   243  		// Make sure to remove from the cache if it was deleted
   244  		r.cache.PutAuthorizerWithTTL(token, nil, cacheTTL)
   245  		return nil, acl.ErrNotFound
   246  
   247  	}
   248  
   249  	// some other RPC error
   250  	switch r.config.ACLDownPolicy {
   251  	case "allow":
   252  		r.cache.PutAuthorizerWithTTL(token, acl.AllowAll(), cacheTTL)
   253  		return acl.AllowAll(), nil
   254  	case "async-cache", "extend-cache":
   255  		if cached != nil {
   256  			r.cache.PutAuthorizerWithTTL(token, cached.Authorizer, cacheTTL)
   257  			return cached.Authorizer, nil
   258  		}
   259  		fallthrough
   260  	default:
   261  		r.cache.PutAuthorizerWithTTL(token, acl.DenyAll(), cacheTTL)
   262  		return acl.DenyAll(), nil
   263  	}
   264  }
   265  
   266  func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) {
   267  	defer metrics.MeasureSince([]string{"acl", "resolveTokenLegacy"}, time.Now())
   268  
   269  	// Attempt to resolve locally first (local results are not cached)
   270  	// This is only useful for servers where either legacy replication is being
   271  	// done or the server is within the primary datacenter.
   272  	if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done {
   273  		if err == nil && identity != nil {
   274  			policies, err := r.resolvePoliciesForIdentity(identity)
   275  			if err != nil {
   276  				return nil, err
   277  			}
   278  
   279  			return policies.Compile(acl.RootAuthorizer(r.config.ACLDefaultPolicy), r.cache, r.sentinel)
   280  		}
   281  
   282  		return nil, err
   283  	}
   284  
   285  	// Look in the cache prior to making a RPC request
   286  	entry := r.cache.GetAuthorizer(token)
   287  
   288  	if entry != nil && entry.Age() <= minTTL(entry.TTL, r.config.ACLTokenTTL) {
   289  		metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1)
   290  		if entry.Authorizer != nil {
   291  			return entry.Authorizer, nil
   292  		}
   293  		return nil, acl.ErrNotFound
   294  	}
   295  
   296  	metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1)
   297  
   298  	// Resolve the token in the background and wait on the result if we must
   299  	waitChan := r.legacyGroup.DoChan(token, func() (interface{}, error) {
   300  		authorizer, err := r.fetchAndCacheTokenLegacy(token, entry)
   301  		return authorizer, err
   302  	})
   303  
   304  	waitForResult := entry == nil || r.config.ACLDownPolicy != "async-cache"
   305  	if !waitForResult {
   306  		// waitForResult being false requires the cacheEntry to not be nil
   307  		if entry.Authorizer != nil {
   308  			return entry.Authorizer, nil
   309  		}
   310  		return nil, acl.ErrNotFound
   311  	}
   312  
   313  	// block waiting for the async RPC to finish.
   314  	res := <-waitChan
   315  
   316  	var authorizer acl.Authorizer
   317  	if res.Val != nil { // avoid a nil-not-nil bug
   318  		authorizer = res.Val.(acl.Authorizer)
   319  	}
   320  
   321  	return authorizer, res.Err
   322  }
   323  
   324  func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) {
   325  	req := structs.ACLTokenGetRequest{
   326  		Datacenter:  r.delegate.ACLDatacenter(false),
   327  		TokenID:     token,
   328  		TokenIDType: structs.ACLTokenSecret,
   329  		QueryOptions: structs.QueryOptions{
   330  			Token:      token,
   331  			AllowStale: true,
   332  		},
   333  	}
   334  
   335  	var resp structs.ACLTokenResponse
   336  	err := r.delegate.RPC("ACL.TokenRead", &req, &resp)
   337  	if err == nil {
   338  		if resp.Token == nil {
   339  			r.cache.PutIdentity(token, nil)
   340  			return nil, acl.ErrNotFound
   341  		} else {
   342  			r.cache.PutIdentity(token, resp.Token)
   343  			return resp.Token, nil
   344  		}
   345  	}
   346  
   347  	if acl.IsErrNotFound(err) {
   348  		// Make sure to remove from the cache if it was deleted
   349  		r.cache.PutIdentity(token, nil)
   350  		return nil, acl.ErrNotFound
   351  
   352  	}
   353  
   354  	// some other RPC error
   355  	if cached != nil && (r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache") {
   356  		// extend the cache
   357  		r.cache.PutIdentity(token, cached.Identity)
   358  		return cached.Identity, nil
   359  	}
   360  
   361  	r.cache.PutIdentity(token, nil)
   362  	return nil, err
   363  }
   364  
   365  func (r *ACLResolver) resolveIdentityFromToken(token string) (structs.ACLIdentity, error) {
   366  	// Attempt to resolve locally first (local results are not cached)
   367  	if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done {
   368  		return identity, err
   369  	}
   370  
   371  	// Check the cache before making any RPC requests
   372  	cacheEntry := r.cache.GetIdentity(token)
   373  	if cacheEntry != nil && cacheEntry.Age() <= r.config.ACLTokenTTL {
   374  		metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1)
   375  		return cacheEntry.Identity, nil
   376  	}
   377  
   378  	metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1)
   379  
   380  	// Background a RPC request and wait on it if we must
   381  	waitChan := r.identityGroup.DoChan(token, func() (interface{}, error) {
   382  		identity, err := r.fetchAndCacheIdentityFromToken(token, cacheEntry)
   383  		return identity, err
   384  	})
   385  
   386  	waitForResult := cacheEntry == nil || r.config.ACLDownPolicy != "async-cache"
   387  	if !waitForResult {
   388  		// waitForResult being false requires the cacheEntry to not be nil
   389  		return cacheEntry.Identity, nil
   390  	}
   391  
   392  	// block on the read here, this is why we don't need chan buffering
   393  	res := <-waitChan
   394  
   395  	var identity structs.ACLIdentity
   396  	if res.Val != nil { // avoid a nil-not-nil bug
   397  		identity = res.Val.(structs.ACLIdentity)
   398  	}
   399  
   400  	if res.Err != nil && !acl.IsErrNotFound(res.Err) {
   401  		return identity, ACLRemoteError{Err: res.Err}
   402  	}
   403  	return identity, res.Err
   404  }
   405  
   406  func (r *ACLResolver) fetchAndCachePoliciesForIdentity(identity structs.ACLIdentity, policyIDs []string, cached map[string]*structs.PolicyCacheEntry) (map[string]*structs.ACLPolicy, error) {
   407  	req := structs.ACLPolicyBatchGetRequest{
   408  		Datacenter: r.delegate.ACLDatacenter(false),
   409  		PolicyIDs:  policyIDs,
   410  		QueryOptions: structs.QueryOptions{
   411  			Token:      identity.SecretToken(),
   412  			AllowStale: true,
   413  		},
   414  	}
   415  
   416  	var resp structs.ACLPolicyBatchResponse
   417  	err := r.delegate.RPC("ACL.PolicyResolve", &req, &resp)
   418  	if err == nil {
   419  		out := make(map[string]*structs.ACLPolicy)
   420  		for _, policy := range resp.Policies {
   421  			out[policy.ID] = policy
   422  		}
   423  
   424  		for _, policyID := range policyIDs {
   425  			if policy, ok := out[policyID]; ok {
   426  				r.cache.PutPolicy(policyID, policy)
   427  			} else {
   428  				r.cache.PutPolicy(policyID, nil)
   429  			}
   430  		}
   431  		return out, nil
   432  	}
   433  
   434  	if acl.IsErrNotFound(err) {
   435  		// make sure to indicate that this identity is no longer valid within
   436  		// the cache
   437  		r.cache.PutIdentity(identity.SecretToken(), nil)
   438  
   439  		// Do not touch the policy cache. Getting a top level ACL not found error
   440  		// only indicates that the secret token used in the request
   441  		// no longer exists
   442  		return nil, &policyTokenError{acl.ErrNotFound, identity.SecretToken()}
   443  	}
   444  
   445  	if acl.IsErrPermissionDenied(err) {
   446  		// invalidate our ID cache so that identity resolution will take place
   447  		// again in the future
   448  		r.cache.RemoveIdentity(identity.SecretToken())
   449  
   450  		// Do not remove from the policy cache for permission denied
   451  		// what this does indicate is that our view of the token is out of date
   452  		return nil, &policyTokenError{acl.ErrPermissionDenied, identity.SecretToken()}
   453  	}
   454  
   455  	// other RPC error - use cache if available
   456  
   457  	extendCache := r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache"
   458  
   459  	out := make(map[string]*structs.ACLPolicy)
   460  	insufficientCache := false
   461  	for _, policyID := range policyIDs {
   462  		if entry, ok := cached[policyID]; extendCache && ok {
   463  			r.cache.PutPolicy(policyID, entry.Policy)
   464  			if entry.Policy != nil {
   465  				out[policyID] = entry.Policy
   466  			}
   467  		} else {
   468  			r.cache.PutPolicy(policyID, nil)
   469  			insufficientCache = true
   470  		}
   471  	}
   472  	if insufficientCache {
   473  		return nil, ACLRemoteError{Err: err}
   474  	}
   475  	return out, nil
   476  }
   477  
   478  func (r *ACLResolver) filterPoliciesByScope(policies structs.ACLPolicies) structs.ACLPolicies {
   479  	var out structs.ACLPolicies
   480  	for _, policy := range policies {
   481  		if len(policy.Datacenters) == 0 {
   482  			out = append(out, policy)
   483  			continue
   484  		}
   485  
   486  		for _, dc := range policy.Datacenters {
   487  			if dc == r.config.Datacenter {
   488  				out = append(out, policy)
   489  				continue
   490  			}
   491  		}
   492  	}
   493  
   494  	return out
   495  }
   496  
   497  func (r *ACLResolver) resolvePoliciesForIdentity(identity structs.ACLIdentity) (structs.ACLPolicies, error) {
   498  	policyIDs := identity.PolicyIDs()
   499  	if len(policyIDs) == 0 {
   500  		policy := identity.EmbeddedPolicy()
   501  		if policy != nil {
   502  			return []*structs.ACLPolicy{policy}, nil
   503  		}
   504  
   505  		// In this case the default policy will be all that is in effect.
   506  		return nil, nil
   507  	}
   508  
   509  	// For the new ACLs policy replication is mandatory for correct operation on servers. Therefore
   510  	// we only attempt to resolve policies locally
   511  	policies := make([]*structs.ACLPolicy, 0, len(policyIDs))
   512  
   513  	// Get all associated policies
   514  	var missing []string
   515  	var expired []*structs.ACLPolicy
   516  	expCacheMap := make(map[string]*structs.PolicyCacheEntry)
   517  
   518  	for _, policyID := range policyIDs {
   519  		if done, policy, err := r.delegate.ResolvePolicyFromID(policyID); done {
   520  			if err != nil && !acl.IsErrNotFound(err) {
   521  				return nil, err
   522  			}
   523  
   524  			if policy != nil {
   525  				policies = append(policies, policy)
   526  			} else {
   527  				r.logger.Printf("[WARN] acl: policy %q not found for identity %q", policyID, identity.ID())
   528  			}
   529  
   530  			continue
   531  		}
   532  
   533  		// create the missing list which we can execute an RPC to get all the missing policies at once
   534  		entry := r.cache.GetPolicy(policyID)
   535  		if entry == nil {
   536  			missing = append(missing, policyID)
   537  			continue
   538  		}
   539  
   540  		if entry.Policy == nil {
   541  			// this happens when we cache a negative response for the policies existence
   542  			continue
   543  		}
   544  
   545  		if entry.Age() >= r.config.ACLPolicyTTL {
   546  			expired = append(expired, entry.Policy)
   547  			expCacheMap[policyID] = entry
   548  		} else {
   549  			policies = append(policies, entry.Policy)
   550  		}
   551  	}
   552  
   553  	// Hot-path if we have no missing or expired policies
   554  	if len(missing)+len(expired) == 0 {
   555  		return r.filterPoliciesByScope(policies), nil
   556  	}
   557  
   558  	hasMissing := len(missing) > 0
   559  
   560  	fetchIDs := missing
   561  	for _, policy := range expired {
   562  		fetchIDs = append(fetchIDs, policy.ID)
   563  	}
   564  
   565  	// Background a RPC request and wait on it if we must
   566  	waitChan := r.policyGroup.DoChan(identity.SecretToken(), func() (interface{}, error) {
   567  		policies, err := r.fetchAndCachePoliciesForIdentity(identity, fetchIDs, expCacheMap)
   568  		return policies, err
   569  	})
   570  
   571  	waitForResult := hasMissing || r.config.ACLDownPolicy != "async-cache"
   572  	if !waitForResult {
   573  		// waitForResult being false requires that all the policies were cached already
   574  		policies = append(policies, expired...)
   575  		return r.filterPoliciesByScope(policies), nil
   576  	}
   577  
   578  	res := <-waitChan
   579  
   580  	if res.Err != nil {
   581  		return nil, res.Err
   582  	}
   583  
   584  	if res.Val != nil {
   585  		foundPolicies := res.Val.(map[string]*structs.ACLPolicy)
   586  
   587  		for _, policy := range foundPolicies {
   588  			policies = append(policies, policy)
   589  		}
   590  	}
   591  
   592  	return r.filterPoliciesByScope(policies), nil
   593  }
   594  
   595  func (r *ACLResolver) resolveTokenToPolicies(token string) (structs.ACLPolicies, error) {
   596  	_, policies, err := r.resolveTokenToIdentityAndPolicies(token)
   597  	return policies, err
   598  }
   599  
   600  func (r *ACLResolver) resolveTokenToIdentityAndPolicies(token string) (structs.ACLIdentity, structs.ACLPolicies, error) {
   601  	var lastErr error
   602  	var lastIdentity structs.ACLIdentity
   603  
   604  	for i := 0; i < tokenPolicyResolutionMaxRetries; i++ {
   605  		// Resolve the token to an ACLIdentity
   606  		identity, err := r.resolveIdentityFromToken(token)
   607  		if err != nil {
   608  			return nil, nil, err
   609  		} else if identity == nil {
   610  			return nil, nil, acl.ErrNotFound
   611  		}
   612  
   613  		lastIdentity = identity
   614  
   615  		policies, err := r.resolvePoliciesForIdentity(identity)
   616  		if err == nil {
   617  			return identity, policies, nil
   618  		}
   619  		lastErr = err
   620  
   621  		if tokenErr, ok := err.(*policyTokenError); ok {
   622  			if acl.IsErrNotFound(err) && tokenErr.token == identity.SecretToken() {
   623  				// token was deleted while resolving policies
   624  				return nil, nil, acl.ErrNotFound
   625  			}
   626  
   627  			// other types of policyTokenErrors should cause retrying the whole token
   628  			// resolution process
   629  		} else {
   630  			return identity, nil, err
   631  		}
   632  	}
   633  
   634  	return lastIdentity, nil, lastErr
   635  }
   636  
   637  func (r *ACLResolver) disableACLsWhenUpstreamDisabled(err error) error {
   638  	if !r.autoDisable || err == nil || !acl.IsErrDisabled(err) {
   639  		return err
   640  	}
   641  
   642  	r.logger.Printf("[DEBUG] acl: ACLs disabled on upstream servers, will check again after %s", r.config.ACLDisabledTTL)
   643  	r.disabledLock.Lock()
   644  	r.disabled = time.Now().Add(r.config.ACLDisabledTTL)
   645  	r.disabledLock.Unlock()
   646  
   647  	return err
   648  }
   649  
   650  func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) {
   651  	if !r.ACLsEnabled() {
   652  		return nil, nil
   653  	}
   654  
   655  	if acl.RootAuthorizer(token) != nil {
   656  		return nil, acl.ErrRootDenied
   657  	}
   658  
   659  	// handle the anonymous token
   660  	if token == "" {
   661  		token = anonymousToken
   662  	}
   663  
   664  	if r.delegate.UseLegacyACLs() {
   665  		authorizer, err := r.resolveTokenLegacy(token)
   666  		return authorizer, r.disableACLsWhenUpstreamDisabled(err)
   667  	}
   668  
   669  	defer metrics.MeasureSince([]string{"acl", "ResolveToken"}, time.Now())
   670  
   671  	policies, err := r.resolveTokenToPolicies(token)
   672  	if err != nil {
   673  		r.disableACLsWhenUpstreamDisabled(err)
   674  		if IsACLRemoteError(err) {
   675  			r.logger.Printf("[ERR] consul.acl: %v", err)
   676  			return r.down, nil
   677  		}
   678  
   679  		return nil, err
   680  	}
   681  
   682  	// Build the Authorizer
   683  	authorizer, err := policies.Compile(acl.RootAuthorizer(r.config.ACLDefaultPolicy), r.cache, r.sentinel)
   684  	return authorizer, err
   685  
   686  }
   687  
   688  func (r *ACLResolver) ACLsEnabled() bool {
   689  	// Whether we desire ACLs to be enabled according to configuration
   690  	if !r.delegate.ACLsEnabled() {
   691  		return false
   692  	}
   693  
   694  	if r.autoDisable {
   695  		// Whether ACLs are disabled according to RPCs failing with a ACLs Disabled error
   696  		r.disabledLock.RLock()
   697  		defer r.disabledLock.RUnlock()
   698  		return !time.Now().Before(r.disabled)
   699  	}
   700  
   701  	return true
   702  }
   703  
   704  func (r *ACLResolver) GetMergedPolicyForToken(token string) (*acl.Policy, error) {
   705  	policies, err := r.resolveTokenToPolicies(token)
   706  	if err != nil {
   707  		return nil, err
   708  	}
   709  	if len(policies) == 0 {
   710  		return nil, acl.ErrNotFound
   711  	}
   712  
   713  	return policies.Merge(r.cache, r.sentinel)
   714  }
   715  
   716  // aclFilter is used to filter results from our state store based on ACL rules
   717  // configured for the provided token.
   718  type aclFilter struct {
   719  	authorizer      acl.Authorizer
   720  	logger          *log.Logger
   721  	enforceVersion8 bool
   722  }
   723  
   724  // newACLFilter constructs a new aclFilter.
   725  func newACLFilter(authorizer acl.Authorizer, logger *log.Logger, enforceVersion8 bool) *aclFilter {
   726  	if logger == nil {
   727  		logger = log.New(os.Stderr, "", log.LstdFlags)
   728  	}
   729  	return &aclFilter{
   730  		authorizer:      authorizer,
   731  		logger:          logger,
   732  		enforceVersion8: enforceVersion8,
   733  	}
   734  }
   735  
   736  // allowNode is used to determine if a node is accessible for an ACL.
   737  func (f *aclFilter) allowNode(node string) bool {
   738  	if !f.enforceVersion8 {
   739  		return true
   740  	}
   741  	return f.authorizer.NodeRead(node)
   742  }
   743  
   744  // allowService is used to determine if a service is accessible for an ACL.
   745  func (f *aclFilter) allowService(service string) bool {
   746  	if service == "" {
   747  		return true
   748  	}
   749  
   750  	if !f.enforceVersion8 && service == structs.ConsulServiceID {
   751  		return true
   752  	}
   753  	return f.authorizer.ServiceRead(service)
   754  }
   755  
   756  // allowSession is used to determine if a session for a node is accessible for
   757  // an ACL.
   758  func (f *aclFilter) allowSession(node string) bool {
   759  	if !f.enforceVersion8 {
   760  		return true
   761  	}
   762  	return f.authorizer.SessionRead(node)
   763  }
   764  
   765  // filterHealthChecks is used to filter a set of health checks down based on
   766  // the configured ACL rules for a token.
   767  func (f *aclFilter) filterHealthChecks(checks *structs.HealthChecks) {
   768  	hc := *checks
   769  	for i := 0; i < len(hc); i++ {
   770  		check := hc[i]
   771  		if f.allowNode(check.Node) && f.allowService(check.ServiceName) {
   772  			continue
   773  		}
   774  		f.logger.Printf("[DEBUG] consul: dropping check %q from result due to ACLs", check.CheckID)
   775  		hc = append(hc[:i], hc[i+1:]...)
   776  		i--
   777  	}
   778  	*checks = hc
   779  }
   780  
   781  // filterServices is used to filter a set of services based on ACLs.
   782  func (f *aclFilter) filterServices(services structs.Services) {
   783  	for svc := range services {
   784  		if f.allowService(svc) {
   785  			continue
   786  		}
   787  		f.logger.Printf("[DEBUG] consul: dropping service %q from result due to ACLs", svc)
   788  		delete(services, svc)
   789  	}
   790  }
   791  
   792  // filterServiceNodes is used to filter a set of nodes for a given service
   793  // based on the configured ACL rules.
   794  func (f *aclFilter) filterServiceNodes(nodes *structs.ServiceNodes) {
   795  	sn := *nodes
   796  	for i := 0; i < len(sn); i++ {
   797  		node := sn[i]
   798  		if f.allowNode(node.Node) && f.allowService(node.ServiceName) {
   799  			continue
   800  		}
   801  		f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node.Node)
   802  		sn = append(sn[:i], sn[i+1:]...)
   803  		i--
   804  	}
   805  	*nodes = sn
   806  }
   807  
   808  // filterNodeServices is used to filter services on a given node base on ACLs.
   809  func (f *aclFilter) filterNodeServices(services **structs.NodeServices) {
   810  	if *services == nil {
   811  		return
   812  	}
   813  
   814  	if !f.allowNode((*services).Node.Node) {
   815  		*services = nil
   816  		return
   817  	}
   818  
   819  	for svc := range (*services).Services {
   820  		if f.allowService(svc) {
   821  			continue
   822  		}
   823  		f.logger.Printf("[DEBUG] consul: dropping service %q from result due to ACLs", svc)
   824  		delete((*services).Services, svc)
   825  	}
   826  }
   827  
   828  // filterCheckServiceNodes is used to filter nodes based on ACL rules.
   829  func (f *aclFilter) filterCheckServiceNodes(nodes *structs.CheckServiceNodes) {
   830  	csn := *nodes
   831  	for i := 0; i < len(csn); i++ {
   832  		node := csn[i]
   833  		if f.allowNode(node.Node.Node) && f.allowService(node.Service.Service) {
   834  			continue
   835  		}
   836  		f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node.Node.Node)
   837  		csn = append(csn[:i], csn[i+1:]...)
   838  		i--
   839  	}
   840  	*nodes = csn
   841  }
   842  
   843  // filterSessions is used to filter a set of sessions based on ACLs.
   844  func (f *aclFilter) filterSessions(sessions *structs.Sessions) {
   845  	s := *sessions
   846  	for i := 0; i < len(s); i++ {
   847  		session := s[i]
   848  		if f.allowSession(session.Node) {
   849  			continue
   850  		}
   851  		f.logger.Printf("[DEBUG] consul: dropping session %q from result due to ACLs", session.ID)
   852  		s = append(s[:i], s[i+1:]...)
   853  		i--
   854  	}
   855  	*sessions = s
   856  }
   857  
   858  // filterCoordinates is used to filter nodes in a coordinate dump based on ACL
   859  // rules.
   860  func (f *aclFilter) filterCoordinates(coords *structs.Coordinates) {
   861  	c := *coords
   862  	for i := 0; i < len(c); i++ {
   863  		node := c[i].Node
   864  		if f.allowNode(node) {
   865  			continue
   866  		}
   867  		f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node)
   868  		c = append(c[:i], c[i+1:]...)
   869  		i--
   870  	}
   871  	*coords = c
   872  }
   873  
   874  // filterIntentions is used to filter intentions based on ACL rules.
   875  // We prune entries the user doesn't have access to, and we redact any tokens
   876  // if the user doesn't have a management token.
   877  func (f *aclFilter) filterIntentions(ixns *structs.Intentions) {
   878  	// Management tokens can see everything with no filtering.
   879  	if f.authorizer.ACLRead() {
   880  		return
   881  	}
   882  
   883  	// Otherwise, we need to see what the token has access to.
   884  	ret := make(structs.Intentions, 0, len(*ixns))
   885  	for _, ixn := range *ixns {
   886  		// If no prefix ACL applies to this then filter it, since
   887  		// we know at this point the user doesn't have a management
   888  		// token, otherwise see what the policy says.
   889  		prefix, ok := ixn.GetACLPrefix()
   890  		if !ok || !f.authorizer.IntentionRead(prefix) {
   891  			f.logger.Printf("[DEBUG] consul: dropping intention %q from result due to ACLs", ixn.ID)
   892  			continue
   893  		}
   894  
   895  		ret = append(ret, ixn)
   896  	}
   897  
   898  	*ixns = ret
   899  }
   900  
   901  // filterNodeDump is used to filter through all parts of a node dump and
   902  // remove elements the provided ACL token cannot access.
   903  func (f *aclFilter) filterNodeDump(dump *structs.NodeDump) {
   904  	nd := *dump
   905  	for i := 0; i < len(nd); i++ {
   906  		info := nd[i]
   907  
   908  		// Filter nodes
   909  		if node := info.Node; !f.allowNode(node) {
   910  			f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node)
   911  			nd = append(nd[:i], nd[i+1:]...)
   912  			i--
   913  			continue
   914  		}
   915  
   916  		// Filter services
   917  		for j := 0; j < len(info.Services); j++ {
   918  			svc := info.Services[j].Service
   919  			if f.allowService(svc) {
   920  				continue
   921  			}
   922  			f.logger.Printf("[DEBUG] consul: dropping service %q from result due to ACLs", svc)
   923  			info.Services = append(info.Services[:j], info.Services[j+1:]...)
   924  			j--
   925  		}
   926  
   927  		// Filter checks
   928  		for j := 0; j < len(info.Checks); j++ {
   929  			chk := info.Checks[j]
   930  			if f.allowService(chk.ServiceName) {
   931  				continue
   932  			}
   933  			f.logger.Printf("[DEBUG] consul: dropping check %q from result due to ACLs", chk.CheckID)
   934  			info.Checks = append(info.Checks[:j], info.Checks[j+1:]...)
   935  			j--
   936  		}
   937  	}
   938  	*dump = nd
   939  }
   940  
   941  // filterNodes is used to filter through all parts of a node list and remove
   942  // elements the provided ACL token cannot access.
   943  func (f *aclFilter) filterNodes(nodes *structs.Nodes) {
   944  	n := *nodes
   945  	for i := 0; i < len(n); i++ {
   946  		node := n[i].Node
   947  		if f.allowNode(node) {
   948  			continue
   949  		}
   950  		f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node)
   951  		n = append(n[:i], n[i+1:]...)
   952  		i--
   953  	}
   954  	*nodes = n
   955  }
   956  
   957  // redactPreparedQueryTokens will redact any tokens unless the client has a
   958  // management token. This eases the transition to delegated authority over
   959  // prepared queries, since it was easy to capture management tokens in Consul
   960  // 0.6.3 and earlier, and we don't want to willy-nilly show those. This does
   961  // have the limitation of preventing delegated non-management users from seeing
   962  // captured tokens, but they can at least see whether or not a token is set.
   963  func (f *aclFilter) redactPreparedQueryTokens(query **structs.PreparedQuery) {
   964  	// Management tokens can see everything with no filtering.
   965  	if f.authorizer.ACLWrite() {
   966  		return
   967  	}
   968  
   969  	// Let the user see if there's a blank token, otherwise we need
   970  	// to redact it, since we know they don't have a management
   971  	// token.
   972  	if (*query).Token != "" {
   973  		// Redact the token, using a copy of the query structure
   974  		// since we could be pointed at a live instance from the
   975  		// state store so it's not safe to modify it. Note that
   976  		// this clone will still point to things like underlying
   977  		// arrays in the original, but for modifying just the
   978  		// token it will be safe to use.
   979  		clone := *(*query)
   980  		clone.Token = redactedToken
   981  		*query = &clone
   982  	}
   983  }
   984  
   985  // filterPreparedQueries is used to filter prepared queries based on ACL rules.
   986  // We prune entries the user doesn't have access to, and we redact any tokens
   987  // if the user doesn't have a management token.
   988  func (f *aclFilter) filterPreparedQueries(queries *structs.PreparedQueries) {
   989  	// Management tokens can see everything with no filtering.
   990  	if f.authorizer.ACLWrite() {
   991  		return
   992  	}
   993  
   994  	// Otherwise, we need to see what the token has access to.
   995  	ret := make(structs.PreparedQueries, 0, len(*queries))
   996  	for _, query := range *queries {
   997  		// If no prefix ACL applies to this query then filter it, since
   998  		// we know at this point the user doesn't have a management
   999  		// token, otherwise see what the policy says.
  1000  		prefix, ok := query.GetACLPrefix()
  1001  		if !ok || !f.authorizer.PreparedQueryRead(prefix) {
  1002  			f.logger.Printf("[DEBUG] consul: dropping prepared query %q from result due to ACLs", query.ID)
  1003  			continue
  1004  		}
  1005  
  1006  		// Redact any tokens if necessary. We make a copy of just the
  1007  		// pointer so we don't mess with the caller's slice.
  1008  		final := query
  1009  		f.redactPreparedQueryTokens(&final)
  1010  		ret = append(ret, final)
  1011  	}
  1012  	*queries = ret
  1013  }
  1014  
  1015  func (f *aclFilter) redactTokenSecret(token **structs.ACLToken) {
  1016  	if token == nil || *token == nil || f == nil || f.authorizer.ACLWrite() {
  1017  		return
  1018  	}
  1019  	clone := *(*token)
  1020  	clone.SecretID = redactedToken
  1021  	*token = &clone
  1022  }
  1023  
  1024  func (f *aclFilter) redactTokenSecrets(tokens *structs.ACLTokens) {
  1025  	ret := make(structs.ACLTokens, 0, len(*tokens))
  1026  	for _, token := range *tokens {
  1027  		final := token
  1028  		f.redactTokenSecret(&final)
  1029  		ret = append(ret, final)
  1030  	}
  1031  	*tokens = ret
  1032  }
  1033  
  1034  func (r *ACLResolver) filterACLWithAuthorizer(authorizer acl.Authorizer, subj interface{}) error {
  1035  	if authorizer == nil {
  1036  		return nil
  1037  	}
  1038  	// Create the filter
  1039  	filt := newACLFilter(authorizer, r.logger, r.config.ACLEnforceVersion8)
  1040  
  1041  	switch v := subj.(type) {
  1042  	case *structs.CheckServiceNodes:
  1043  		filt.filterCheckServiceNodes(v)
  1044  
  1045  	case *structs.IndexedCheckServiceNodes:
  1046  		filt.filterCheckServiceNodes(&v.Nodes)
  1047  
  1048  	case *structs.IndexedCoordinates:
  1049  		filt.filterCoordinates(&v.Coordinates)
  1050  
  1051  	case *structs.IndexedHealthChecks:
  1052  		filt.filterHealthChecks(&v.HealthChecks)
  1053  
  1054  	case *structs.IndexedIntentions:
  1055  		filt.filterIntentions(&v.Intentions)
  1056  
  1057  	case *structs.IndexedNodeDump:
  1058  		filt.filterNodeDump(&v.Dump)
  1059  
  1060  	case *structs.IndexedNodes:
  1061  		filt.filterNodes(&v.Nodes)
  1062  
  1063  	case *structs.IndexedNodeServices:
  1064  		filt.filterNodeServices(&v.NodeServices)
  1065  
  1066  	case *structs.IndexedServiceNodes:
  1067  		filt.filterServiceNodes(&v.ServiceNodes)
  1068  
  1069  	case *structs.IndexedServices:
  1070  		filt.filterServices(v.Services)
  1071  
  1072  	case *structs.IndexedSessions:
  1073  		filt.filterSessions(&v.Sessions)
  1074  
  1075  	case *structs.IndexedPreparedQueries:
  1076  		filt.filterPreparedQueries(&v.Queries)
  1077  
  1078  	case **structs.PreparedQuery:
  1079  		filt.redactPreparedQueryTokens(v)
  1080  
  1081  	case *structs.ACLTokens:
  1082  		filt.redactTokenSecrets(v)
  1083  
  1084  	case **structs.ACLToken:
  1085  		filt.redactTokenSecret(v)
  1086  
  1087  	default:
  1088  		panic(fmt.Errorf("Unhandled type passed to ACL filter: %#v", subj))
  1089  	}
  1090  
  1091  	return nil
  1092  }
  1093  
  1094  // filterACL is used to filter results from our service catalog based on the
  1095  // rules configured for the provided token.
  1096  func (r *ACLResolver) filterACL(token string, subj interface{}) error {
  1097  	// Get the ACL from the token
  1098  	authorizer, err := r.ResolveToken(token)
  1099  	if err != nil {
  1100  		return err
  1101  	}
  1102  
  1103  	// Fast path if ACLs are not enabled
  1104  	if authorizer == nil {
  1105  		return nil
  1106  	}
  1107  
  1108  	return r.filterACLWithAuthorizer(authorizer, subj)
  1109  }
  1110  
  1111  // vetRegisterWithACL applies the given ACL's policy to the catalog update and
  1112  // determines if it is allowed. Since the catalog register request is so
  1113  // dynamic, this is a pretty complex algorithm and was worth breaking out of the
  1114  // endpoint. The NodeServices record for the node must be supplied, and can be
  1115  // nil.
  1116  //
  1117  // This is a bit racy because we have to check the state store outside of a
  1118  // transaction. It's the best we can do because we don't want to flow ACL
  1119  // checking down there. The node information doesn't change in practice, so this
  1120  // will be fine. If we expose ways to change node addresses in a later version,
  1121  // then we should split the catalog API at the node and service level so we can
  1122  // address this race better (even then it would be super rare, and would at
  1123  // worst let a service update revert a recent node update, so it doesn't open up
  1124  // too much abuse).
  1125  func vetRegisterWithACL(rule acl.Authorizer, subj *structs.RegisterRequest,
  1126  	ns *structs.NodeServices) error {
  1127  	// Fast path if ACLs are not enabled.
  1128  	if rule == nil {
  1129  		return nil
  1130  	}
  1131  
  1132  	// This gets called potentially from a few spots so we save it and
  1133  	// return the structure we made if we have it.
  1134  	var memo map[string]interface{}
  1135  	scope := func() map[string]interface{} {
  1136  		if memo != nil {
  1137  			return memo
  1138  		}
  1139  
  1140  		node := &api.Node{
  1141  			ID:              string(subj.ID),
  1142  			Node:            subj.Node,
  1143  			Address:         subj.Address,
  1144  			Datacenter:      subj.Datacenter,
  1145  			TaggedAddresses: subj.TaggedAddresses,
  1146  			Meta:            subj.NodeMeta,
  1147  		}
  1148  
  1149  		var service *api.AgentService
  1150  		if subj.Service != nil {
  1151  			service = &api.AgentService{
  1152  				ID:                subj.Service.ID,
  1153  				Service:           subj.Service.Service,
  1154  				Tags:              subj.Service.Tags,
  1155  				Meta:              subj.Service.Meta,
  1156  				Address:           subj.Service.Address,
  1157  				Port:              subj.Service.Port,
  1158  				EnableTagOverride: subj.Service.EnableTagOverride,
  1159  			}
  1160  		}
  1161  
  1162  		memo = sentinel.ScopeCatalogUpsert(node, service)
  1163  		return memo
  1164  	}
  1165  
  1166  	// Vet the node info. This allows service updates to re-post the required
  1167  	// node info for each request without having to have node "write"
  1168  	// privileges.
  1169  	needsNode := ns == nil || subj.ChangesNode(ns.Node)
  1170  
  1171  	if needsNode && !rule.NodeWrite(subj.Node, scope) {
  1172  		return acl.ErrPermissionDenied
  1173  	}
  1174  
  1175  	// Vet the service change. This includes making sure they can register
  1176  	// the given service, and that we can write to any existing service that
  1177  	// is being modified by id (if any).
  1178  	if subj.Service != nil {
  1179  		if !rule.ServiceWrite(subj.Service.Service, scope) {
  1180  			return acl.ErrPermissionDenied
  1181  		}
  1182  
  1183  		if ns != nil {
  1184  			other, ok := ns.Services[subj.Service.ID]
  1185  
  1186  			// This is effectively a delete, so we DO NOT apply the
  1187  			// sentinel scope to the service we are overwriting, just
  1188  			// the regular ACL policy.
  1189  			if ok && !rule.ServiceWrite(other.Service, nil) {
  1190  				return acl.ErrPermissionDenied
  1191  			}
  1192  		}
  1193  	}
  1194  
  1195  	// Make sure that the member was flattened before we got there. This
  1196  	// keeps us from having to verify this check as well.
  1197  	if subj.Check != nil {
  1198  		return fmt.Errorf("check member must be nil")
  1199  	}
  1200  
  1201  	// Vet the checks. Node-level checks require node write, and
  1202  	// service-level checks require service write.
  1203  	for _, check := range subj.Checks {
  1204  		// Make sure that the node matches - we don't allow you to mix
  1205  		// checks from other nodes because we'd have to pull a bunch
  1206  		// more state store data to check this. If ACLs are enabled then
  1207  		// we simply require them to match in a given request. There's a
  1208  		// note in state_store.go to ban this down there in Consul 0.8,
  1209  		// but it's good to leave this here because it's required for
  1210  		// correctness wrt. ACLs.
  1211  		if check.Node != subj.Node {
  1212  			return fmt.Errorf("Node '%s' for check '%s' doesn't match register request node '%s'",
  1213  				check.Node, check.CheckID, subj.Node)
  1214  		}
  1215  
  1216  		// Node-level check.
  1217  		if check.ServiceID == "" {
  1218  			if !rule.NodeWrite(subj.Node, scope) {
  1219  				return acl.ErrPermissionDenied
  1220  			}
  1221  			continue
  1222  		}
  1223  
  1224  		// Service-level check, check the common case where it
  1225  		// matches the service part of this request, which has
  1226  		// already been vetted above, and might be being registered
  1227  		// along with its checks.
  1228  		if subj.Service != nil && subj.Service.ID == check.ServiceID {
  1229  			continue
  1230  		}
  1231  
  1232  		// Service-level check for some other service. Make sure they've
  1233  		// got write permissions for that service.
  1234  		if ns == nil {
  1235  			return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID)
  1236  		}
  1237  
  1238  		other, ok := ns.Services[check.ServiceID]
  1239  		if !ok {
  1240  			return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID)
  1241  		}
  1242  
  1243  		// We are only adding a check here, so we don't add the scope,
  1244  		// since the sentinel policy doesn't apply to adding checks at
  1245  		// this time.
  1246  		if !rule.ServiceWrite(other.Service, nil) {
  1247  			return acl.ErrPermissionDenied
  1248  		}
  1249  	}
  1250  
  1251  	return nil
  1252  }
  1253  
  1254  // vetDeregisterWithACL applies the given ACL's policy to the catalog update and
  1255  // determines if it is allowed. Since the catalog deregister request is so
  1256  // dynamic, this is a pretty complex algorithm and was worth breaking out of the
  1257  // endpoint. The NodeService for the referenced service must be supplied, and can
  1258  // be nil; similar for the HealthCheck for the referenced health check.
  1259  func vetDeregisterWithACL(rule acl.Authorizer, subj *structs.DeregisterRequest,
  1260  	ns *structs.NodeService, nc *structs.HealthCheck) error {
  1261  
  1262  	// Fast path if ACLs are not enabled.
  1263  	if rule == nil {
  1264  		return nil
  1265  	}
  1266  
  1267  	// We don't apply sentinel in this path, since at this time sentinel
  1268  	// only applies to create and update operations.
  1269  
  1270  	// This order must match the code in applyRegister() in fsm.go since it
  1271  	// also evaluates things in this order, and will ignore fields based on
  1272  	// this precedence. This lets us also ignore them from an ACL perspective.
  1273  	if subj.ServiceID != "" {
  1274  		if ns == nil {
  1275  			return fmt.Errorf("Unknown service '%s'", subj.ServiceID)
  1276  		}
  1277  		if !rule.ServiceWrite(ns.Service, nil) {
  1278  			return acl.ErrPermissionDenied
  1279  		}
  1280  	} else if subj.CheckID != "" {
  1281  		if nc == nil {
  1282  			return fmt.Errorf("Unknown check '%s'", subj.CheckID)
  1283  		}
  1284  		if nc.ServiceID != "" {
  1285  			if !rule.ServiceWrite(nc.ServiceName, nil) {
  1286  				return acl.ErrPermissionDenied
  1287  			}
  1288  		} else {
  1289  			if !rule.NodeWrite(subj.Node, nil) {
  1290  				return acl.ErrPermissionDenied
  1291  			}
  1292  		}
  1293  	} else {
  1294  		if !rule.NodeWrite(subj.Node, nil) {
  1295  			return acl.ErrPermissionDenied
  1296  		}
  1297  	}
  1298  
  1299  	return nil
  1300  }
  1301  
  1302  // vetNodeTxnOp applies the given ACL policy to a node transaction operation.
  1303  func vetNodeTxnOp(op *structs.TxnNodeOp, rule acl.Authorizer) error {
  1304  	// Fast path if ACLs are not enabled.
  1305  	if rule == nil {
  1306  		return nil
  1307  	}
  1308  
  1309  	node := op.Node
  1310  
  1311  	n := &api.Node{
  1312  		Node:            node.Node,
  1313  		ID:              string(node.ID),
  1314  		Address:         node.Address,
  1315  		Datacenter:      node.Datacenter,
  1316  		TaggedAddresses: node.TaggedAddresses,
  1317  		Meta:            node.Meta,
  1318  	}
  1319  
  1320  	// Sentinel doesn't apply to deletes, only creates/updates, so we don't need the scopeFn.
  1321  	var scope func() map[string]interface{}
  1322  	if op.Verb != api.NodeDelete && op.Verb != api.NodeDeleteCAS {
  1323  		scope = func() map[string]interface{} {
  1324  			return sentinel.ScopeCatalogUpsert(n, nil)
  1325  		}
  1326  	}
  1327  
  1328  	if rule != nil && !rule.NodeWrite(node.Node, scope) {
  1329  		return acl.ErrPermissionDenied
  1330  	}
  1331  
  1332  	return nil
  1333  }
  1334  
  1335  // vetServiceTxnOp applies the given ACL policy to a service transaction operation.
  1336  func vetServiceTxnOp(op *structs.TxnServiceOp, rule acl.Authorizer) error {
  1337  	// Fast path if ACLs are not enabled.
  1338  	if rule == nil {
  1339  		return nil
  1340  	}
  1341  
  1342  	service := op.Service
  1343  
  1344  	n := &api.Node{Node: op.Node}
  1345  	svc := &api.AgentService{
  1346  		ID:                service.ID,
  1347  		Service:           service.Service,
  1348  		Tags:              service.Tags,
  1349  		Meta:              service.Meta,
  1350  		Address:           service.Address,
  1351  		Port:              service.Port,
  1352  		EnableTagOverride: service.EnableTagOverride,
  1353  	}
  1354  	var scope func() map[string]interface{}
  1355  	if op.Verb != api.ServiceDelete && op.Verb != api.ServiceDeleteCAS {
  1356  		scope = func() map[string]interface{} {
  1357  			return sentinel.ScopeCatalogUpsert(n, svc)
  1358  		}
  1359  	}
  1360  	if !rule.ServiceWrite(service.Service, scope) {
  1361  		return acl.ErrPermissionDenied
  1362  	}
  1363  
  1364  	return nil
  1365  }
  1366  
  1367  // vetCheckTxnOp applies the given ACL policy to a check transaction operation.
  1368  func vetCheckTxnOp(op *structs.TxnCheckOp, rule acl.Authorizer) error {
  1369  	// Fast path if ACLs are not enabled.
  1370  	if rule == nil {
  1371  		return nil
  1372  	}
  1373  
  1374  	n := &api.Node{Node: op.Check.Node}
  1375  	svc := &api.AgentService{
  1376  		ID:      op.Check.ServiceID,
  1377  		Service: op.Check.ServiceID,
  1378  		Tags:    op.Check.ServiceTags,
  1379  	}
  1380  	var scope func() map[string]interface{}
  1381  	if op.Check.ServiceID == "" {
  1382  		// Node-level check.
  1383  		if op.Verb == api.CheckDelete || op.Verb == api.CheckDeleteCAS {
  1384  			scope = func() map[string]interface{} {
  1385  				return sentinel.ScopeCatalogUpsert(n, svc)
  1386  			}
  1387  		}
  1388  		if !rule.NodeWrite(op.Check.Node, scope) {
  1389  			return acl.ErrPermissionDenied
  1390  		}
  1391  	} else {
  1392  		// Service-level check.
  1393  		if op.Verb == api.CheckDelete || op.Verb == api.CheckDeleteCAS {
  1394  			scope = func() map[string]interface{} {
  1395  				return sentinel.ScopeCatalogUpsert(n, svc)
  1396  			}
  1397  		}
  1398  		if !rule.ServiceWrite(op.Check.ServiceName, scope) {
  1399  			return acl.ErrPermissionDenied
  1400  		}
  1401  	}
  1402  
  1403  	return nil
  1404  }