diff --git a/.changelog/2790.txt b/.changelog/2790.txt new file mode 100644 index 0000000000..c16b55f74d --- /dev/null +++ b/.changelog/2790.txt @@ -0,0 +1,3 @@ +```release-note:improvement +control-plane: prevent updation of anonymous-token-policy and anonymous-token if anonymous-token-policy is already attached to the anonymous-token +``` \ No newline at end of file diff --git a/control-plane/subcommand/server-acl-init/anonymous_token.go b/control-plane/subcommand/server-acl-init/anonymous_token.go index 3423ee78da..46d456471e 100644 --- a/control-plane/subcommand/server-acl-init/anonymous_token.go +++ b/control-plane/subcommand/server-acl-init/anonymous_token.go @@ -4,9 +4,24 @@ import ( "github.com/hashicorp/consul/api" ) +const ( + anonymousTokenPolicyName = "anonymous-token-policy" + anonymousTokenAccessorID = "00000000-0000-0000-0000-000000000002" +) + // configureAnonymousPolicy sets up policies and tokens so that Consul DNS and // cross-datacenter Consul connect calls will work. func (c *Command) configureAnonymousPolicy(consulClient *api.Client) error { + exists, err := checkIfAnonymousTokenPolicyExists(consulClient) + if err != nil { + c.log.Error("Error checking if anonymous token policy exists", "err", err) + return err + } + if exists { + c.log.Info("skipping creating anonymous token since it already exists") + return nil + } + anonRules, err := c.anonymousTokenRules() if err != nil { c.log.Error("Error templating anonymous token rules", "err", err) @@ -15,7 +30,7 @@ func (c *Command) configureAnonymousPolicy(consulClient *api.Client) error { // Create policy for the anonymous token anonPolicy := api.ACLPolicy{ - Name: "anonymous-token-policy", + Name: anonymousTokenPolicyName, Description: "Anonymous token Policy", Rules: anonRules, } @@ -30,7 +45,7 @@ func (c *Command) configureAnonymousPolicy(consulClient *api.Client) error { // Create token to get sent to TokenUpdate aToken := api.ACLToken{ - AccessorID: "00000000-0000-0000-0000-000000000002", + AccessorID: anonymousTokenAccessorID, Policies: []*api.ACLTokenPolicyLink{{Name: anonPolicy.Name}}, } @@ -41,3 +56,18 @@ func (c *Command) configureAnonymousPolicy(consulClient *api.Client) error { return err }) } + +func checkIfAnonymousTokenPolicyExists(consulClient *api.Client) (bool, error) { + token, _, err := consulClient.ACL().TokenRead(anonymousTokenAccessorID, nil) + if err != nil { + return false, err + } + + for _, policy := range token.Policies { + if policy.Name == anonymousTokenPolicyName { + return true, nil + } + } + + return false, nil +} diff --git a/control-plane/subcommand/server-acl-init/anonymous_token_test.go b/control-plane/subcommand/server-acl-init/anonymous_token_test.go new file mode 100644 index 0000000000..4a36c676e1 --- /dev/null +++ b/control-plane/subcommand/server-acl-init/anonymous_token_test.go @@ -0,0 +1,68 @@ +package serveraclinit + +import ( + "strings" + "testing" + + "github.com/hashicorp/consul/api" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" +) + +func Test_configureAnonymousPolicy(t *testing.T) { + + k8s, testClient := completeSetup(t) + consulHTTPAddr := testClient.TestServer.HTTPAddr + consulGRPCAddr := testClient.TestServer.GRPCAddr + + setUpK8sServiceAccount(t, k8s, ns) + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + clientset: k8s, + } + cmd.init() + flags := []string{"-connect-inject"} + cmdArgs := append([]string{ + "-timeout=1m", + "-resource-prefix=" + resourcePrefix, + "-k8s-namespace=" + ns, + "-auth-method-host=https://my-kube.com", + "-addresses", strings.Split(consulHTTPAddr, ":")[0], + "-http-port", strings.Split(consulHTTPAddr, ":")[1], + "-grpc-port", strings.Split(consulGRPCAddr, ":")[1], + }, flags...) + responseCode := cmd.Run(cmdArgs) + require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) + + bootToken := getBootToken(t, k8s, resourcePrefix, ns) + consul, err := api.NewClient(&api.Config{ + Address: consulHTTPAddr, + Token: bootToken, + }) + require.NoError(t, err) + + err = cmd.configureAnonymousPolicy(consul) + require.NoError(t, err) + + policy, _, err := consul.ACL().PolicyReadByName(anonymousTokenPolicyName, nil) + require.NoError(t, err) + + testPolicy := api.ACLPolicy{ + ID: policy.ID, + Name: anonymousTokenPolicyName, + Description: "Anonymous token Policy", + Rules: `acl = "read"`, + } + readOnlyPolicy, _, err := consul.ACL().PolicyUpdate(&testPolicy, &api.WriteOptions{}) + require.NoError(t, err) + + err = cmd.configureAnonymousPolicy(consul) + require.NoError(t, err) + + actualPolicy, _, err := consul.ACL().PolicyReadByName(anonymousTokenPolicyName, nil) + require.NoError(t, err) + + // assert policy is still same. + require.Equal(t, readOnlyPolicy, actualPolicy) +}