Skip to content

Commit

Permalink
Add -create-acl-replication-token flag
Browse files Browse the repository at this point in the history
The ACL replication token is used for ACL replication between Consul
datacenters.
  • Loading branch information
lkysow committed Mar 6, 2020
1 parent 2c3e680 commit 9f636b6
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 19 deletions.
54 changes: 35 additions & 19 deletions subcommand/server-acl-init/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,26 @@ import (
type Command struct {
UI cli.Ui

flags *flag.FlagSet
k8s *k8sflags.K8SFlags
flagReleaseName string
flagServerLabelSelector string
flagResourcePrefix string
flagReplicas int
flagK8sNamespace string
flagAllowDNS bool
flagCreateClientToken bool
flagCreateSyncToken bool
flagCreateInjectToken bool
flagCreateInjectAuthMethod bool
flagBindingRuleSelector string
flagCreateEntLicenseToken bool
flagCreateSnapshotAgentToken bool
flagCreateMeshGatewayToken bool
flagConsulCACert string
flagConsulTLSServerName string
flagUseHTTPS bool
flags *flag.FlagSet
k8s *k8sflags.K8SFlags
flagReleaseName string
flagServerLabelSelector string
flagResourcePrefix string
flagReplicas int
flagK8sNamespace string
flagAllowDNS bool
flagCreateClientToken bool
flagCreateSyncToken bool
flagCreateInjectToken bool
flagCreateInjectAuthMethod bool
flagBindingRuleSelector string
flagCreateEntLicenseToken bool
flagCreateSnapshotAgentToken bool
flagCreateMeshGatewayToken bool
flagCreateACLReplicationToken bool
flagConsulCACert string
flagConsulTLSServerName string
flagUseHTTPS bool

// Flags to support namespaces
flagEnableNamespaces bool // Use namespacing on all components
Expand Down Expand Up @@ -99,6 +100,8 @@ func (c *Command) init() {
"Toggle for creating a token for the Consul snapshot agent deployment (enterprise only)")
c.flags.BoolVar(&c.flagCreateMeshGatewayToken, "create-mesh-gateway-token", false,
"Toggle for creating a token for a Connect mesh gateway")
c.flags.BoolVar(&c.flagCreateACLReplicationToken, "create-acl-replication-token", false,
"Toggle for creating a token for ACL replication between datacenters")
c.flags.StringVar(&c.flagConsulCACert, "consul-ca-cert", "",
"Path to the PEM-encoded CA certificate of the Consul cluster.")
c.flags.StringVar(&c.flagConsulTLSServerName, "consul-tls-server-name", "",
Expand Down Expand Up @@ -416,6 +419,19 @@ func (c *Command) Run(args []string) int {
}
}

if c.flagCreateACLReplicationToken {
rules, err := c.aclReplicationRules()
if err != nil {
c.Log.Error("Error templating acl replication token rules", "err", err)
return 1
}
err = c.createACL("acl-replication", rules, consulClient)
if err != nil {
c.Log.Error(err.Error())
return 1
}
}

c.Log.Info("server-acl-init completed successfully")
return 0
}
Expand Down
14 changes: 14 additions & 0 deletions subcommand/server-acl-init/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,20 @@ func TestRun_Tokens(t *testing.T) {
TokenName: "mesh-gateway",
SecretName: "my-prefix-mesh-gateway-acl-token",
},
"acl-replication token -release-name": {
TokenFlag: "-create-acl-replication-token",
ResourcePrefixFlag: "",
ReleaseNameFlag: "release-name",
TokenName: "acl-replication",
SecretName: "release-name-consul-acl-replication-acl-token",
},
"acl-replication token -resource-prefix": {
TokenFlag: "-create-acl-replication-token",
ResourcePrefixFlag: "my-prefix",
ReleaseNameFlag: "release-name",
TokenName: "acl-replication",
SecretName: "my-prefix-acl-replication-acl-token",
},
}
for testName, c := range cases {
t.Run(testName, func(t *testing.T) {
Expand Down
26 changes: 26 additions & 0 deletions subcommand/server-acl-init/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,32 @@ operator = "write"
return c.renderRules(injectRulesTpl)
}

func (c *Command) aclReplicationRules() (string, error) {
// NOTE: The node_prefix rule is not required for ACL replication. It's
// added so that this token can be used as an ACL replication token *and*
// as an agent token. This allows us to only pass one token between
// datacenters during federation since in order to start ACL replication,
// we need a token with both replication and agent permissions.
aclReplicationRulesTpl := `
acl = "write"
operator = "write"
{{- if .EnableNamespaces }}
namespace_prefix "" {
{{- end }}
node_prefix "" {
policy = "write"
}
service_prefix "" {
policy = "read"
intentions = "read"
}
{{- if .EnableNamespaces }}
}
{{- end }}
`
return c.renderRules(aclReplicationRulesTpl)
}

func (c *Command) renderRules(tmpl string) (string, error) {
// Check that it's a valid template
compiled, err := template.New("root").Parse(strings.TrimSpace(tmpl))
Expand Down
49 changes: 49 additions & 0 deletions subcommand/server-acl-init/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,52 @@ operator = "write"`,
})
}
}

func TestReplicationTokenRules(t *testing.T) {
cases := []struct {
Name string
EnableNamespaces bool
Expected string
}{
{
"Namespaces are disabled",
false,
`acl = "write"
operator = "write"
node_prefix "" {
policy = "write"
}
service_prefix "" {
policy = "read"
intentions = "read"
}`,
},
{
"Namespaces are enabled",
true,
`acl = "write"
operator = "write"
namespace_prefix "" {
node_prefix "" {
policy = "write"
}
service_prefix "" {
policy = "read"
intentions = "read"
}
}`,
},
}

for _, tt := range cases {
t.Run(tt.Name, func(t *testing.T) {
require := require.New(t)
cmd := Command{
flagEnableNamespaces: tt.EnableNamespaces,
}
replicationTokenRules, err := cmd.aclReplicationRules()
require.NoError(err)
require.Equal(tt.Expected, replicationTokenRules)
})
}
}

0 comments on commit 9f636b6

Please sign in to comment.