-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
client: split identity_hook across allocrunner and taskrunner (#18431)
This commit splits identity_hook between the allocrunner and taskrunner. The allocrunner-level part of the hook signs each task identity, and the taskrunner-level part picks it up and stores secrets for each task. The code revamps the WIDMgr, which is now split into 2 interfaces: IdentityManager which manages renewals of signatures and handles sending updates to subscribers via Watch method, and IdentitySigner which only does the signing. This work is necessary for having a unified Consul login workflow that comes with the new Consul integration. A new, allocrunner-level consul_hook will now be the only hook doing Consul authentication.
- Loading branch information
1 parent
cf8dde0
commit 86d2cdc
Showing
17 changed files
with
823 additions
and
403 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package allocrunner | ||
|
||
import ( | ||
"context" | ||
|
||
log "github.com/hashicorp/go-hclog" | ||
"github.com/hashicorp/nomad/client/allocrunner/interfaces" | ||
"github.com/hashicorp/nomad/client/widmgr" | ||
) | ||
|
||
type identityHook struct { | ||
widmgr widmgr.IdentityManager | ||
logger log.Logger | ||
} | ||
|
||
func newIdentityHook(logger log.Logger, widmgr widmgr.IdentityManager) *identityHook { | ||
h := &identityHook{ | ||
widmgr: widmgr, | ||
} | ||
h.logger = logger.Named(h.Name()) | ||
return h | ||
} | ||
|
||
func (*identityHook) Name() string { | ||
return "identity" | ||
} | ||
|
||
func (h *identityHook) Prerun() error { | ||
// run the renewal | ||
if err := h.widmgr.Run(); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Stop implements interfaces.TaskStopHook | ||
func (h *identityHook) Stop(context.Context, *interfaces.TaskStopRequest, *interfaces.TaskStopResponse) error { | ||
h.widmgr.Shutdown() | ||
return nil | ||
} | ||
|
||
// Shutdown implements interfaces.ShutdownHook | ||
func (h *identityHook) Shutdown() { | ||
h.widmgr.Shutdown() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package allocrunner | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
"time" | ||
|
||
"github.com/hashicorp/nomad/ci" | ||
"github.com/hashicorp/nomad/client/allocrunner/interfaces" | ||
cstructs "github.com/hashicorp/nomad/client/structs" | ||
"github.com/hashicorp/nomad/client/widmgr" | ||
"github.com/hashicorp/nomad/helper/testlog" | ||
"github.com/hashicorp/nomad/nomad/mock" | ||
"github.com/hashicorp/nomad/nomad/structs" | ||
"github.com/shoenig/test/must" | ||
) | ||
|
||
// statically assert network hook implements the expected interfaces | ||
var _ interfaces.RunnerPrerunHook = (*identityHook)(nil) | ||
var _ interfaces.ShutdownHook = (*identityHook)(nil) | ||
var _ interfaces.TaskStopHook = (*identityHook)(nil) | ||
|
||
func TestIdentityHook_Prerun(t *testing.T) { | ||
ci.Parallel(t) | ||
|
||
ttl := 30 * time.Second | ||
|
||
wid := &structs.WorkloadIdentity{ | ||
Name: "testing", | ||
Audience: []string{"consul.io"}, | ||
Env: true, | ||
File: true, | ||
TTL: ttl, | ||
} | ||
|
||
alloc := mock.Alloc() | ||
task := alloc.LookupTask("web") | ||
task.Identity = wid | ||
task.Identities = []*structs.WorkloadIdentity{wid} | ||
|
||
allocrunner, stopAR := TestAllocRunnerFromAlloc(t, alloc) | ||
defer stopAR() | ||
|
||
logger := testlog.HCLogger(t) | ||
|
||
// setup mock signer and WIDMgr | ||
mockSigner := widmgr.NewMockWIDSigner(task.Identities) | ||
mockWIDMgr := widmgr.NewWIDMgr(mockSigner, alloc, logger) | ||
allocrunner.widmgr = mockWIDMgr | ||
allocrunner.widsigner = mockSigner | ||
|
||
// do the initial signing | ||
_, err := mockSigner.SignIdentities(1, []*structs.WorkloadIdentityRequest{ | ||
{ | ||
AllocID: alloc.ID, | ||
TaskName: task.Name, | ||
IdentityName: task.Identities[0].Name, | ||
}, | ||
}) | ||
must.NoError(t, err) | ||
|
||
start := time.Now() | ||
hook := newIdentityHook(logger, mockWIDMgr) | ||
must.Eq(t, hook.Name(), "identity") | ||
must.NoError(t, hook.Prerun()) | ||
|
||
time.Sleep(time.Second) // give goroutines a moment to run | ||
sid, err := hook.widmgr.Get(cstructs.TaskIdentity{ | ||
TaskName: task.Name, | ||
IdentityName: task.Identities[0].Name}, | ||
) | ||
must.Nil(t, err) | ||
must.Eq(t, sid.IdentityName, task.Identity.Name) | ||
must.NotEq(t, sid.JWT, "") | ||
|
||
// pad expiry time with a second to be safe | ||
must.Between(t, | ||
start.Add(ttl).Add(-1*time.Second).Unix(), | ||
sid.Expiration.Unix(), | ||
start.Add(ttl).Add(1*time.Second).Unix(), | ||
) | ||
|
||
must.NoError(t, hook.Stop(context.Background(), nil, nil)) | ||
} |
Oops, something went wrong.