From bac5d45dd2c5be71e23243b6ac5058089f957bbb Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 14 Jan 2022 14:51:18 -0500 Subject: [PATCH 1/6] Create anonymous-policy and token from non-default partitions. --- .circleci/config.yml | 2 +- .../subcommand/server-acl-init/command.go | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 48f27ca0cb..08e847549e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,7 @@ commands: type: string consul-k8s-image: type: string - default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" + default: "ashwinvenkatesh/consul-k8s@sha256:9b46fae446fcf99c715d9063231857eef5525830f2cd3cdcb46266c84db11deb" go-path: type: string default: "/home/circleci/.go_workspace" diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index a5daefc8f5..1d710de7e7 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -451,7 +451,21 @@ func (c *Command) Run(args []string) int { } if c.createAnonymousPolicy(isPrimary) { - err := c.configureAnonymousPolicy(consulClient) + // When the default partition is in a VM, the anonymous policy does not allow cross-partition + // DNS lookups. The anonymous policy in the default partition needs to be updated in order to + // support this use-case. Creating a separate anonymous token client that updates the anonymous + // policy and token in the default partition ensures this works. + anonTokenConfig := clientConfig + if c.flagEnablePartitions { + anonTokenConfig.Partition = consulDefaultPartition + } + anonTokenClient, err := consul.NewClient(anonTokenConfig) + if err != nil { + c.log.Error(err.Error()) + return 1 + } + + err = c.configureAnonymousPolicy(anonTokenClient) if err != nil { c.log.Error(err.Error()) return 1 @@ -793,12 +807,6 @@ type Config struct { // createAnonymousPolicy returns whether we should create a policy for the // anonymous ACL token, i.e. queries without ACL tokens. func (c *Command) createAnonymousPolicy(isPrimary bool) bool { - // Don't try to create the anonymous policy in non-default partitions because - // non-default partitions will use the anonymous policy from the default - // partition. - if c.flagEnablePartitions && c.flagPartitionName != "default" { - return false - } // If isPrimary is not set then we're in a secondary DC. // In this case we assume that the primary datacenter has already created // the anonymous policy and attached it to the anonymous token. From 03c7e3bcb4c97f929d434e61c3cd66db910bd329 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 20 Jan 2022 11:24:07 -0500 Subject: [PATCH 2/6] Add unit test for anonymous token behavior. --- .../endpoints_controller_ent_test.go | 4 +- .../endpoints_controller_test.go | 6 +- control-plane/go.mod | 2 + control-plane/go.sum | 4 +- control-plane/namespaces/namespaces_test.go | 4 +- .../connect-init/command_ent_test.go | 2 +- .../subcommand/connect-init/command_test.go | 2 +- .../server-acl-init/command_ent_test.go | 87 +++++++++++++++++++ .../server-acl-init/command_test.go | 4 +- .../server-acl-init/create_or_update_test.go | 2 +- 10 files changed, 103 insertions(+), 14 deletions(-) diff --git a/control-plane/connect-inject/endpoints_controller_ent_test.go b/control-plane/connect-inject/endpoints_controller_ent_test.go index 7d333783c8..5859bd9206 100644 --- a/control-plane/connect-inject/endpoints_controller_ent_test.go +++ b/control-plane/connect-inject/endpoints_controller_ent_test.go @@ -1180,7 +1180,7 @@ func TestReconcileUpdateEndpointWithNamespaces(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = true - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) @@ -1514,7 +1514,7 @@ func TestReconcileDeleteEndpointWithNamespaces(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = true - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 846c1c434e..96f6f198ee 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -127,7 +127,7 @@ func TestProcessUpstreamsTLSandACLs(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true c.ACL.DefaultPolicy = "deny" - c.ACL.Tokens.Master = masterToken + c.ACL.Tokens.InitialManagement = masterToken c.CAFile = caFile c.CertFile = certFile c.KeyFile = keyFile @@ -2340,7 +2340,7 @@ func TestReconcileUpdateEndpoint(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = tt.enableACLs - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) @@ -2627,7 +2627,7 @@ func TestReconcileDeleteEndpoint(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = true - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) diff --git a/control-plane/go.mod b/control-plane/go.mod index 93e5bc5c77..e8842f4643 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -129,4 +129,6 @@ require ( sigs.k8s.io/yaml v1.2.0 // indirect ) +replace github.com/hashicorp/consul/sdk v0.9.0 => github.com/hashicorp/consul/sdk v0.4.1-0.20220120214936-7568f3a102a8 + go 1.17 diff --git a/control-plane/go.sum b/control-plane/go.sum index 879cb915bf..42ee98bb0f 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -300,9 +300,9 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/api v1.12.0 h1:k3y1FYv6nuKyNTqj6w9gXOx5r5CfLj/k/euUeBXj1OY= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.4.1-0.20220120214936-7568f3a102a8 h1:1O/CANaJGcL6urr47PLoPZ0oQcGLUlGpYoRLYAYFSDs= +github.com/hashicorp/consul/sdk v0.4.1-0.20220120214936-7568f3a102a8/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/consul/sdk v0.9.0 h1:NGSHAU7X3yDCjo8WBUbNOtD3BSqv8u0vu3+zNxgmxQI= -github.com/hashicorp/consul/sdk v0.9.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= diff --git a/control-plane/namespaces/namespaces_test.go b/control-plane/namespaces/namespaces_test.go index 8cd3d316fd..7b6a061a65 100644 --- a/control-plane/namespaces/namespaces_test.go +++ b/control-plane/namespaces/namespaces_test.go @@ -33,7 +33,7 @@ func TestEnsureExists_AlreadyExists(tt *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(cfg *testutil.TestServerConfig) { cfg.ACL.Enabled = c.ACLsEnabled cfg.ACL.DefaultPolicy = "deny" - cfg.ACL.Tokens.Master = masterToken + cfg.ACL.Tokens.InitialManagement = masterToken }) req.NoError(err) defer consul.Stop() @@ -104,7 +104,7 @@ func TestEnsureExists_CreatesNS(tt *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(cfg *testutil.TestServerConfig) { cfg.ACL.Enabled = c.ACLsEnabled cfg.ACL.DefaultPolicy = "deny" - cfg.ACL.Tokens.Master = masterToken + cfg.ACL.Tokens.InitialManagement = masterToken }) req.NoError(err) defer consul.Stop() diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index 50b52f44e2..f043542d83 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -136,7 +136,7 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { if c.acls { cfg.ACL.Enabled = true cfg.ACL.DefaultPolicy = "deny" - cfg.ACL.Tokens.Master = masterToken + cfg.ACL.Tokens.InitialManagement = masterToken } if c.tls { caFile, certFile, keyFile = test.GenerateServerCerts(t) diff --git a/control-plane/subcommand/connect-init/command_test.go b/control-plane/subcommand/connect-init/command_test.go index ff847bf0fb..40136b9fd8 100644 --- a/control-plane/subcommand/connect-init/command_test.go +++ b/control-plane/subcommand/connect-init/command_test.go @@ -122,7 +122,7 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { server, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true c.ACL.DefaultPolicy = "deny" - c.ACL.Tokens.Master = masterToken + c.ACL.Tokens.InitialManagement = masterToken if tt.tls { caFile, certFile, keyFile = test.GenerateServerCerts(t) c.CAFile = caFile diff --git a/control-plane/subcommand/server-acl-init/command_ent_test.go b/control-plane/subcommand/server-acl-init/command_ent_test.go index af240e4960..2ad763d62b 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -7,6 +7,8 @@ import ( "strings" "testing" + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil" "github.com/mitchellh/cli" @@ -206,6 +208,54 @@ func TestRun_ConnectInject_NamespaceMirroring(t *testing.T) { } } +// Test that the anonymous token is created in the default partition from +// a non-default partition. +func TestRun_AnonymousToken_CreatedFromNonDefaultPartition(t *testing.T) { + bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + tokenFile := common.WriteTempFile(t, bootToken) + server, stopFn := partitionedSetup(t, bootToken, "test") + defer stopFn() + k8s := fake.NewSimpleClientset() + setUpK8sServiceAccount(t, k8s, ns) + + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + clientset: k8s, + } + cmd.init() + args := []string{ + "-server-address=" + strings.Split(server.HTTPAddr, ":")[0], + "-server-port=" + strings.Split(server.HTTPAddr, ":")[1], + "-resource-prefix=" + resourcePrefix, + "-k8s-namespace=" + ns, + "-bootstrap-token-file", tokenFile, + "-enable-partitions", + "-allow-dns", + "-partition=test", + "-enable-namespaces", + } + responseCode := cmd.Run(args) + require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) + + consul, err := api.NewClient(&api.Config{ + Address: server.HTTPAddr, + Token: bootToken, + }) + require.NoError(t, err) + + anonPolicyName := "anonymous-token-policy" + // Check that the anonymous token policy was created. + policy := policyExists(t, anonPolicyName, consul) + // Should be a global policy. + require.Len(t, policy.Datacenters, 0) + + // Check that the anonymous token has the policy. + tokenData, _, err := consul.ACL().TokenReadSelf(&api.QueryOptions{Token: "anonymous"}) + require.NoError(t, err) + require.Equal(t, anonPolicyName, tokenData.Policies[0].Name) +} + // Test that ACL policies get updated if namespaces/partition config changes. func TestRun_ACLPolicyUpdates(t *testing.T) { t.Parallel() @@ -1037,3 +1087,40 @@ func completeEnterpriseSetup(t *testing.T) (*fake.Clientset, *testutil.TestServe return k8s, svr } + +// partitionedSetup is a helper function which creates a server and a consul agent that runs as +// a client in the provided partitionName. The bootToken is the token used as the bootstrap token +// for both the client and the server. The helper creates a server, then creates a partition with +// the provided partitionName and then creates a client in said partition. +func partitionedSetup(t *testing.T, bootToken string, partitionName string) (*testutil.TestServer, func()) { + server, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { + c.ACL.Enabled = true + c.ACL.Tokens.InitialManagement = bootToken + }) + require.NoError(t, err) + server.WaitForLeader(t) + + serverAPIClient, err := consul.NewClient(&api.Config{ + Address: server.HTTPAddr, + Token: bootToken, + }) + require.NoError(t, err) + + _, _, err = serverAPIClient.Partitions().Create(context.Background(), &api.Partition{Name: partitionName}, &api.WriteOptions{}) + require.NoError(t, err) + + partitionedClient, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { + c.Server = false + c.Bootstrap = false + c.Partition = partitionName + c.RetryJoin = []string{server.LANAddr} + c.ACL.Enabled = true + c.ACL.Tokens.Agent = bootToken + }) + require.NoError(t, err) + + return server, func() { + server.Stop() + partitionedClient.Stop() + } +} diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index efcfaacac0..8ca8974182 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -2108,7 +2108,7 @@ func completeBootstrappedSetup(t *testing.T, masterToken string) (*fake.Clientse svr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true - c.ACL.Tokens.Master = masterToken + c.ACL.Tokens.InitialManagement = masterToken }) require.NoError(t, err) svr.WaitForActiveCARoot(t) @@ -2153,7 +2153,7 @@ func replicatedSetup(t *testing.T, bootToken string) (*fake.Clientset, *api.Clie primarySvr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true if bootToken != "" { - c.ACL.Tokens.Master = bootToken + c.ACL.Tokens.InitialManagement = bootToken } }) require.NoError(t, err) diff --git a/control-plane/subcommand/server-acl-init/create_or_update_test.go b/control-plane/subcommand/server-acl-init/create_or_update_test.go index 62775e786c..57cdffa2a1 100644 --- a/control-plane/subcommand/server-acl-init/create_or_update_test.go +++ b/control-plane/subcommand/server-acl-init/create_or_update_test.go @@ -30,7 +30,7 @@ func TestCreateOrUpdateACLPolicy_ErrorsIfDescriptionDoesNotMatch(t *testing.T) { bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" svr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true - c.ACL.Tokens.Master = bootToken + c.ACL.Tokens.InitialManagement = bootToken }) require.NoError(err) svr.WaitForLeader(t) From be23d956fc67caa9003379fe09529152321a3e0f Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 20 Jan 2022 19:27:23 -0500 Subject: [PATCH 3/6] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5186dcf40c..4a725a9667 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ IMPROVEMENTS: BUG FIXES: * Helm * Add `PodDisruptionBudget` Kind when checking for existing versions so that `helm template` can generate the right version. [[GH-923](https://github.com/hashicorp/consul-k8s/pull/923)] +* Control Plane + * Admin Partitions **(Consul Enterprise only)**: Create anonymous-policy and anonymous-token from non-default partitions to support DNS queries when the default partition is on a VM. [[GH-966](https://github.com/hashicorp/consul-k8s/pull/966)] ## 0.39.0 (December 15, 2021) From 804c7bc824a70e3f0623c925342d4ad6aded2e60 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 24 Jan 2022 13:11:39 -0500 Subject: [PATCH 4/6] Update CHANGELOG.md Co-authored-by: Iryna Shustava --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a725a9667..d080f46571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ BUG FIXES: * Helm * Add `PodDisruptionBudget` Kind when checking for existing versions so that `helm template` can generate the right version. [[GH-923](https://github.com/hashicorp/consul-k8s/pull/923)] * Control Plane - * Admin Partitions **(Consul Enterprise only)**: Create anonymous-policy and anonymous-token from non-default partitions to support DNS queries when the default partition is on a VM. [[GH-966](https://github.com/hashicorp/consul-k8s/pull/966)] + * Admin Partitions **(Consul Enterprise only)**: Attach anonymous-policy to the anonymous token from non-default partitions to support DNS queries when the default partition is on a VM. [[GH-966](https://github.com/hashicorp/consul-k8s/pull/966)] ## 0.39.0 (December 15, 2021) From e6793227ca071d0457bed7a5d932db17fc84c004 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 24 Jan 2022 13:11:46 -0500 Subject: [PATCH 5/6] Update control-plane/subcommand/server-acl-init/command_ent_test.go Co-authored-by: Iryna Shustava --- control-plane/subcommand/server-acl-init/command_ent_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control-plane/subcommand/server-acl-init/command_ent_test.go b/control-plane/subcommand/server-acl-init/command_ent_test.go index 2ad763d62b..5824d4af9b 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -208,7 +208,7 @@ func TestRun_ConnectInject_NamespaceMirroring(t *testing.T) { } } -// Test that the anonymous token is created in the default partition from +// Test that the anonymous token policy is created in the default partition from // a non-default partition. func TestRun_AnonymousToken_CreatedFromNonDefaultPartition(t *testing.T) { bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" From 03f2f17af95f74bf8c3b740af89d17809440d1f4 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 24 Jan 2022 13:12:43 -0500 Subject: [PATCH 6/6] revert consul-k8s image --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 08e847549e..48f27ca0cb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,7 @@ commands: type: string consul-k8s-image: type: string - default: "ashwinvenkatesh/consul-k8s@sha256:9b46fae446fcf99c715d9063231857eef5525830f2cd3cdcb46266c84db11deb" + default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" go-path: type: string default: "/home/circleci/.go_workspace"