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 8, 2021
1 parent 18de67c commit 12f194d
Show file tree
Hide file tree
Showing 10 changed files with 879 additions and 425 deletions.
13 changes: 10 additions & 3 deletions charts/consul/templates/partition-init-job.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,26 @@ spec:
path: tls.crt
{{- end }}
containers:
- name: post-install-job
- name: partition-create-job
image: {{ .Values.global.imageK8S }}
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- if .Values.global.tls.enabled }}
{{- if (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey) }}
- name: CONSUL_HTTP_TOKEN
valueFrom:
secretKeyRef:
name: {{ .Values.global.acls.bootstrapToken.secretName }}
key: {{ .Values.global.acls.bootstrapToken.secretKey }}
{{- end }}
{{- if .Values.global.tls.enabled }}
volumeMounts:
- name: consul-ca-cert
mountPath: /consul/tls/ca
readOnly: true
{{- end }}
{{- end }}
command:
- "/bin/sh"
- "-ec"
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
18 changes: 17 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,20 @@ 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: HTTP_TOKEN 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].env[].name] | any(contains("CONSUL_HTTP_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
4 changes: 3 additions & 1 deletion control-plane/subcommand/partition-init/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Command struct {

flags *flag.FlagSet
k8s *k8sflags.K8SFlags
http *flags.HTTPFlags

flagPartitionName string

Expand Down Expand Up @@ -65,7 +66,6 @@ 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.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 All @@ -75,7 +75,9 @@ func (c *Command) init() {
"Enable or disable JSON output format for logging.")

c.k8s = &k8sflags.K8SFlags{}
c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.k8s.Flags())
flags.Merge(c.flags, c.http.Flags())
c.help = flags.Usage(help, c.flags)

// Default retry to 1s. This is exposed for setting in tests.
Expand Down
49 changes: 44 additions & 5 deletions control-plane/subcommand/server-acl-init/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ type Command struct {
flagCreateACLReplicationToken bool
flagACLReplicationTokenFile string

// Flags to support partitions
flagEnablePartitions bool // true if Admin Partitions are enabled
flagPartitionName string // name of the Admin Partition

// Flags to support namespaces
flagEnableNamespaces bool // Use namespacing on all components
flagConsulSyncDestinationNamespace string // Consul namespace to register all catalog sync services into if not mirroring
Expand Down Expand Up @@ -169,6 +173,11 @@ func (c *Command) init() {
c.flags.BoolVar(&c.flagUseHTTPS, "use-https", false,
"Toggle for using HTTPS for all API calls to Consul.")

c.flags.BoolVar(&c.flagEnablePartitions, "enable-partitions", false,
"[Enterprise Only] Enables Admin Partitions [Enterprise only feature]")
c.flags.StringVar(&c.flagPartitionName, "partition", "",
"[Enterprise Only] Name of the Admin Partition")

c.flags.BoolVar(&c.flagEnableNamespaces, "enable-namespaces", false,
"[Enterprise Only] Enables namespaces, in either a single Consul namespace or mirrored [Enterprise only feature]")
c.flags.StringVar(&c.flagConsulSyncDestinationNamespace, "consul-sync-destination-namespace", consulDefaultNamespace,
Expand Down Expand Up @@ -349,15 +358,20 @@ 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{
clientConfig := &api.Config{
Address: serverAddr,
Scheme: scheme,
Token: bootstrapToken,
TLSConfig: api.TLSConfig{
Address: c.flagConsulTLSServerName,
CAFile: c.flagConsulCACert,
},
})
}
if c.flagEnablePartitions {
clientConfig.Partition = c.flagPartitionName
}

consulClient, err := consul.NewClient(clientConfig)
if err != nil {
c.log.Error(fmt.Sprintf("Error creating Consul client for addr %q: %s", serverAddr, err))
return 1
Expand All @@ -382,19 +396,33 @@ func (c *Command) Run(args []string) int {
}
}

if c.flagEnablePartitions && c.flagPartitionName == "default" && isPrimary {
// Partition token must be local because only the Primary datacenter can have Admin Partitions.
err := c.createLocalACL("partitions", partitionRules, consulDC, isPrimary, consulClient)
if err != nil {
c.log.Error(err.Error())
return 1
}
}

// If namespaces are enabled, to allow cross-Consul-namespace permissions
// for services from k8s, the Consul `default` namespace needs a policy
// allowing service discovery in all namespaces. Each namespace that is
// created by consul-k8s components (this bootstrapper, catalog sync or
// connect inject) needs to reference this policy on namespace creation
// to finish the cross namespace permission setup.
if c.flagEnableNamespaces {
crossNamespaceRule, err := c.crossNamespaceRule()
if err != nil {
c.log.Error("Error templating cross namespace rules", "err", err)
return 1
}
policyTmpl := api.ACLPolicy{
Name: "cross-namespace-policy",
Description: "Policy to allow permissions to cross Consul namespaces for k8s services",
Rules: crossNamespaceRules,
Rules: crossNamespaceRule,
}
err := c.untilSucceeds(fmt.Sprintf("creating %s policy", policyTmpl.Name),
err = c.untilSucceeds(fmt.Sprintf("creating %s policy", policyTmpl.Name),
func() error {
return c.createOrUpdateACLPolicy(policyTmpl, consulClient)
})
Expand Down Expand Up @@ -497,7 +525,12 @@ func (c *Command) Run(args []string) int {
}

if c.flagCreateEntLicenseToken {
err := c.createLocalACL("enterprise-license", entLicenseRules, consulDC, isPrimary, consulClient)
var err error
if c.flagEnablePartitions {
err = c.createLocalACL("enterprise-license", entPartitionLicenseRules, consulDC, isPrimary, consulClient)
} else {
err = c.createLocalACL("enterprise-license", entLicenseRules, consulDC, isPrimary, consulClient)
}
if err != nil {
c.log.Error(err.Error())
return 1
Expand Down Expand Up @@ -827,6 +860,12 @@ func (c *Command) validateFlags() error {
)
}

if c.flagEnablePartitions && c.flagPartitionName == "" {
return errors.New("-partition must be set if -enable-partitions is true")
}
if !c.flagEnablePartitions && c.flagPartitionName != "" {
return fmt.Errorf("-enable-partitions must be 'true' if setting -partition to %s", c.flagPartitionName)
}
return nil
}

Expand Down
Loading

0 comments on commit 12f194d

Please sign in to comment.