Repository: hashicorp/nomad
File: nomad/acl_endpoint.go (Go)

Code before:
	}

	// Setup the blocking query
	opts := blockingOptions{
		queryOpts: &args.QueryOptions,
		queryMeta: &reply.QueryMeta,
		run: func(ws memdb.WatchSet, state *state.StateStore) error {
			// Setup the output
			reply.Policies = make(map[string]*structs.ACLPolicy)

			// Look for the policy and check whether the caller has the
			// permission to view it. This endpoint is used by the replication
			// process, or Nomad clients looking up a callers policies. It is
			// therefore safe, to perform auth checks here and ensures we do
			// not return erroneous permission denied errors when a caller uses
			// a token with dangling policies.
			for _, policyName := range args.Names {
				out, err := state.ACLPolicyByName(ws, policyName)
				if err != nil {
					return err
				}
				if out == nil {
					continue
				}

				if !mgt && !tokenPolicyNames.Contains(policyName) {
					return structs.ErrPermissionDenied
				}
				reply.Policies[policyName] = out
			}

			// Use the last index that affected the policy table
			index, err := state.Index("acl_policy")
			if err != nil {
				return err
			}
			reply.Index = index
			return nil
		}}
	return a.srv.blockingRPC(&opts)
}

// GetClaimPolicies return the ACLPolicy objects for a workload identity.
// Similar to GetPolicies except an error will *not* be returned if ACLs are
// disabled.
func (a *ACL) GetClaimPolicies(args *structs.GenericRequest, reply *structs.ACLPolicySetResponse) error {
	authErr := a.srv.Authenticate(a.ctx, args)
	if done, err := a.srv.forward("ACL.GetClaimPolicies", args, args, reply); done {
		return err
	}
	a.srv.MeasureRPCRate("acl", structs.RateMetricList, args)

Review comment (security):
the loosely-coupled relationship between the `mgt` `bool` and the `nil`-ness of `tokenPolicyNames` has me nervous about accidentally causing a panic...  I would like to think a test would blow up if there was a code error like that, but I'm still like 😬

up in `ListPolicies` it's `if mgt || tokenPolicyNames.Contains(...`, which is different but similar loose coupling.

`GetPolicies` doesn't trigger me, because they are directly coupled -- `tokenPolicyNames` is only created, and used, within an `if !mgt{}`

sometimes I worry I'm over-sensitive about nil panics

Code after:
			// Look for the policy and check whether the caller has the
			// permission to view it. This endpoint is used by the replication
			// process, or Nomad clients looking up a callers policies. It is
			// therefore safe, to perform auth checks here and ensures we do
			// not return erroneous permission denied errors when a caller uses
			// a token with dangling policies.
			for _, policyName := range args.Names {
				out, err := state.ACLPolicyByName(ws, policyName)
				if err != nil {
					return err
				}
				if out == nil {
					continue
				}

				if !allowedPolicyFn(policyName) {
					return structs.ErrPermissionDenied
				}
				reply.Policies[policyName] = out
			}

			// Use the last index that affected the policy table
			index, err := state.Index("acl_policy")
			if err != nil {
				return err
			}
			reply.Index = index
			return nil
		}}
	return a.srv.blockingRPC(&opts)
}

// GetClaimPolicies return the ACLPolicy objects for a workload identity.
// Similar to GetPolicies except an error will *not* be returned if ACLs are
// disabled.
func (a *ACL) GetClaimPolicies(args *structs.GenericRequest, reply *structs.ACLPolicySetResponse) error {
	authErr := a.srv.Authenticate(a.ctx, args)
	if done, err := a.srv.forward("ACL.GetClaimPolicies", args, args, reply); done {
		return err
	}
	a.srv.MeasureRPCRate("acl", structs.RateMetricList, args)
	if authErr != nil {
		return structs.ErrPermissionDenied
	}
	defer metrics.MeasureSince([]string{"nomad", "acl", "get_claim_policies"}, time.Now())

	// Should only be called using a workload identity
	claims := args.GetIdentity().Claims
	if claims == nil {
		// Calling this RPC without a workload identity is either a bug or an
		// attacker as this RPC is not exposed to users directly.