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