From 0c5f6ea111930a69a08242e677a994e6d669a51c Mon Sep 17 00:00:00 2001 From: Hans Hasselberg Date: Tue, 9 Jun 2020 21:13:09 +0200 Subject: [PATCH] acl: do not resolve local tokens from remote dcs (#8068) --- agent/consul/acl.go | 3 +++ agent/consul/acl_endpoint.go | 1 + agent/consul/acl_test.go | 46 ++++++++++++++++++++++++++++++++++++ agent/structs/acl.go | 5 ++-- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/agent/consul/acl.go b/agent/consul/acl.go index 47220dd10c44..6452fdb1aee8 100644 --- a/agent/consul/acl.go +++ b/agent/consul/acl.go @@ -413,6 +413,9 @@ func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *struc if resp.Token == nil { r.cache.PutIdentity(cacheID, nil) return nil, acl.ErrNotFound + } else if resp.Token.Local && r.config.Datacenter != resp.SourceDatacenter { + r.cache.PutIdentity(cacheID, nil) + return nil, acl.PermissionDeniedError{Cause: fmt.Sprintf("This is a local token in datacenter %q", resp.SourceDatacenter)} } else { r.cache.PutIdentity(cacheID, resp.Token) return resp.Token, nil diff --git a/agent/consul/acl_endpoint.go b/agent/consul/acl_endpoint.go index 1f1f92a08e56..f2d98a826424 100644 --- a/agent/consul/acl_endpoint.go +++ b/agent/consul/acl_endpoint.go @@ -259,6 +259,7 @@ func (a *ACL) TokenRead(args *structs.ACLTokenGetRequest, reply *structs.ACLToke } reply.Index, reply.Token = index, token + reply.SourceDatacenter = args.Datacenter return nil }) } diff --git a/agent/consul/acl_test.go b/agent/consul/acl_test.go index e02ce2614259..b860629842cd 100644 --- a/agent/consul/acl_test.go +++ b/agent/consul/acl_test.go @@ -3622,3 +3622,49 @@ func TestDedupeServiceIdentities(t *testing.T) { }) } } +func TestACL_LocalToken(t *testing.T) { + t.Run("local token in same dc", func(t *testing.T) { + d := &ACLResolverTestDelegate{ + datacenter: "dc1", + tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { + reply.Token = &structs.ACLToken{Local: true} + // different dc + reply.SourceDatacenter = "dc1" + return nil + }, + } + r := newTestACLResolver(t, d, nil) + _, err := r.fetchAndCacheIdentityFromToken("", nil) + require.NoError(t, err) + }) + + t.Run("non local token in remote dc", func(t *testing.T) { + d := &ACLResolverTestDelegate{ + datacenter: "dc1", + tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { + reply.Token = &structs.ACLToken{Local: false} + // different dc + reply.SourceDatacenter = "remote" + return nil + }, + } + r := newTestACLResolver(t, d, nil) + _, err := r.fetchAndCacheIdentityFromToken("", nil) + require.NoError(t, err) + }) + + t.Run("local token in remote dc", func(t *testing.T) { + d := &ACLResolverTestDelegate{ + datacenter: "dc1", + tokenReadFn: func(_ *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { + reply.Token = &structs.ACLToken{Local: true} + // different dc + reply.SourceDatacenter = "remote" + return nil + }, + } + r := newTestACLResolver(t, d, nil) + _, err := r.fetchAndCacheIdentityFromToken("", nil) + require.Equal(t, acl.PermissionDeniedError{Cause: "This is a local token in datacenter \"remote\""}, err) + }) +} diff --git a/agent/structs/acl.go b/agent/structs/acl.go index 84a09682aa7a..92a7cf6aabdf 100644 --- a/agent/structs/acl.go +++ b/agent/structs/acl.go @@ -1195,8 +1195,9 @@ type ACLTokenBootstrapRequest struct { // ACLTokenResponse returns a single Token + metadata type ACLTokenResponse struct { - Token *ACLToken - Redacted bool // whether the token's secret was redacted + Token *ACLToken + Redacted bool // whether the token's secret was redacted + SourceDatacenter string QueryMeta }