Skip to content

Commit

Permalink
Add ACL support
Browse files Browse the repository at this point in the history
- Update server-acl-init job to create tokens that are partition aware
  when Admin Partitions are enabled.
- server-acl-init creates a partition-token that is used by
  partition-init and server-acl-init in non-default-partitions.
- Update partition-init to use provided partition-token when ACLs are
  enabled.
- Update license-policy to be acl:write when created in a partition.
  • Loading branch information
thisisnotashwin committed Oct 7, 2021
1 parent 18de67c commit 084fa55
Show file tree
Hide file tree
Showing 11 changed files with 1,044 additions and 489 deletions.
24 changes: 22 additions & 2 deletions charts/consul/templates/partition-init-job.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ spec:
spec:
restartPolicy: Never
serviceAccountName: {{ template "consul.fullname" . }}-partition-init
{{- if .Values.global.tls.enabled }}
{{- if (or .Values.global.tls.enabled (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }}
volumes:
{{- if .Values.global.tls.enabled }}
- name: consul-ca-cert
secret:
{{- if .Values.global.tls.caCert.secretName }}
Expand All @@ -41,6 +42,15 @@ spec:
- key: {{ default "tls.crt" .Values.global.tls.caCert.secretKey }}
path: tls.crt
{{- end }}
{{- if (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey) }}
- name: partition-token
secret:
secretName: {{ .Values.global.acls.bootstrapToken.secretName }}
items:
- key: {{ .Values.global.acls.bootstrapToken.secretKey }}
path: partition-token
{{- end }}
{{- end }}
containers:
- name: post-install-job
image: {{ .Values.global.imageK8S }}
Expand All @@ -49,11 +59,18 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- if .Values.global.tls.enabled }}
{{- if (or .Values.global.tls.enabled (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }}
volumeMounts:
{{- if .Values.global.tls.enabled }}
- name: consul-ca-cert
mountPath: /consul/tls/ca
readOnly: true
{{- end }}
{{- if (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey) }}
- name: partition-token
mountPath: /consul/acl/tokens
readOnly: true
{{- end }}
{{- end }}
command:
- "/bin/sh"
Expand Down Expand Up @@ -81,6 +98,9 @@ spec:
-consul-tls-server-name={{ .Values.externalServers.tlsServerName }} \
{{- end }}
{{- end }}
{{- if (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey) }}
-token-file=/consul/acl/tokens/partition-token \
{{- end }}
-partition-name={{ .Values.global.adminPartitions.name }}
resources:
requests:
Expand Down
5 changes: 4 additions & 1 deletion charts/consul/templates/server-acl-init-job.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ spec:
-sync-consul-node-name={{ .Values.syncCatalog.consulNodeName }} \
{{- end }}
{{- end }}
{{- if .Values.global.adminPartitions.enabled }}
-enable-partitions=true \
-partition={{ .Values.global.adminPartitions.name }} \
{{- end }}
{{- if (or (and (ne (.Values.dns.enabled | toString) "-") .Values.dns.enabled) (and (eq (.Values.dns.enabled | toString) "-") .Values.global.enabled)) }}
-allow-dns=true \
{{- end }}
Expand Down
4 changes: 2 additions & 2 deletions charts/consul/test/unit/client-daemonset.bats
Original file line number Diff line number Diff line change
Expand Up @@ -1407,7 +1407,7 @@ rollingUpdate:
#--------------------------------------------------------------------
# partitions

@test "client/DaemonSet: -partitions can be set by global.adminPartition.enabled" {
@test "client/DaemonSet: -partitions can be set by global.adminPartitions.enabled" {
cd `chart_dir`
local actual=$(helm template \
-s templates/client-daemonset.yaml \
Expand All @@ -1417,7 +1417,7 @@ rollingUpdate:
[ "${actual}" = "true" ]
}

@test "client/DaemonSet: -partitions can be overridden by global.adminPartition.name" {
@test "client/DaemonSet: -partitions can be overridden by global.adminPartitions.name" {
cd `chart_dir`
local actual=$(helm template \
-s templates/client-daemonset.yaml \
Expand Down
51 changes: 50 additions & 1 deletion charts/consul/test/unit/partition-init-job.bats
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,53 @@ load _helpers
# check that the volume uses the provided secret key
actual=$(echo $ca_cert_volume | jq -r '.secret.items[0].key' | tee /dev/stderr)
[ "${actual}" = "key" ]
}
}

#--------------------------------------------------------------------
# global.acls.bootstrapToken

@test "partitionInit/Job: partition-token volume is created when global.acls.bootstrapToken is provided" {
cd `chart_dir`
local actual=$(helm template \
-s templates/partition-init-job.yaml \
--set 'global.enabled=false' \
--set 'global.adminPartitions.enabled=true' \
--set 'global.acls.bootstrapToken.secretName=partition-token' \
--set 'global.acls.bootstrapToken.secretKey=token' \
. | tee /dev/stderr |
yq '.spec.template.spec.volumes[0].name == "partition-token"' | tee /dev/stderr)
[ "${actual}" = "true" ]
}

@test "partitionInit/Job: partition-token volumeMount is created when global.acls.bootstrapToken is provided" {
cd `chart_dir`
local object=$(helm template \
-s templates/partition-init-job.yaml \
--set 'global.enabled=false' \
--set 'global.adminPartitions.enabled=true' \
--set 'global.acls.bootstrapToken.secretName=partition-token' \
--set 'global.acls.bootstrapToken.secretKey=token' \
. | tee /dev/stderr |
yq '.spec.template.spec.containers[0].volumeMounts[0]' | tee /dev/stderr)

local actual=$(echo $object |
yq -r '.name' | tee /dev/stderr)
[ "${actual}" = "partition-token" ]

local actual=$(echo $object |
yq -r '.mountPath' | tee /dev/stderr)
[ "${actual}" = "/consul/acl/tokens" ]
}

@test "partitionInit/Job: command includes partition-token dir when global.acls.bootstrapToken is provided" {
cd `chart_dir`
local actual=$(helm template \
-s templates/partition-init-job.yaml \
--set 'global.enabled=false' \
--set 'global.adminPartitions.enabled=true' \
--set 'global.acls.bootstrapToken.secretName=partition-token' \
--set 'global.acls.bootstrapToken.secretKey=token' \
. | tee /dev/stderr |
yq '.spec.template.spec.containers[0].command | any(contains("/consul/acl/tokens/partition-token"))' | tee /dev/stderr)
[ "${actual}" = "true" ]
}
39 changes: 39 additions & 0 deletions charts/consul/test/unit/server-acl-init-job.bats
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,45 @@ load _helpers
[ "${actual}" = "true" ]
}

#--------------------------------------------------------------------
# admin partitions

@test "serverACLInit/Job: admin partitions disabled by default" {
cd `chart_dir`
local object=$(helm template \
-s templates/server-acl-init-job.yaml \
--set 'global.acls.manageSystemACLs=true' \
. | tee /dev/stderr |
yq '.spec.template.spec.containers[0].command' | tee /dev/stderr)

local actual=$(echo $object |
yq 'any(contains("enable-partitions"))' | tee /dev/stderr)
[ "${actual}" = "false" ]

local actual=$(echo $object |
yq 'any(contains("partition"))' | tee /dev/stderr)
[ "${actual}" = "false" ]
}

@test "serverACLInit/Job: admin partitions enabled when admin partitions are enabled" {
cd `chart_dir`
local object=$(helm template \
-s templates/server-acl-init-job.yaml \
--set 'global.acls.manageSystemACLs=true' \
--set 'global.adminPartitions.enabled=true' \
--set 'global.enableConsulNamespaces=true' \
. | tee /dev/stderr |
yq '.spec.template.spec.containers[0].command' | tee /dev/stderr)

local actual=$(echo $object |
yq 'any(contains("enable-partitions"))' | tee /dev/stderr)
[ "${actual}" = "true" ]

local actual=$(echo $object |
yq 'any(contains("partition"))' | tee /dev/stderr)
[ "${actual}" = "true" ]
}

#--------------------------------------------------------------------
# global.acls.createReplicationToken

Expand Down
29 changes: 26 additions & 3 deletions control-plane/subcommand/partition-init/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"errors"
"flag"
"fmt"
"io/ioutil"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -32,6 +34,7 @@ type Command struct {
flagConsulCACert string
flagConsulTLSServerName string
flagUseHTTPS bool
flagTokenFile string

flagLogLevel string
flagLogJSON bool
Expand Down Expand Up @@ -65,7 +68,8 @@ func (c *Command) init() {
"The server name to set as the SNI header when sending HTTPS requests to Consul.")
c.flags.BoolVar(&c.flagUseHTTPS, "use-https", false,
"Toggle for using HTTPS for all API calls to Consul.")

c.flags.StringVar(&c.flagTokenFile, "token-file", "",
"Path to file containing ACL token for creating partitions. This token must have 'acl:write' and 'operator:write' permissions.")
c.flags.DurationVar(&c.flagTimeout, "timeout", 10*time.Minute,
"How long we'll try to bootstrap Partitions for before timing out, e.g. 1ms, 2s, 3m")
c.flags.StringVar(&c.flagLogLevel, "log-level", "info",
Expand Down Expand Up @@ -120,6 +124,21 @@ func (c *Command) Run(args []string) int {
return 1
}

var providedToken string
if c.flagTokenFile != "" {
// Load the bootstrap token from file.
tokenBytes, err := ioutil.ReadFile(c.flagTokenFile)
if err != nil {
c.UI.Error(fmt.Sprintf("Unable to read bootstrap token from file %q: %s", c.flagTokenFile, err))
return 1
}
if len(tokenBytes) == 0 {
c.UI.Error(fmt.Sprintf("Bootstrap token file %q is empty", c.flagTokenFile))
return 1
}
providedToken = strings.TrimSpace(string(tokenBytes))
}

serverAddresses, err := common.GetResolvedServerAddresses(c.flagServerAddresses, c.providers, c.log)
if err != nil {
c.UI.Error(fmt.Sprintf("Unable to discover any Consul addresses from %q: %s", c.flagServerAddresses[0], err))
Expand All @@ -132,14 +151,18 @@ func (c *Command) Run(args []string) int {
}
// For all of the next operations we'll need a Consul client.
serverAddr := fmt.Sprintf("%s:%d", serverAddresses[0], c.flagServerPort)
consulClient, err := consul.NewClient(&api.Config{
config := &api.Config{
Address: serverAddr,
Scheme: scheme,
TLSConfig: api.TLSConfig{
Address: c.flagConsulTLSServerName,
CAFile: c.flagConsulCACert,
},
})
}
if providedToken != "" {
config.Token = providedToken
}
consulClient, err := consul.NewClient(config)
if err != nil {
c.UI.Error(fmt.Sprintf("Error creating Consul client for addr %q: %s", serverAddr, err))
return 1
Expand Down
Loading

0 comments on commit 084fa55

Please sign in to comment.