Skip to content

Commit

Permalink
acl: remove timestamps from WhoAmI response (hashicorp#19578)
Browse files Browse the repository at this point in the history
In Nomad 1.7 we updated our JWT library to go-jose, but this changed the wire
format of the embedded struct we have in the `IdentityClaims` struct that we
return as part of the `WhoAmI` RPC response. This wasn't originally intended to
be sent over the wire but other changes in Nomad 1.5+ added a caller to the
client. The library change causes a deserialization error on Nomad 1.5 and 1.6
clients, which prevents access to Nomad Variables and SD via template blocks.

Removed the incompatible fields from the response, which are unused by any
current caller. In a future version of Nomad, we'll likely remove the `WhoAmI`
callers from the client in lieu of using the public keys the clients have to
check auth.

Fixes: hashicorp#19555
  • Loading branch information
tgross authored and nvanthao committed Mar 1, 2024
1 parent 8e6420e commit 06bcd89
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/19578.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
acl: Fixed a bug where 1.5 and 1.6 clients could not access Nomad Variables and Services via templates
```
10 changes: 10 additions & 0 deletions nomad/acl_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -2182,6 +2182,16 @@ func (a *ACL) WhoAmI(args *structs.GenericRequest, reply *structs.ACLWhoAmIRespo
}

reply.Identity = args.GetIdentity()

// COMPAT: originally these were time.Time objects but switching to go-jose
// changed them to int64 which aren't compatible with Nomad versions
// <1.7. These aren't used by any existing callers of this handler.
if reply.Identity.Claims != nil {
reply.Identity.Claims.Expiry = nil
reply.Identity.Claims.IssuedAt = nil
reply.Identity.Claims.NotBefore = nil
}

return nil
}

Expand Down
45 changes: 45 additions & 0 deletions nomad/acl_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,51 @@ func TestACLEndpoint_ResolveToken(t *testing.T) {
assert.Nil(t, resp.Token)
}

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

s1, _, cleanupS1 := TestACLServer(t, nil)
t.Cleanup(cleanupS1)
codec := rpcClient(t, s1)
testutil.WaitForKeyring(t, s1.RPC, "global")

// Create the register request
token := mock.ACLToken()
s1.fsm.State().UpsertACLTokens(structs.MsgTypeTestSetup, 1000, []*structs.ACLToken{token})

// Lookup via token
get := &structs.GenericRequest{
QueryOptions: structs.QueryOptions{Region: "global", AuthToken: token.SecretID},
}
var resp structs.ACLWhoAmIResponse
err := msgpackrpc.CallWithCodec(codec, "ACL.WhoAmI", get, &resp)
must.NoError(t, err)
must.Eq(t, token, resp.Identity.ACLToken)

// Lookup non-existing token
get.AuthToken = uuid.Generate()
var resp2 structs.ACLWhoAmIResponse
err = msgpackrpc.CallWithCodec(codec, "ACL.WhoAmI", get, &resp2)
must.EqError(t, err, structs.ErrPermissionDenied.Error())
must.Nil(t, resp2.Identity)

// Lookup identity claim
alloc := mock.Alloc()
s1.fsm.State().UpsertAllocs(structs.MsgTypeTestSetup, 1500, []*structs.Allocation{alloc})
claims := structs.NewIdentityClaims(alloc.Job, alloc,
wiHandle, // see encrypter_test.go
alloc.LookupTask("web").Identity, time.Now().Add(-10*time.Minute))
jwtToken, _, err := s1.encrypter.SignClaims(claims)
must.NoError(t, err)

get.AuthToken = jwtToken
var resp3 structs.ACLWhoAmIResponse
err = msgpackrpc.CallWithCodec(codec, "ACL.WhoAmI", get, &resp3)
must.NoError(t, err)
must.NotNil(t, resp3.Identity.Claims)
must.Eq(t, alloc.ID, resp3.Identity.Claims.AllocationID)
}

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

Expand Down

0 comments on commit 06bcd89

Please sign in to comment.