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