github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/nomad/acl_endpoint.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"time"
    10  
    11  	metrics "github.com/armon/go-metrics"
    12  	log "github.com/hashicorp/go-hclog"
    13  	memdb "github.com/hashicorp/go-memdb"
    14  	policy "github.com/hashicorp/nomad/acl"
    15  	"github.com/hashicorp/nomad/helper/uuid"
    16  	"github.com/hashicorp/nomad/nomad/state"
    17  	"github.com/hashicorp/nomad/nomad/structs"
    18  )
    19  
    20  var (
    21  	// aclDisabled is returned when an ACL endpoint is hit but ACLs are not enabled
    22  	aclDisabled = structs.NewErrRPCCoded(400, "ACL support disabled")
    23  )
    24  
    25  const (
    26  	// aclBootstrapReset is the file name to create in the data dir. It's only contents
    27  	// should be the reset index
    28  	aclBootstrapReset = "acl-bootstrap-reset"
    29  )
    30  
    31  // ACL endpoint is used for manipulating ACL tokens and policies
    32  type ACL struct {
    33  	srv    *Server
    34  	logger log.Logger
    35  }
    36  
    37  // UpsertPolicies is used to create or update a set of policies
    38  func (a *ACL) UpsertPolicies(args *structs.ACLPolicyUpsertRequest, reply *structs.GenericResponse) error {
    39  	// Ensure ACLs are enabled, and always flow modification requests to the authoritative region
    40  	if !a.srv.config.ACLEnabled {
    41  		return aclDisabled
    42  	}
    43  	args.Region = a.srv.config.AuthoritativeRegion
    44  
    45  	if done, err := a.srv.forward("ACL.UpsertPolicies", args, args, reply); done {
    46  		return err
    47  	}
    48  	defer metrics.MeasureSince([]string{"nomad", "acl", "upsert_policies"}, time.Now())
    49  
    50  	// Check management level permissions
    51  	if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
    52  		return err
    53  	} else if acl == nil || !acl.IsManagement() {
    54  		return structs.ErrPermissionDenied
    55  	}
    56  
    57  	// Validate non-zero set of policies
    58  	if len(args.Policies) == 0 {
    59  		return structs.NewErrRPCCoded(400, "must specify as least one policy")
    60  	}
    61  
    62  	// Validate each policy, compute hash
    63  	for idx, policy := range args.Policies {
    64  		if err := policy.Validate(); err != nil {
    65  			return structs.NewErrRPCCodedf(404, "policy %d invalid: %v", idx, err)
    66  		}
    67  		policy.SetHash()
    68  	}
    69  
    70  	// Update via Raft
    71  	_, index, err := a.srv.raftApply(structs.ACLPolicyUpsertRequestType, args)
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	// Update the index
    77  	reply.Index = index
    78  	return nil
    79  }
    80  
    81  // DeletePolicies is used to delete policies
    82  func (a *ACL) DeletePolicies(args *structs.ACLPolicyDeleteRequest, reply *structs.GenericResponse) error {
    83  	// Ensure ACLs are enabled, and always flow modification requests to the authoritative region
    84  	if !a.srv.config.ACLEnabled {
    85  		return aclDisabled
    86  	}
    87  	args.Region = a.srv.config.AuthoritativeRegion
    88  
    89  	if done, err := a.srv.forward("ACL.DeletePolicies", args, args, reply); done {
    90  		return err
    91  	}
    92  	defer metrics.MeasureSince([]string{"nomad", "acl", "delete_policies"}, time.Now())
    93  
    94  	// Check management level permissions
    95  	if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
    96  		return err
    97  	} else if acl == nil || !acl.IsManagement() {
    98  		return structs.ErrPermissionDenied
    99  	}
   100  
   101  	// Validate non-zero set of policies
   102  	if len(args.Names) == 0 {
   103  		return structs.NewErrRPCCoded(400, "must specify as least one policy")
   104  	}
   105  
   106  	// Update via Raft
   107  	_, index, err := a.srv.raftApply(structs.ACLPolicyDeleteRequestType, args)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	// Update the index
   113  	reply.Index = index
   114  	return nil
   115  }
   116  
   117  // ListPolicies is used to list the policies
   118  func (a *ACL) ListPolicies(args *structs.ACLPolicyListRequest, reply *structs.ACLPolicyListResponse) error {
   119  	if !a.srv.config.ACLEnabled {
   120  		return aclDisabled
   121  	}
   122  
   123  	if done, err := a.srv.forward("ACL.ListPolicies", args, args, reply); done {
   124  		return err
   125  	}
   126  	defer metrics.MeasureSince([]string{"nomad", "acl", "list_policies"}, time.Now())
   127  
   128  	// Check management level permissions
   129  	acl, err := a.srv.ResolveToken(args.AuthToken)
   130  	if err != nil {
   131  		return err
   132  	} else if acl == nil {
   133  		return structs.ErrPermissionDenied
   134  	}
   135  
   136  	// If it is not a management token determine the policies that may be listed
   137  	mgt := acl.IsManagement()
   138  	var policies map[string]struct{}
   139  	if !mgt {
   140  		token, err := a.requestACLToken(args.AuthToken)
   141  		if err != nil {
   142  			return err
   143  		}
   144  		if token == nil {
   145  			return structs.ErrTokenNotFound
   146  		}
   147  
   148  		policies = make(map[string]struct{}, len(token.Policies))
   149  		for _, p := range token.Policies {
   150  			policies[p] = struct{}{}
   151  		}
   152  	}
   153  
   154  	// Setup the blocking query
   155  	opts := blockingOptions{
   156  		queryOpts: &args.QueryOptions,
   157  		queryMeta: &reply.QueryMeta,
   158  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
   159  			// Iterate over all the policies
   160  			var err error
   161  			var iter memdb.ResultIterator
   162  			if prefix := args.QueryOptions.Prefix; prefix != "" {
   163  				iter, err = state.ACLPolicyByNamePrefix(ws, prefix)
   164  			} else {
   165  				iter, err = state.ACLPolicies(ws)
   166  			}
   167  			if err != nil {
   168  				return err
   169  			}
   170  
   171  			// Convert all the policies to a list stub
   172  			reply.Policies = nil
   173  			for {
   174  				raw := iter.Next()
   175  				if raw == nil {
   176  					break
   177  				}
   178  				policy := raw.(*structs.ACLPolicy)
   179  				if _, ok := policies[policy.Name]; ok || mgt {
   180  					reply.Policies = append(reply.Policies, policy.Stub())
   181  				}
   182  			}
   183  
   184  			// Use the last index that affected the policy table
   185  			index, err := state.Index("acl_policy")
   186  			if err != nil {
   187  				return err
   188  			}
   189  
   190  			// Ensure we never set the index to zero, otherwise a blocking query cannot be used.
   191  			// We floor the index at one, since realistically the first write must have a higher index.
   192  			if index == 0 {
   193  				index = 1
   194  			}
   195  			reply.Index = index
   196  			return nil
   197  		}}
   198  	return a.srv.blockingRPC(&opts)
   199  }
   200  
   201  // GetPolicy is used to get a specific policy
   202  func (a *ACL) GetPolicy(args *structs.ACLPolicySpecificRequest, reply *structs.SingleACLPolicyResponse) error {
   203  	if !a.srv.config.ACLEnabled {
   204  		return aclDisabled
   205  	}
   206  
   207  	if done, err := a.srv.forward("ACL.GetPolicy", args, args, reply); done {
   208  		return err
   209  	}
   210  	defer metrics.MeasureSince([]string{"nomad", "acl", "get_policy"}, time.Now())
   211  
   212  	// Check management level permissions
   213  	acl, err := a.srv.ResolveToken(args.AuthToken)
   214  	if err != nil {
   215  		return err
   216  	} else if acl == nil {
   217  		return structs.ErrPermissionDenied
   218  	}
   219  
   220  	// If the policy is the anonymous one, anyone can get it
   221  	// If it is not a management token determine if it can get this policy
   222  	mgt := acl.IsManagement()
   223  	if !mgt && args.Name != "anonymous" {
   224  		token, err := a.requestACLToken(args.AuthToken)
   225  		if err != nil {
   226  			return err
   227  		}
   228  		if token == nil {
   229  			return structs.ErrTokenNotFound
   230  		}
   231  
   232  		found := false
   233  		for _, p := range token.Policies {
   234  			if p == args.Name {
   235  				found = true
   236  				break
   237  			}
   238  		}
   239  
   240  		if !found {
   241  			return structs.ErrPermissionDenied
   242  		}
   243  	}
   244  
   245  	// Setup the blocking query
   246  	opts := blockingOptions{
   247  		queryOpts: &args.QueryOptions,
   248  		queryMeta: &reply.QueryMeta,
   249  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
   250  			// Look for the policy
   251  			out, err := state.ACLPolicyByName(ws, args.Name)
   252  			if err != nil {
   253  				return err
   254  			}
   255  
   256  			// Setup the output
   257  			reply.Policy = out
   258  			if out != nil {
   259  				reply.Index = out.ModifyIndex
   260  				rules, err := policy.Parse(out.Rules)
   261  
   262  				if err != nil {
   263  					return err
   264  				}
   265  				reply.Policy.RulesJSON = rules
   266  			} else {
   267  				// Use the last index that affected the policy table
   268  				index, err := state.Index("acl_policy")
   269  				if err != nil {
   270  					return err
   271  				}
   272  				reply.Index = index
   273  			}
   274  			return nil
   275  		}}
   276  	return a.srv.blockingRPC(&opts)
   277  }
   278  
   279  func (a *ACL) requestACLToken(secretID string) (*structs.ACLToken, error) {
   280  	if secretID == "" {
   281  		return structs.AnonymousACLToken, nil
   282  	}
   283  
   284  	snap, err := a.srv.fsm.State().Snapshot()
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  
   289  	return snap.ACLTokenBySecretID(nil, secretID)
   290  }
   291  
   292  // GetPolicies is used to get a set of policies
   293  func (a *ACL) GetPolicies(args *structs.ACLPolicySetRequest, reply *structs.ACLPolicySetResponse) error {
   294  	if !a.srv.config.ACLEnabled {
   295  		return aclDisabled
   296  	}
   297  	if done, err := a.srv.forward("ACL.GetPolicies", args, args, reply); done {
   298  		return err
   299  	}
   300  	defer metrics.MeasureSince([]string{"nomad", "acl", "get_policies"}, time.Now())
   301  
   302  	// For client typed tokens, allow them to query any policies associated with that token.
   303  	// This is used by clients which are resolving the policies to enforce. Any associated
   304  	// policies need to be fetched so that the client can determine what to allow.
   305  	token, err := a.requestACLToken(args.AuthToken)
   306  	if err != nil {
   307  		return err
   308  	}
   309  
   310  	if token == nil {
   311  		return structs.ErrTokenNotFound
   312  	}
   313  	if token.Type != structs.ACLManagementToken && !token.PolicySubset(args.Names) {
   314  		return structs.ErrPermissionDenied
   315  	}
   316  
   317  	// Setup the blocking query
   318  	opts := blockingOptions{
   319  		queryOpts: &args.QueryOptions,
   320  		queryMeta: &reply.QueryMeta,
   321  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
   322  			// Setup the output
   323  			reply.Policies = make(map[string]*structs.ACLPolicy, len(args.Names))
   324  
   325  			// Look for the policy
   326  			for _, policyName := range args.Names {
   327  				out, err := state.ACLPolicyByName(ws, policyName)
   328  				if err != nil {
   329  					return err
   330  				}
   331  				if out != nil {
   332  					reply.Policies[policyName] = out
   333  				}
   334  			}
   335  
   336  			// Use the last index that affected the policy table
   337  			index, err := state.Index("acl_policy")
   338  			if err != nil {
   339  				return err
   340  			}
   341  			reply.Index = index
   342  			return nil
   343  		}}
   344  	return a.srv.blockingRPC(&opts)
   345  }
   346  
   347  // Bootstrap is used to bootstrap the initial token
   348  func (a *ACL) Bootstrap(args *structs.ACLTokenBootstrapRequest, reply *structs.ACLTokenUpsertResponse) error {
   349  	// Ensure ACLs are enabled, and always flow modification requests to the authoritative region
   350  	if !a.srv.config.ACLEnabled {
   351  		return aclDisabled
   352  	}
   353  	args.Region = a.srv.config.AuthoritativeRegion
   354  
   355  	if done, err := a.srv.forward("ACL.Bootstrap", args, args, reply); done {
   356  		return err
   357  	}
   358  	defer metrics.MeasureSince([]string{"nomad", "acl", "bootstrap"}, time.Now())
   359  
   360  	// Always ignore the reset index from the arguments
   361  	args.ResetIndex = 0
   362  
   363  	// Snapshot the state
   364  	state, err := a.srv.State().Snapshot()
   365  	if err != nil {
   366  		return err
   367  	}
   368  
   369  	// Verify bootstrap is possible. The state store method re-verifies this,
   370  	// but we do an early check to avoid raft transactions when possible.
   371  	ok, resetIdx, err := state.CanBootstrapACLToken()
   372  	if err != nil {
   373  		return err
   374  	}
   375  	if !ok {
   376  		// Check if there is a reset index specified
   377  		specifiedIndex := a.fileBootstrapResetIndex()
   378  		if specifiedIndex == 0 {
   379  			return structs.NewErrRPCCodedf(400, "ACL bootstrap already done (reset index: %d)", resetIdx)
   380  		} else if specifiedIndex != resetIdx {
   381  			return structs.NewErrRPCCodedf(400, "Invalid bootstrap reset index (specified %d, reset index: %d)", specifiedIndex, resetIdx)
   382  		}
   383  
   384  		// Setup the reset index to allow bootstrapping again
   385  		args.ResetIndex = resetIdx
   386  	}
   387  
   388  	// Create a new global management token, override any parameter
   389  	args.Token = &structs.ACLToken{
   390  		AccessorID: uuid.Generate(),
   391  		SecretID:   uuid.Generate(),
   392  		Name:       "Bootstrap Token",
   393  		Type:       structs.ACLManagementToken,
   394  		Global:     true,
   395  		CreateTime: time.Now().UTC(),
   396  	}
   397  	args.Token.SetHash()
   398  
   399  	// Update via Raft
   400  	_, index, err := a.srv.raftApply(structs.ACLTokenBootstrapRequestType, args)
   401  	if err != nil {
   402  		return err
   403  	}
   404  
   405  	// Populate the response. We do a lookup against the state to
   406  	// pickup the proper create / modify times.
   407  	state, err = a.srv.State().Snapshot()
   408  	if err != nil {
   409  		return err
   410  	}
   411  	out, err := state.ACLTokenByAccessorID(nil, args.Token.AccessorID)
   412  	if err != nil {
   413  		return structs.NewErrRPCCodedf(400, "token lookup failed: %v", err)
   414  	}
   415  	reply.Tokens = append(reply.Tokens, out)
   416  
   417  	// Update the index
   418  	reply.Index = index
   419  	return nil
   420  }
   421  
   422  // fileBootstrapResetIndex is used to read the reset file from <data-dir>/acl-bootstrap-reset
   423  func (a *ACL) fileBootstrapResetIndex() uint64 {
   424  	// Determine the file path to check
   425  	path := filepath.Join(a.srv.config.DataDir, aclBootstrapReset)
   426  
   427  	// Read the file
   428  	raw, err := ioutil.ReadFile(path)
   429  	if err != nil {
   430  		if !os.IsNotExist(err) {
   431  			a.logger.Error("failed to read bootstrap file", "path", path, "error", err)
   432  		}
   433  		return 0
   434  	}
   435  
   436  	// Attempt to parse the file
   437  	var resetIdx uint64
   438  	if _, err := fmt.Sscanf(string(raw), "%d", &resetIdx); err != nil {
   439  		a.logger.Error("failed to parse bootstrap file", "path", path, "error", err)
   440  		return 0
   441  	}
   442  
   443  	// Return the reset index
   444  	a.logger.Warn("bootstrap file parsed", "path", path, "reset_index", resetIdx)
   445  	return resetIdx
   446  }
   447  
   448  // UpsertTokens is used to create or update a set of tokens
   449  func (a *ACL) UpsertTokens(args *structs.ACLTokenUpsertRequest, reply *structs.ACLTokenUpsertResponse) error {
   450  	// Ensure ACLs are enabled, and always flow modification requests to the authoritative region
   451  	if !a.srv.config.ACLEnabled {
   452  		return aclDisabled
   453  	}
   454  
   455  	// Validate non-zero set of tokens
   456  	if len(args.Tokens) == 0 {
   457  		return structs.NewErrRPCCoded(400, "must specify as least one token")
   458  	}
   459  
   460  	// Force the request to the authoritative region if we are creating global tokens
   461  	hasGlobal := false
   462  	allGlobal := true
   463  	for _, token := range args.Tokens {
   464  		if token.Global {
   465  			hasGlobal = true
   466  		} else {
   467  			allGlobal = false
   468  		}
   469  	}
   470  
   471  	// Disallow mixed requests with global and non-global tokens since we forward
   472  	// the entire request as a single batch.
   473  	if hasGlobal {
   474  		if !allGlobal {
   475  			return structs.NewErrRPCCoded(400, "cannot upsert mixed global and non-global tokens")
   476  		}
   477  
   478  		// Force the request to the authoritative region if it has global
   479  		args.Region = a.srv.config.AuthoritativeRegion
   480  	}
   481  
   482  	if done, err := a.srv.forward("ACL.UpsertTokens", args, args, reply); done {
   483  		return err
   484  	}
   485  	defer metrics.MeasureSince([]string{"nomad", "acl", "upsert_tokens"}, time.Now())
   486  
   487  	// Check management level permissions
   488  	if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
   489  		return err
   490  	} else if acl == nil || !acl.IsManagement() {
   491  		return structs.ErrPermissionDenied
   492  	}
   493  
   494  	// Snapshot the state
   495  	state, err := a.srv.State().Snapshot()
   496  	if err != nil {
   497  		return err
   498  	}
   499  
   500  	// Validate each token
   501  	for idx, token := range args.Tokens {
   502  		if err := token.Validate(); err != nil {
   503  			return structs.NewErrRPCCodedf(400, "token %d invalid: %v", idx, err)
   504  		}
   505  
   506  		// Generate an accessor and secret ID if new
   507  		if token.AccessorID == "" {
   508  			token.AccessorID = uuid.Generate()
   509  			token.SecretID = uuid.Generate()
   510  			token.CreateTime = time.Now().UTC()
   511  
   512  		} else {
   513  			// Verify the token exists
   514  			out, err := state.ACLTokenByAccessorID(nil, token.AccessorID)
   515  			if err != nil {
   516  				return structs.NewErrRPCCodedf(400, "token lookup failed: %v", err)
   517  			}
   518  			if out == nil {
   519  				return structs.NewErrRPCCodedf(404, "cannot find token %s", token.AccessorID)
   520  			}
   521  
   522  			// Cannot toggle the "Global" mode
   523  			if token.Global != out.Global {
   524  				return structs.NewErrRPCCodedf(400, "cannot toggle global mode of %s", token.AccessorID)
   525  			}
   526  		}
   527  
   528  		// Compute the token hash
   529  		token.SetHash()
   530  	}
   531  
   532  	// Update via Raft
   533  	_, index, err := a.srv.raftApply(structs.ACLTokenUpsertRequestType, args)
   534  	if err != nil {
   535  		return err
   536  	}
   537  
   538  	// Populate the response. We do a lookup against the state to
   539  	// pickup the proper create / modify times.
   540  	state, err = a.srv.State().Snapshot()
   541  	if err != nil {
   542  		return err
   543  	}
   544  	for _, token := range args.Tokens {
   545  		out, err := state.ACLTokenByAccessorID(nil, token.AccessorID)
   546  		if err != nil {
   547  			return structs.NewErrRPCCodedf(400, "token lookup failed: %v", err)
   548  		}
   549  		reply.Tokens = append(reply.Tokens, out)
   550  	}
   551  
   552  	// Update the index
   553  	reply.Index = index
   554  	return nil
   555  }
   556  
   557  // DeleteTokens is used to delete tokens
   558  func (a *ACL) DeleteTokens(args *structs.ACLTokenDeleteRequest, reply *structs.GenericResponse) error {
   559  	// Ensure ACLs are enabled, and always flow modification requests to the authoritative region
   560  	if !a.srv.config.ACLEnabled {
   561  		return aclDisabled
   562  	}
   563  
   564  	// Validate non-zero set of tokens
   565  	if len(args.AccessorIDs) == 0 {
   566  		return structs.NewErrRPCCoded(400, "must specify as least one token")
   567  	}
   568  
   569  	if done, err := a.srv.forward("ACL.DeleteTokens", args, args, reply); done {
   570  		return err
   571  	}
   572  	defer metrics.MeasureSince([]string{"nomad", "acl", "delete_tokens"}, time.Now())
   573  
   574  	// Check management level permissions
   575  	if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
   576  		return err
   577  	} else if acl == nil || !acl.IsManagement() {
   578  		return structs.ErrPermissionDenied
   579  	}
   580  
   581  	// Snapshot the state
   582  	state, err := a.srv.State().Snapshot()
   583  	if err != nil {
   584  		return err
   585  	}
   586  
   587  	// Determine if we are deleting local or global tokens
   588  	hasGlobal := false
   589  	allGlobal := true
   590  	nonexistentTokens := make([]string, 0)
   591  	for _, accessor := range args.AccessorIDs {
   592  		token, err := state.ACLTokenByAccessorID(nil, accessor)
   593  		if err != nil {
   594  			return structs.NewErrRPCCodedf(400, "token lookup failed: %v", err)
   595  		}
   596  		if token == nil {
   597  			nonexistentTokens = append(nonexistentTokens, accessor)
   598  			continue
   599  		}
   600  		if token.Global {
   601  			hasGlobal = true
   602  		} else {
   603  			allGlobal = false
   604  		}
   605  	}
   606  
   607  	if len(nonexistentTokens) != 0 {
   608  		return structs.NewErrRPCCodedf(400, "Cannot delete nonexistent tokens: %v", strings.Join(nonexistentTokens, ", "))
   609  	}
   610  
   611  	// Disallow mixed requests with global and non-global tokens since we forward
   612  	// the entire request as a single batch.
   613  	if hasGlobal {
   614  		if !allGlobal {
   615  			return structs.NewErrRPCCoded(400, "cannot delete mixed global and non-global tokens")
   616  		}
   617  
   618  		// Force the request to the authoritative region if it has global
   619  		if a.srv.config.Region != a.srv.config.AuthoritativeRegion {
   620  			args.Region = a.srv.config.AuthoritativeRegion
   621  			_, err := a.srv.forward("ACL.DeleteTokens", args, args, reply)
   622  			return err
   623  		}
   624  	}
   625  
   626  	// Update via Raft
   627  	_, index, err := a.srv.raftApply(structs.ACLTokenDeleteRequestType, args)
   628  	if err != nil {
   629  		return err
   630  	}
   631  
   632  	// Update the index
   633  	reply.Index = index
   634  	return nil
   635  }
   636  
   637  // ListTokens is used to list the tokens
   638  func (a *ACL) ListTokens(args *structs.ACLTokenListRequest, reply *structs.ACLTokenListResponse) error {
   639  	if !a.srv.config.ACLEnabled {
   640  		return aclDisabled
   641  	}
   642  	if done, err := a.srv.forward("ACL.ListTokens", args, args, reply); done {
   643  		return err
   644  	}
   645  	defer metrics.MeasureSince([]string{"nomad", "acl", "list_tokens"}, time.Now())
   646  
   647  	// Check management level permissions
   648  	if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
   649  		return err
   650  	} else if acl == nil || !acl.IsManagement() {
   651  		return structs.ErrPermissionDenied
   652  	}
   653  
   654  	// Setup the blocking query
   655  	opts := blockingOptions{
   656  		queryOpts: &args.QueryOptions,
   657  		queryMeta: &reply.QueryMeta,
   658  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
   659  			// Iterate over all the tokens
   660  			var err error
   661  			var iter memdb.ResultIterator
   662  			if prefix := args.QueryOptions.Prefix; prefix != "" {
   663  				iter, err = state.ACLTokenByAccessorIDPrefix(ws, prefix)
   664  			} else if args.GlobalOnly {
   665  				iter, err = state.ACLTokensByGlobal(ws, true)
   666  			} else {
   667  				iter, err = state.ACLTokens(ws)
   668  			}
   669  			if err != nil {
   670  				return err
   671  			}
   672  
   673  			// Convert all the tokens to a list stub
   674  			reply.Tokens = nil
   675  			for {
   676  				raw := iter.Next()
   677  				if raw == nil {
   678  					break
   679  				}
   680  				token := raw.(*structs.ACLToken)
   681  				reply.Tokens = append(reply.Tokens, token.Stub())
   682  			}
   683  
   684  			// Use the last index that affected the token table
   685  			index, err := state.Index("acl_token")
   686  			if err != nil {
   687  				return err
   688  			}
   689  			reply.Index = index
   690  			return nil
   691  		}}
   692  	return a.srv.blockingRPC(&opts)
   693  }
   694  
   695  // GetToken is used to get a specific token
   696  func (a *ACL) GetToken(args *structs.ACLTokenSpecificRequest, reply *structs.SingleACLTokenResponse) error {
   697  	if !a.srv.config.ACLEnabled {
   698  		return aclDisabled
   699  	}
   700  	if done, err := a.srv.forward("ACL.GetToken", args, args, reply); done {
   701  		return err
   702  	}
   703  	defer metrics.MeasureSince([]string{"nomad", "acl", "get_token"}, time.Now())
   704  
   705  	acl, err := a.srv.ResolveToken(args.AuthToken)
   706  	if err != nil {
   707  		return err
   708  	}
   709  
   710  	// Ensure ACLs are enabled and this call is made with one
   711  	if acl == nil {
   712  		return structs.ErrPermissionDenied
   713  	}
   714  
   715  	// Setup the blocking query
   716  	opts := blockingOptions{
   717  		queryOpts: &args.QueryOptions,
   718  		queryMeta: &reply.QueryMeta,
   719  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
   720  			// Look for the token
   721  			out, err := state.ACLTokenByAccessorID(ws, args.AccessorID)
   722  			if err != nil {
   723  				return err
   724  			}
   725  
   726  			if out == nil {
   727  				// If the token doesn't resolve, only allow management tokens to
   728  				// block.
   729  				if !acl.IsManagement() {
   730  					return structs.ErrPermissionDenied
   731  				}
   732  
   733  				// Check management level permissions or that the secret ID matches the
   734  				// accessor ID
   735  			} else if !acl.IsManagement() && out.SecretID != args.AuthToken {
   736  				return structs.ErrPermissionDenied
   737  			}
   738  
   739  			// Setup the output
   740  			reply.Token = out
   741  			if out != nil {
   742  				reply.Index = out.ModifyIndex
   743  			} else {
   744  				// Use the last index that affected the token table
   745  				index, err := state.Index("acl_token")
   746  				if err != nil {
   747  					return err
   748  				}
   749  				reply.Index = index
   750  			}
   751  			return nil
   752  		}}
   753  	return a.srv.blockingRPC(&opts)
   754  }
   755  
   756  // GetTokens is used to get a set of token
   757  func (a *ACL) GetTokens(args *structs.ACLTokenSetRequest, reply *structs.ACLTokenSetResponse) error {
   758  	if !a.srv.config.ACLEnabled {
   759  		return aclDisabled
   760  	}
   761  	if done, err := a.srv.forward("ACL.GetTokens", args, args, reply); done {
   762  		return err
   763  	}
   764  	defer metrics.MeasureSince([]string{"nomad", "acl", "get_tokens"}, time.Now())
   765  
   766  	// Check management level permissions
   767  	if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
   768  		return err
   769  	} else if acl == nil || !acl.IsManagement() {
   770  		return structs.ErrPermissionDenied
   771  	}
   772  
   773  	// Setup the blocking query
   774  	opts := blockingOptions{
   775  		queryOpts: &args.QueryOptions,
   776  		queryMeta: &reply.QueryMeta,
   777  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
   778  			// Setup the output
   779  			reply.Tokens = make(map[string]*structs.ACLToken, len(args.AccessorIDS))
   780  
   781  			// Look for the token
   782  			for _, accessor := range args.AccessorIDS {
   783  				out, err := state.ACLTokenByAccessorID(ws, accessor)
   784  				if err != nil {
   785  					return err
   786  				}
   787  				if out != nil {
   788  					reply.Tokens[out.AccessorID] = out
   789  				}
   790  			}
   791  
   792  			// Use the last index that affected the token table
   793  			index, err := state.Index("acl_token")
   794  			if err != nil {
   795  				return err
   796  			}
   797  			reply.Index = index
   798  			return nil
   799  		}}
   800  	return a.srv.blockingRPC(&opts)
   801  }
   802  
   803  // ResolveToken is used to lookup a specific token by a secret ID. This is used for enforcing ACLs by clients.
   804  func (a *ACL) ResolveToken(args *structs.ResolveACLTokenRequest, reply *structs.ResolveACLTokenResponse) error {
   805  	if !a.srv.config.ACLEnabled {
   806  		return aclDisabled
   807  	}
   808  	if done, err := a.srv.forward("ACL.ResolveToken", args, args, reply); done {
   809  		return err
   810  	}
   811  	defer metrics.MeasureSince([]string{"nomad", "acl", "resolve_token"}, time.Now())
   812  
   813  	// Setup the query meta
   814  	a.srv.setQueryMeta(&reply.QueryMeta)
   815  
   816  	// Snapshot the state
   817  	state, err := a.srv.State().Snapshot()
   818  	if err != nil {
   819  		return err
   820  	}
   821  
   822  	// Look for the token
   823  	out, err := state.ACLTokenBySecretID(nil, args.SecretID)
   824  	if err != nil {
   825  		return err
   826  	}
   827  
   828  	// Setup the output
   829  	reply.Token = out
   830  	if out != nil {
   831  		reply.Index = out.ModifyIndex
   832  	} else {
   833  		// Use the last index that affected the token table
   834  		index, err := state.Index("acl_token")
   835  		if err != nil {
   836  			return err
   837  		}
   838  		reply.Index = index
   839  	}
   840  	return nil
   841  }