Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/28133.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
consul: Added the issuing Nomad client's node ID to the metadata of Consul tokens created via workload identity
```
2 changes: 2 additions & 0 deletions client/allocrunner/consul_hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ func (h *consulHook) prepareConsulTokensForTask(task *structs.Task, tg *structs.
AuthMethodName: consulConfig.TaskIdentityAuthMethod,
Meta: map[string]string{
"requested_by": fmt.Sprintf("nomad_task_%s", task.Name),
"node_id": h.alloc.NodeID,
},
}

Expand Down Expand Up @@ -225,6 +226,7 @@ func (h *consulHook) prepareConsulTokensForServices(services []*structs.Service,
AuthMethodName: consulConfig.ServiceIdentityAuthMethod,
Meta: map[string]string{
"requested_by": fmt.Sprintf("nomad_service_%s", ti.InterpolatedWorkloadIdentifier),
"node_id": h.alloc.NodeID,
},
}

Expand Down
49 changes: 36 additions & 13 deletions client/allocrunner/consul_hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

consulapi "github.com/hashicorp/consul/api"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/client/consul"
cstate "github.com/hashicorp/nomad/client/state"
Expand All @@ -23,7 +24,7 @@ import (
"github.com/shoenig/test/must"
)

func consulHookTestHarness(t *testing.T) *consulHook {
func consulHookTestHarness(t *testing.T) (*consulHook, *consul.MockConsulClient) {
logger := testlog.HCLogger(t)

alloc := mock.Alloc()
Expand Down Expand Up @@ -69,23 +70,27 @@ func consulHookTestHarness(t *testing.T) *consulHook {

hookResources := cstructs.NewAllocHookResources()

mockClient := &consul.MockConsulClient{}

consulHookCfg := consulHookConfig{
alloc: alloc,
allocdir: nil,
widmgr: mockWIDMgr,
consulConfigs: consulConfigs,
consulClientConstructor: consul.NewMockConsulClient,
hookResources: hookResources,
db: db,
logger: logger,
alloc: alloc,
allocdir: nil,
widmgr: mockWIDMgr,
consulConfigs: consulConfigs,
consulClientConstructor: func(_ *structsc.ConsulConfig, _ hclog.Logger) (consul.Client, error) {
return mockClient, nil
},
hookResources: hookResources,
db: db,
logger: logger,
}
return newConsulHook(consulHookCfg)
return newConsulHook(consulHookCfg), mockClient
}

func Test_consulHook_prepareConsulTokensForTask(t *testing.T) {
ci.Parallel(t)

hook := consulHookTestHarness(t)
hook, _ := consulHookTestHarness(t)
task := hook.alloc.LookupTask("web")

wid := task.GetIdentity("consul_default")
Expand Down Expand Up @@ -178,7 +183,7 @@ func Test_consulHook_prepareConsulTokensForTask(t *testing.T) {
func Test_consulHook_prepareConsulTokensForServices(t *testing.T) {
ci.Parallel(t)

hook := consulHookTestHarness(t)
hook, _ := consulHookTestHarness(t)
task := hook.alloc.LookupTask("web")
services := task.Services
env := taskenv.NewBuilder(mock.Node(), hook.alloc, task, "global").
Expand Down Expand Up @@ -258,7 +263,7 @@ func Test_consulHook_Postrun(t *testing.T) {
ci.Parallel(t)

// no-op must be safe
hook := consulHookTestHarness(t)
hook, _ := consulHookTestHarness(t)
must.NoError(t, hook.Postrun())

task := hook.alloc.LookupTask("web")
Expand All @@ -277,3 +282,21 @@ func Test_consulHook_Postrun(t *testing.T) {
tokens = hook.resourcesBackend.getConsulTokens()
must.MapEmpty(t, tokens["default"])
}

func Test_consulHook_consulTokenMetaIncludesNodeID(t *testing.T) {
ci.Parallel(t)

hook, mockClient := consulHookTestHarness(t)
task := hook.alloc.LookupTask("web")

tokens := map[string]map[string]*consulapi.ACLToken{}
must.NoError(t, hook.prepareConsulTokensForTask(task, nil, tokens))

found := false
for _, req := range mockClient.Requests {
if req.Meta["node_id"] == hook.alloc.NodeID {
found = true
}
}
must.True(t, found, must.Sprint("expected node_id in the Consul login request meta"))
}
5 changes: 4 additions & 1 deletion client/consul/consul_testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
)

type MockConsulClient struct {
tokens map[string]*consulapi.ACLToken
tokens map[string]*consulapi.ACLToken
Requests []JWTLoginRequest
}

func NewMockConsulClient(config *config.ConsulConfig, logger hclog.Logger) (Client, error) {
Expand All @@ -25,6 +26,8 @@ func NewMockConsulClient(config *config.ConsulConfig, logger hclog.Logger) (Clie
// the request ID for the AccessorID and the md5 checksum of the request ID for
// the SecretID
func (mc *MockConsulClient) DeriveTokenWithJWT(req JWTLoginRequest) (*consulapi.ACLToken, error) {
mc.Requests = append(mc.Requests, req)

if t, ok := mc.tokens[req.JWT]; ok {
return t, nil
}
Expand Down
Loading