diff --git a/.changelog/19578.txt b/.changelog/19578.txt new file mode 100644 index 000000000000..42dacee35a24 --- /dev/null +++ b/.changelog/19578.txt @@ -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 +``` diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index bea0dd98c7f7..63e7e0781276 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -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 } diff --git a/nomad/acl_endpoint_test.go b/nomad/acl_endpoint_test.go index 4dd5b292a04f..3d5a260b5808 100644 --- a/nomad/acl_endpoint_test.go +++ b/nomad/acl_endpoint_test.go @@ -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)