mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 08:55:43 +03:00
Allow Node.SecretID for GetNode and GetAlloc
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/nomad/acl"
|
||||
"github.com/hashicorp/nomad/nomad/state"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
@@ -81,7 +82,25 @@ func (a *Alloc) GetAlloc(args *structs.AllocSpecificRequest,
|
||||
|
||||
// Check namespace read-job permissions
|
||||
if aclObj, err := a.srv.ResolveToken(args.AuthToken); err != nil {
|
||||
return err
|
||||
// If ResolveToken had an unexpected error return that
|
||||
if err != structs.ErrTokenNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
// Attempt to lookup AuthToken as a Node.SecretID since nodes
|
||||
// call this endpoint and don't have an ACL token.
|
||||
node, stateErr := a.srv.fsm.State().NodeBySecretID(nil, args.AuthToken)
|
||||
if stateErr != nil {
|
||||
// Return the original ResolveToken error with this err
|
||||
var merr multierror.Error
|
||||
merr.Errors = append(merr.Errors, err, stateErr)
|
||||
return merr.ErrorOrNil()
|
||||
}
|
||||
|
||||
// Not a node or a valid ACL token
|
||||
if node == nil {
|
||||
return structs.ErrTokenNotFound
|
||||
}
|
||||
} else if aclObj != nil && !aclObj.AllowNsOp(args.RequestNamespace(), acl.NamespaceCapabilityReadJob) {
|
||||
return structs.ErrPermissionDenied
|
||||
}
|
||||
|
||||
@@ -267,32 +267,55 @@ func TestAllocEndpoint_GetAlloc_ACL(t *testing.T) {
|
||||
invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid",
|
||||
mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityListJobs}))
|
||||
|
||||
// Lookup the alloc without a token and expect failure
|
||||
get := &structs.AllocSpecificRequest{
|
||||
AllocID: alloc.ID,
|
||||
QueryOptions: structs.QueryOptions{Region: "global"},
|
||||
}
|
||||
var resp structs.SingleAllocResponse
|
||||
assert.NotNil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
|
||||
|
||||
// Try with a valid token
|
||||
get.AuthToken = validToken.SecretID
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
|
||||
assert.EqualValues(resp.Index, 1000, "resp.Index")
|
||||
assert.Equal(alloc, resp.Alloc, "Returned alloc not equal")
|
||||
// Lookup the alloc without a token and expect failure
|
||||
{
|
||||
var resp structs.SingleAllocResponse
|
||||
err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp)
|
||||
assert.Equal(structs.ErrPermissionDenied.Error(), err.Error())
|
||||
}
|
||||
|
||||
// Try with a valid ACL token
|
||||
{
|
||||
get.AuthToken = validToken.SecretID
|
||||
var resp structs.SingleAllocResponse
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
|
||||
assert.EqualValues(resp.Index, 1000, "resp.Index")
|
||||
assert.Equal(alloc, resp.Alloc, "Returned alloc not equal")
|
||||
}
|
||||
|
||||
// Try with a valid Node.SecretID
|
||||
{
|
||||
node := mock.Node()
|
||||
assert.Nil(state.UpsertNode(1005, node))
|
||||
get.AuthToken = node.SecretID
|
||||
var resp structs.SingleAllocResponse
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
|
||||
assert.EqualValues(resp.Index, 1000, "resp.Index")
|
||||
assert.Equal(alloc, resp.Alloc, "Returned alloc not equal")
|
||||
}
|
||||
|
||||
// Try with a invalid token
|
||||
get.AuthToken = invalidToken.SecretID
|
||||
err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp)
|
||||
assert.NotNil(err, "RPC")
|
||||
assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
|
||||
{
|
||||
get.AuthToken = invalidToken.SecretID
|
||||
var resp structs.SingleAllocResponse
|
||||
err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp)
|
||||
assert.NotNil(err, "RPC")
|
||||
assert.Equal(err.Error(), structs.ErrPermissionDenied.Error())
|
||||
}
|
||||
|
||||
// Try with a root token
|
||||
get.AuthToken = root.SecretID
|
||||
var resp2 structs.SingleAllocResponse
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp2), "RPC")
|
||||
assert.EqualValues(resp2.Index, 1000, "resp.Index")
|
||||
assert.Equal(alloc, resp2.Alloc, "Returned alloc not equal")
|
||||
{
|
||||
get.AuthToken = root.SecretID
|
||||
var resp structs.SingleAllocResponse
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp), "RPC")
|
||||
assert.EqualValues(resp.Index, 1000, "resp.Index")
|
||||
assert.Equal(alloc, resp.Alloc, "Returned alloc not equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocEndpoint_GetAlloc_Blocking(t *testing.T) {
|
||||
|
||||
@@ -507,8 +507,26 @@ func (n *Node) GetNode(args *structs.NodeSpecificRequest,
|
||||
defer metrics.MeasureSince([]string{"nomad", "client", "get_node"}, time.Now())
|
||||
|
||||
// Check node read permissions
|
||||
if aclObj, err := n.srv.ResolveToken(args.SecretID); err != nil {
|
||||
return err
|
||||
if aclObj, err := n.srv.ResolveToken(args.AuthToken); err != nil {
|
||||
// If ResolveToken had an unexpected error return that
|
||||
if err != structs.ErrTokenNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
// Attempt to lookup AuthToken as a Node.SecretID since nodes
|
||||
// call this endpoint and don't have an ACL token.
|
||||
node, stateErr := n.srv.fsm.State().NodeBySecretID(nil, args.AuthToken)
|
||||
if stateErr != nil {
|
||||
// Return the original ResolveToken error with this err
|
||||
var merr multierror.Error
|
||||
merr.Errors = append(merr.Errors, err, stateErr)
|
||||
return merr.ErrorOrNil()
|
||||
}
|
||||
|
||||
// Not a node or a valid ACL token
|
||||
if node == nil {
|
||||
return structs.ErrTokenNotFound
|
||||
}
|
||||
} else if aclObj != nil && !aclObj.AllowNodeRead() {
|
||||
return structs.ErrPermissionDenied
|
||||
}
|
||||
|
||||
@@ -941,7 +941,15 @@ func TestClientEndpoint_GetNode_ACL(t *testing.T) {
|
||||
}
|
||||
|
||||
// Try with a valid token
|
||||
req.SecretID = validToken.SecretID
|
||||
req.AuthToken = validToken.SecretID
|
||||
{
|
||||
var resp structs.SingleNodeResponse
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp), "RPC")
|
||||
assert.Equal(node.ID, resp.Node.ID)
|
||||
}
|
||||
|
||||
// Try with a Node.SecretID
|
||||
req.AuthToken = node.SecretID
|
||||
{
|
||||
var resp structs.SingleNodeResponse
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp), "RPC")
|
||||
@@ -949,7 +957,7 @@ func TestClientEndpoint_GetNode_ACL(t *testing.T) {
|
||||
}
|
||||
|
||||
// Try with a invalid token
|
||||
req.SecretID = invalidToken.SecretID
|
||||
req.AuthToken = invalidToken.SecretID
|
||||
{
|
||||
var resp structs.SingleNodeResponse
|
||||
err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp)
|
||||
@@ -958,7 +966,7 @@ func TestClientEndpoint_GetNode_ACL(t *testing.T) {
|
||||
}
|
||||
|
||||
// Try with a root token
|
||||
req.SecretID = root.SecretID
|
||||
req.AuthToken = root.SecretID
|
||||
{
|
||||
var resp structs.SingleNodeResponse
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp), "RPC")
|
||||
|
||||
Reference in New Issue
Block a user