diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go index 0e571b3763..9b10f59338 100644 --- a/acceptance/tests/vault/vault_wan_fed_test.go +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -200,12 +200,26 @@ func TestVault_WANFederationViaGateways(t *testing.T) { primaryConsulCluster := consul.NewHelmCluster(t, primaryConsulHelmValues, primaryCtx, cfg, consulReleaseName) primaryConsulCluster.Create(t) + var k8sAuthMethodHost string + // When running on kind, the kube API address in kubeconfig will have a localhost address + // which will not work from inside the container. That's why we need to use the endpoints address instead + // which will point the node IP. + if cfg.UseKind { + // The Kubernetes AuthMethod host is read from the endpoints for the Kubernetes service. + kubernetesEndpoint, err := secondaryCtx.KubernetesClient(t).CoreV1().Endpoints("default").Get(context.Background(), "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + } else { + k8sAuthMethodHost = k8s.KubernetesAPIServerHostFromOptions(t, secondaryCtx.KubectlOptions(t)) + } + // Get the address of the mesh gateway. primaryMeshGWAddress := meshGatewayAddress(t, cfg, primaryCtx, consulReleaseName) secondaryConsulHelmValues := map[string]string{ "global.datacenter": "dc2", "global.federation.enabled": "true", + "global.federation.k8sAuthMethodHost": k8sAuthMethodHost, "global.federation.primaryDatacenter": "dc1", "global.federation.primaryGateways[0]": primaryMeshGWAddress, diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index 9766793e37..eb64c9b58c 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -205,7 +205,7 @@ spec: {{- if .Values.global.adminPartitions.enabled }} -partition={{ .Values.global.adminPartitions.name }} \ {{- end }} - -log-level={{ default .Values.global.logLevel .Values.controller.logLevel }} \ + -log-level={{ default .Values.global.logLevel .Values.apiGateway.logLevel }} \ -log-json={{ .Values.global.logJSON }} resources: requests: diff --git a/charts/consul/templates/client-snapshot-agent-deployment.yaml b/charts/consul/templates/client-snapshot-agent-deployment.yaml index e5202644cd..48581e29da 100644 --- a/charts/consul/templates/client-snapshot-agent-deployment.yaml +++ b/charts/consul/templates/client-snapshot-agent-deployment.yaml @@ -229,7 +229,7 @@ spec: {{- if .Values.global.adminPartitions.enabled }} -partition={{ .Values.global.adminPartitions.name }} \ {{- end }} - -log-level={{ default .Values.global.logLevel .Values.controller.logLevel }} \ + -log-level={{ default .Values.global.logLevel }} \ -log-json={{ .Values.global.logJSON }} resources: requests: diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 9c79db4235..5804cc988b 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -348,7 +348,7 @@ spec: {{- if .Values.global.adminPartitions.enabled }} -partition={{ .Values.global.adminPartitions.name }} \ {{- end }} - -log-level={{ default .Values.global.logLevel .Values.controller.logLevel }} \ + -log-level={{ default .Values.global.logLevel .Values.connectInject.logLevel }} \ -log-json={{ .Values.global.logJSON }} resources: requests: diff --git a/charts/consul/templates/mesh-gateway-clusterrole.yaml b/charts/consul/templates/mesh-gateway-clusterrole.yaml index 2df2ba5343..b951418b26 100644 --- a/charts/consul/templates/mesh-gateway-clusterrole.yaml +++ b/charts/consul/templates/mesh-gateway-clusterrole.yaml @@ -19,15 +19,6 @@ rules: verbs: - use {{- end }} -{{- if .Values.global.acls.manageSystemACLs }} - - apiGroups: [""] - resources: - - secrets - resourceNames: - - {{ template "consul.fullname" . }}-mesh-gateway-acl-token - verbs: - - get -{{- end }} {{- if eq .Values.meshGateway.wanAddress.source "Service" }} - apiGroups: [""] resources: diff --git a/charts/consul/templates/mesh-gateway-deployment.yaml b/charts/consul/templates/mesh-gateway-deployment.yaml index 8a0a05caba..8b09c22fbc 100644 --- a/charts/consul/templates/mesh-gateway-deployment.yaml +++ b/charts/consul/templates/mesh-gateway-deployment.yaml @@ -121,26 +121,26 @@ spec: {{- if (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} {{- include "consul.getAutoEncryptClientCA" . | nindent 8 }} {{- end }} - # service-init registers the mesh gateway service. - - name: service-init + - name: mesh-gateway-init image: {{ .Values.global.imageK8S }} env: - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + {{- if .Values.global.tls.enabled }} + - name: CONSUL_CACERT + value: /consul/tls/ca/tls.crt + {{- end }} + - name: CONSUL_HTTP_ADDR {{- if .Values.global.tls.enabled }} - - name: CONSUL_HTTP_ADDR - value: https://$(HOST_IP):8501 - - name: CONSUL_CACERT - value: /consul/tls/ca/tls.crt + value: https://$(HOST_IP):8501 {{- else }} - - name: CONSUL_HTTP_ADDR - value: http://$(HOST_IP):8500 + value: http://$(HOST_IP):8500 {{- end }} command: - "/bin/sh" @@ -148,9 +148,19 @@ spec: - | {{- if .Values.global.acls.manageSystemACLs }} consul-k8s-control-plane acl-init \ - -secret-name="{{ template "consul.fullname" . }}-mesh-gateway-acl-token" \ - -k8s-namespace={{ .Release.Namespace }} \ - -token-sink-file=/consul/service/acl-token + -component-name=mesh-gateway \ + -token-sink-file=/consul/service/acl-token \ + {{- if and .Values.global.federation.enabled .Values.global.federation.primaryDatacenter }} + -acl-auth-method={{ template "consul.fullname" . }}-k8s-component-auth-method-{{ .Values.global.datacenter }} \ + -primary-datacenter={{ .Values.global.federation.primaryDatacenter }} \ + {{- else }} + -acl-auth-method={{ template "consul.fullname" . }}-k8s-component-auth-method \ + {{- end }} + {{- if .Values.global.adminPartitions.enabled }} + -partition={{ .Values.global.adminPartitions.name }} \ + {{- end }} + -log-level={{ default .Values.global.logLevel }} \ + -log-json={{ .Values.global.logJSON }} {{ end }} {{- $source := .Values.meshGateway.wanAddress.source }} @@ -258,6 +268,9 @@ spec: {{- end }} {{- end }} volumeMounts: + - mountPath: /consul/service + name: consul-service + readOnly: true - name: consul-bin mountPath: /consul-bin {{- if .Values.global.tls.enabled }} @@ -285,12 +298,9 @@ spec: fieldPath: spec.nodeName {{- end }} {{- if .Values.global.acls.manageSystemACLs }} - - name: CONSUL_HTTP_TOKEN - valueFrom: - secretKeyRef: - name: "{{ template "consul.fullname" . }}-mesh-gateway-acl-token" - key: "token" - {{- end}} + - name: CONSUL_HTTP_TOKEN_FILE + value: /consul/service/acl-token + {{- end }} {{- if .Values.global.tls.enabled }} - name: CONSUL_HTTP_ADDR value: https://$(HOST_IP):8501 @@ -337,7 +347,7 @@ spec: lifecycle: preStop: exec: - command: ["/bin/sh", "-ec", "/consul-bin/consul services deregister -id=\"{{ .Values.meshGateway.consulServiceName }}\""] + command: ["/bin/sh", "-ec", "/consul-bin/consul services deregister -id=\"{{ .Values.meshGateway.consulServiceName }}\"", "&&", "/bin/sh", "-ec", "/consul-bin/consul logout"] # consul-sidecar ensures the mesh gateway is always registered with # the local Consul agent, even if it loses the initial registration. diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index f78f2bc632..fd221cf91f 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -194,7 +194,7 @@ spec: {{- end }} {{- if .Values.meshGateway.enabled }} - -create-mesh-gateway-token=true \ + -mesh-gateway=true \ {{- end }} {{- if .Values.ingressGateways.enabled }} diff --git a/charts/consul/templates/sync-catalog-deployment.yaml b/charts/consul/templates/sync-catalog-deployment.yaml index a344ad6f90..ba6c347b94 100644 --- a/charts/consul/templates/sync-catalog-deployment.yaml +++ b/charts/consul/templates/sync-catalog-deployment.yaml @@ -276,7 +276,7 @@ spec: {{- if .Values.global.adminPartitions.enabled }} -partition={{ .Values.global.adminPartitions.name }} \ {{- end }} - -log-level={{ default .Values.global.logLevel .Values.controller.logLevel }} \ + -log-level={{ default .Values.global.logLevel .Values.syncCatalog.logLevel }} \ -log-json={{ .Values.global.logJSON }} resources: requests: diff --git a/charts/consul/test/unit/mesh-gateway-clusterrole.bats b/charts/consul/test/unit/mesh-gateway-clusterrole.bats index fa9c39b923..da4d0bdb2c 100644 --- a/charts/consul/test/unit/mesh-gateway-clusterrole.bats +++ b/charts/consul/test/unit/mesh-gateway-clusterrole.bats @@ -32,18 +32,6 @@ load _helpers [ "${actual}" = "podsecuritypolicies" ] } -@test "meshGateway/ClusterRole: rules for global.acls.manageSystemACLs=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/mesh-gateway-clusterrole.yaml \ - --set 'meshGateway.enabled=true' \ - --set 'connectInject.enabled=true' \ - --set 'global.acls.manageSystemACLs=true' \ - . | tee /dev/stderr | - yq -r '.rules[0].resources[0]' | tee /dev/stderr) - [ "${actual}" = "secrets" ] -} - @test "meshGateway/ClusterRole: rules for meshGateway.wanAddress.source=Service" { cd `chart_dir` local actual=$(helm template \ @@ -83,5 +71,5 @@ load _helpers --set 'meshGateway.wanAddress.source=Service' \ . | tee /dev/stderr | yq -r '.rules | length' | tee /dev/stderr) - [ "${actual}" = "3" ] + [ "${actual}" = "2" ] } diff --git a/charts/consul/test/unit/mesh-gateway-deployment.bats b/charts/consul/test/unit/mesh-gateway-deployment.bats index e8a2b1eeec..4115c20384 100755 --- a/charts/consul/test/unit/mesh-gateway-deployment.bats +++ b/charts/consul/test/unit/mesh-gateway-deployment.bats @@ -438,9 +438,9 @@ key2: value2' \ } #-------------------------------------------------------------------- -# service-init container resources +# mesh-gateway-init container resources -@test "meshGateway/Deployment: init service-init container has default resources" { +@test "meshGateway/Deployment: init mesh-gateway-init container has default resources" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -455,7 +455,7 @@ key2: value2' \ [ $(echo "${actual}" | yq -r '.limits.cpu') = "50m" ] } -@test "meshGateway/Deployment: init service-init container resources can be set" { +@test "meshGateway/Deployment: init mesh-gateway-init container resources can be set" { cd `chart_dir` local object=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -584,31 +584,228 @@ key2: value2' \ [[ "$output" =~ "if global.acls.manageSystemACLs is true, meshGateway.consulServiceName cannot be set" ]] } -@test "meshGateway/Deployment: does not fail if consulServiceName is set to mesh-gateway and acls.manageSystemACLs is true" { +#-------------------------------------------------------------------- +# manageSystemACLs + +@test "meshGateway/Deployment: consul logout preStop hook is added when ACLs are enabled" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ --set 'meshGateway.enabled=true' \ --set 'connectInject.enabled=true' \ - --set 'meshGateway.consulServiceName=mesh-gateway' \ --set 'global.acls.manageSystemACLs=true' \ - . | tee /dev/stderr \ - | yq '.spec.template.spec.containers[0]' | tee /dev/stderr ) + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].lifecycle.preStop.exec.command[6]] | any(contains("logout"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} - [[ $(echo "${actual}" | yq -r '.lifecycle.preStop.exec.command' ) =~ '-id=\"mesh-gateway\"' ]] +@test "meshGateway/Deployment: CONSUL_HTTP_TOKEN_FILE is not set when acls are disabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[0].name] | any(contains("CONSUL_HTTP_TOKEN_FILE"))' | tee /dev/stderr) + [ "${actual}" = "false" ] } -@test "meshGateway/Deployment: consulServiceName can be set" { +@test "meshGateway/Deployment: CONSUL_HTTP_TOKEN_FILE is set when acls are enabled" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ --set 'meshGateway.enabled=true' \ --set 'connectInject.enabled=true' \ - --set 'meshGateway.consulServiceName=overridden' \ - . | tee /dev/stderr \ - | yq '.spec.template.spec.containers[0]' | tee /dev/stderr ) + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[2].name] | any(contains("CONSUL_HTTP_TOKEN_FILE"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "meshGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command and environment with tls disabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1]' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.name' | tee /dev/stderr) + [ "${actual}" = "mesh-gateway-init" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[2].name] | any(contains("CONSUL_HTTP_ADDR"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[2].value] | any(contains("http://$(HOST_IP):8500"))' | tee /dev/stderr) + echo $actual + [ "${actual}" = "true" ] +} + +@test "meshGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command and environment with tls enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "mesh-gateway-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[2].name] | any(contains("CONSUL_CACERT"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].name] | any(contains("CONSUL_HTTP_ADDR"))' | tee /dev/stderr) + [ "${actual}" = "true" ] - [[ $(echo "${actual}" | yq -r '.lifecycle.preStop.exec.command' ) =~ '-id=\"overridden\"' ]] + local actual=$(echo $object | + yq '[.env[3].value] | any(contains("https://$(HOST_IP):8501"))' | tee /dev/stderr) + echo $actual + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[2] | any(contains("consul-ca-cert"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "meshGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command with Partitions enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=default' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "mesh-gateway-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("-acl-auth-method=RELEASE-NAME-consul-k8s-component-auth-method"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("-partition=default"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[2].name] | any(contains("CONSUL_CACERT"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].name] | any(contains("CONSUL_HTTP_ADDR"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].value] | any(contains("https://$(HOST_IP):8501"))' | tee /dev/stderr) + echo $actual + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[2] | any(contains("consul-ca-cert"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "meshGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command and environment with tls enabled and autoencrypt enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "mesh-gateway-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[2].name] | any(contains("CONSUL_CACERT"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].name] | any(contains("CONSUL_HTTP_ADDR"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '[.env[3].value] | any(contains("https://$(HOST_IP):8501"))' | tee /dev/stderr) + echo $actual + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq '.volumeMounts[2] | any(contains("consul-auto-encrypt-ca-cert"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "meshGateway/Deployment: auto-encrypt init container is created and is the first init-container when global.acls.manageSystemACLs=true and has correct command and environment with tls enabled and autoencrypt enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1]' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.name' | tee /dev/stderr) + [ "${actual}" = "get-auto-encrypt-client-ca" ] +} + +@test "meshGateway/Deployment: init container is created when global.acls.manageSystemACLs=true and has correct command when federation enabled in non-primary datacenter" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.datacenter=dc2' \ + --set 'global.federation.enabled=true' \ + --set 'global.federation.primaryDatacenter=dc1' \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "mesh-gateway-init")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("-acl-auth-method=RELEASE-NAME-consul-k8s-component-auth-method-dc2"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("-primary-datacenter=dc1"))' | tee /dev/stderr) + [ "${actual}" = "true" ] } #-------------------------------------------------------------------- @@ -848,16 +1045,16 @@ key2: value2' \ } ##-------------------------------------------------------------------- -## service-init init container +## mesh-gateway-init init container -@test "meshGateway/Deployment: service-init init container" { +@test "meshGateway/Deployment: mesh-gateway-init init container" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ --set 'meshGateway.enabled=true' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='consul-k8s-control-plane service-address \ -log-level=info \ @@ -901,7 +1098,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container with acls.manageSystemACLs=true" { +@test "meshGateway/Deployment: mesh-gateway-init init container with acls.manageSystemACLs=true" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -909,12 +1106,14 @@ EOF --set 'connectInject.enabled=true' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='consul-k8s-control-plane acl-init \ - -secret-name="RELEASE-NAME-consul-mesh-gateway-acl-token" \ - -k8s-namespace=default \ - -token-sink-file=/consul/service/acl-token + -component-name=mesh-gateway \ + -token-sink-file=/consul/service/acl-token \ + -acl-auth-method=RELEASE-NAME-consul-k8s-component-auth-method \ + -log-level=info \ + -log-json=false consul-k8s-control-plane service-address \ -log-level=info \ @@ -959,7 +1158,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container with global.federation.enabled=true" { +@test "meshGateway/Deployment: mesh-gateway-init init container with global.federation.enabled=true" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -968,7 +1167,7 @@ EOF --set 'global.federation.enabled=true' \ --set 'global.tls.enabled=true' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='consul-k8s-control-plane service-address \ -log-level=info \ @@ -1015,7 +1214,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container containerPort and wanAddress.port can be changed" { +@test "meshGateway/Deployment: mesh-gateway-init init container containerPort and wanAddress.port can be changed" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1025,7 +1224,7 @@ EOF --set 'meshGateway.wanAddress.source=NodeIP' \ --set 'meshGateway.wanAddress.port=9999' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='WAN_ADDR="${HOST_IP}" WAN_PORT="9999" @@ -1063,7 +1262,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=NodeIP" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=NodeIP" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1071,7 +1270,7 @@ EOF --set 'connectInject.enabled=true' \ --set 'meshGateway.wanAddress.source=NodeIP' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='WAN_ADDR="${HOST_IP}" WAN_PORT="443" @@ -1109,7 +1308,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=NodeName" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=NodeName" { cd `chart_dir` local obj=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1123,7 +1322,7 @@ EOF [ "${actual}" = "true" ] local actual=$(echo "$obj" | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='WAN_ADDR="${NODE_NAME}" WAN_PORT="443" @@ -1161,7 +1360,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=Static fails if wanAddress.static is empty" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=Static fails if wanAddress.static is empty" { cd `chart_dir` run helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1175,7 +1374,7 @@ EOF [[ "$output" =~ "if meshGateway.wanAddress.source=Static then meshGateway.wanAddress.static cannot be empty" ]] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=Static" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=Static" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1184,7 +1383,7 @@ EOF --set 'meshGateway.wanAddress.source=Static' \ --set 'meshGateway.wanAddress.static=example.com' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='WAN_ADDR="example.com" WAN_PORT="443" @@ -1222,7 +1421,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=Service fails if service.enable is false" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=Service fails if service.enable is false" { cd `chart_dir` run helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1236,7 +1435,7 @@ EOF [[ "$output" =~ "if meshGateway.wanAddress.source=Service then meshGateway.service.enabled must be set to true" ]] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=Service, type=LoadBalancer" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=Service, type=LoadBalancer" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1247,7 +1446,7 @@ EOF --set 'meshGateway.service.enabled=true' \ --set 'meshGateway.service.type=LoadBalancer' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='consul-k8s-control-plane service-address \ -log-level=info \ @@ -1291,7 +1490,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=Service, type=NodePort" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=Service, type=NodePort" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1302,7 +1501,7 @@ EOF --set 'meshGateway.service.nodePort=9999' \ --set 'meshGateway.service.type=NodePort' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='WAN_ADDR="${HOST_IP}" WAN_PORT="9999" @@ -1340,7 +1539,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=Service, type=NodePort fails if service.nodePort is null" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=Service, type=NodePort fails if service.nodePort is null" { cd `chart_dir` run helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1355,7 +1554,7 @@ EOF [[ "$output" =~ "if meshGateway.wanAddress.source=Service and meshGateway.service.type=NodePort, meshGateway.service.nodePort must be set" ]] } -@test "meshGateway/Deployment: service-init init container wanAddress.source=Service, type=ClusterIP" { +@test "meshGateway/Deployment: mesh-gateway-init init container wanAddress.source=Service, type=ClusterIP" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1366,7 +1565,7 @@ EOF --set 'meshGateway.service.enabled=true' \ --set 'meshGateway.service.type=ClusterIP' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='consul-k8s-control-plane service-address \ -log-level=info \ @@ -1410,7 +1609,7 @@ EOF [ "${actual}" = "${exp}" ] } -@test "meshGateway/Deployment: service-init init container consulServiceName can be changed" { +@test "meshGateway/Deployment: mesh-gateway-init init container consulServiceName can be changed" { cd `chart_dir` local actual=$(helm template \ -s templates/mesh-gateway-deployment.yaml \ @@ -1418,7 +1617,7 @@ EOF --set 'connectInject.enabled=true' \ --set 'meshGateway.consulServiceName=new-name' \ . | tee /dev/stderr | - yq -r '.spec.template.spec.initContainers | map(select(.name == "service-init"))[0] | .command[2]' | tee /dev/stderr) + yq -r '.spec.template.spec.initContainers | map(select(.name == "mesh-gateway-init"))[0] | .command[2]' | tee /dev/stderr) exp='consul-k8s-control-plane service-address \ -log-level=info \ diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index 1582510948..66300c3e15 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -297,7 +297,7 @@ load _helpers --set 'global.acls.manageSystemACLs=true' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | any(contains("-create-mesh-gateway-token"))' | tee /dev/stderr) + yq '.spec.template.spec.containers[0].command | any(contains("-mesh-gateway"))' | tee /dev/stderr) [ "${actual}" = "false" ] } @@ -309,7 +309,7 @@ load _helpers --set 'meshGateway.enabled=true' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | any(contains("-create-mesh-gateway-token"))' | tee /dev/stderr) + yq '.spec.template.spec.containers[0].command | any(contains("-mesh-gateway"))' | tee /dev/stderr) [ "${actual}" = "true" ] } diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index 6f19d45905..400b69a9b8 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -54,7 +54,7 @@ type Command struct { flagSnapshotAgent bool - flagCreateMeshGatewayToken bool + flagMeshGateway bool flagIngressGatewayNames []string flagTerminatingGatewayNames []string @@ -126,13 +126,13 @@ func (c *Command) init() { "Toggle for creating a client agent token. Default is true.") c.flags.BoolVar(&c.flagSyncCatalog, "sync-catalog", false, - "Toggle for creating a catalog sync policy.") + "Toggle for configuring ACL login for sync catalog.") c.flags.StringVar(&c.flagSyncConsulNodeName, "sync-consul-node-name", "k8s-sync", "The Consul node name to register for catalog sync. Defaults to k8s-sync. To be discoverable "+ "via DNS, the name should only contain alpha-numerics and dashes.") c.flags.BoolVar(&c.flagConnectInject, "connect-inject", false, - "Toggle for creating a connect inject auth method and policy.") + "Toggle for configuring ACL login for Connect inject.") c.flags.StringVar(&c.flagAuthMethodHost, "auth-method-host", "", "Kubernetes Host config parameter for the auth method."+ "If not provided, the default cluster Kubernetes service will be used.") @@ -140,14 +140,14 @@ func (c *Command) init() { "Selector string for connectInject ACL Binding Rule.") c.flags.BoolVar(&c.flagController, "controller", false, - "Toggle for configuring ACLs for the controller.") + "Toggle for configuring ACL login for the controller.") c.flags.BoolVar(&c.flagCreateEntLicenseToken, "create-enterprise-license-token", false, "Toggle for creating a token for the enterprise license job.") c.flags.BoolVar(&c.flagSnapshotAgent, "snapshot-agent", false, - "[Enterprise Only] Toggle for creating a token for the Consul snapshot agent deployment.") - c.flags.BoolVar(&c.flagCreateMeshGatewayToken, "create-mesh-gateway-token", false, - "Toggle for creating a token for a Connect mesh gateway.") + "[Enterprise Only] Toggle for configuring ACL login for the snapshot agent.") + c.flags.BoolVar(&c.flagMeshGateway, "mesh-gateway", false, + "Toggle for configuring ACL login for the mesh gateway.") c.flags.Var((*flags.AppendSliceValue)(&c.flagIngressGatewayNames), "ingress-gateway-name", "Name of an ingress gateway that needs an acl token. May be specified multiple times. "+ "[Enterprise Only] If using Consul namespaces and registering the gateway outside of the "+ @@ -157,7 +157,7 @@ func (c *Command) init() { "[Enterprise Only] If using Consul namespaces and registering the gateway outside of the "+ "default namespace, specify the value in the form ..") c.flags.BoolVar(&c.flagAPIGatewayController, "api-gateway-controller", false, - "Toggle for creating a token for the API Gateway controller integration.") + "Toggle for configuring ACL login for the API gateway controller.") c.flags.Var((*flags.AppendSliceValue)(&c.flagServerAddresses), "server-address", "The IP, DNS name or the cloud auto-join string of the Consul server(s). If providing IPs or DNS names, may be specified multiple times. "+ @@ -579,16 +579,21 @@ func (c *Command) Run(args []string) int { } } - if c.flagCreateMeshGatewayToken { - meshGatewayRules, err := c.meshGatewayRules() + if c.flagMeshGateway { + rules, err := c.meshGatewayRules() if err != nil { - c.log.Error("Error templating dns rules", "err", err) + c.log.Error("Error templating mesh gateway rules", "err", err) return 1 } + serviceAccountName := c.withPrefix("mesh-gateway") // Mesh gateways require a global policy/token because they must // discover services in other datacenters. - err = c.createGlobalACL("mesh-gateway", meshGatewayRules, consulDC, primary, consulClient) + authMethodName := localComponentAuthMethodName + if !primary { + authMethodName = globalComponentAuthMethodName + } + err = c.createACLPolicyRoleAndBindingRule("mesh-gateway", rules, consulDC, primaryDC, globalPolicy, primary, authMethodName, serviceAccountName, consulClient) if err != nil { c.log.Error(err.Error()) return 1 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 ee3b26ebe6..70a3145083 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -286,7 +286,7 @@ func TestRun_ACLPolicyUpdates(t *testing.T) { "-k8s-namespace", k8sNamespaceFlag, "-create-client-token", "-allow-dns", - "-create-mesh-gateway-token", + "-mesh-gateway", "-sync-catalog", "-connect-inject", "-snapshot-agent", @@ -326,7 +326,7 @@ func TestRun_ACLPolicyUpdates(t *testing.T) { "anonymous-token-policy", "client-token", "sync-catalog-policy", - "mesh-gateway-token", + "mesh-gateway-policy", "snapshot-agent-policy", "enterprise-license-token", "gw-ingress-gateway-token", @@ -378,7 +378,7 @@ func TestRun_ACLPolicyUpdates(t *testing.T) { "client-token", "sync-catalog-policy", "connect-inject-policy", - "mesh-gateway-token", + "mesh-gateway-policy", "snapshot-agent-policy", "enterprise-license-token", "cross-namespace-policy", @@ -682,13 +682,6 @@ func TestRun_TokensWithNamespacesEnabled(t *testing.T) { SecretNames: []string{resourcePrefix + "-enterprise-license-acl-token"}, LocalToken: true, }, - "mesh-gateway token": { - TokenFlags: []string{"-create-mesh-gateway-token"}, - PolicyNames: []string{"mesh-gateway-token"}, - PolicyDCs: nil, - SecretNames: []string{resourcePrefix + "-mesh-gateway-acl-token"}, - LocalToken: false, - }, "ingress gateway tokens": { TokenFlags: []string{"-ingress-gateway-name=ingress", "-ingress-gateway-name=gateway", diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index a4df1b7d2d..e8d561da47 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -178,14 +178,6 @@ func TestRun_TokensPrimaryDC(t *testing.T) { SecretNames: []string{resourcePrefix + "-enterprise-license-acl-token"}, LocalToken: true, }, - { - TestName: "Mesh gateway token", - TokenFlags: []string{"-create-mesh-gateway-token"}, - PolicyNames: []string{"mesh-gateway-token"}, - PolicyDCs: nil, - SecretNames: []string{resourcePrefix + "-mesh-gateway-acl-token"}, - LocalToken: false, - }, { TestName: "Ingress gateway tokens", TokenFlags: []string{"-ingress-gateway-name=ingress", @@ -380,14 +372,6 @@ func TestRun_TokensReplicatedDC(t *testing.T) { SecretNames: []string{resourcePrefix + "-enterprise-license-acl-token"}, LocalToken: true, }, - { - TestName: "Mesh gateway token", - TokenFlags: []string{"-create-mesh-gateway-token"}, - PolicyNames: []string{"mesh-gateway-token-dc2"}, - PolicyDCs: nil, - SecretNames: []string{resourcePrefix + "-mesh-gateway-acl-token"}, - LocalToken: false, - }, { TestName: "Ingress gateway tokens", TokenFlags: []string{"-ingress-gateway-name=ingress", @@ -492,12 +476,6 @@ func TestRun_TokensWithProvidedBootstrapToken(t *testing.T) { PolicyNames: []string{"enterprise-license-token"}, SecretNames: []string{resourcePrefix + "-enterprise-license-acl-token"}, }, - { - TestName: "Mesh gateway token", - TokenFlags: []string{"-create-mesh-gateway-token"}, - PolicyNames: []string{"mesh-gateway-token"}, - SecretNames: []string{resourcePrefix + "-mesh-gateway-acl-token"}, - }, { TestName: "Ingress gateway tokens", TokenFlags: []string{"-ingress-gateway-name=ingress", @@ -1906,8 +1884,9 @@ func TestRun_ACLReplicationTokenValid(t *testing.T) { "-server-port", strings.Split(secondaryAddr, ":")[1], "-resource-prefix=" + resourcePrefix, "-acl-replication-token-file", tokenFile, + "-auth-method-host=" + "https://my-kube.com", "-create-client-token", - "-create-mesh-gateway-token", + "-mesh-gateway", } responseCode := secondaryCmd.Run(secondaryCmdArgs) require.Equal(t, 0, responseCode, secondaryUI.ErrorWriter.String()) @@ -1929,8 +1908,8 @@ func TestRun_ACLReplicationTokenValid(t *testing.T) { // Test that the mesh-gateway policy was created. This is a global policy // so replication has to have worked for it to exist. retry.Run(t, func(r *retry.R) { - p := policyExists(r, "mesh-gateway-token-dc2", secondaryConsulClient) - require.Len(r, p.Datacenters, 0) + p := policyExists(r, "mesh-gateway-policy-dc2", secondaryConsulClient) + require.Len(r, p.Datacenters, 2) }) } @@ -2129,6 +2108,12 @@ func TestRun_PoliciesAndBindingRulesForACLLogin_PrimaryDatacenter(t *testing.T) PolicyNames: []string{"snapshot-agent-policy"}, Roles: []string{resourcePrefix + "-snapshot-agent-acl-role"}, }, + { + TestName: "Mesh Gateway", + TokenFlags: []string{"-mesh-gateway"}, + PolicyNames: []string{"mesh-gateway-policy"}, + Roles: []string{resourcePrefix + "-mesh-gateway-acl-role"}, + }, } for _, c := range cases { t.Run(c.TestName, func(t *testing.T) { @@ -2254,6 +2239,13 @@ func TestRun_PoliciesAndBindingRulesACLLogin_SecondaryDatacenter(t *testing.T) { Roles: []string{resourcePrefix + "-snapshot-agent-acl-role-" + secondaryDatacenter}, GlobalAuthMethod: false, }, + { + TestName: "Mesh Gateway", + TokenFlags: []string{"-mesh-gateway"}, + PolicyNames: []string{"mesh-gateway-policy-" + secondaryDatacenter}, + Roles: []string{resourcePrefix + "-mesh-gateway-acl-role-" + secondaryDatacenter}, + GlobalAuthMethod: true, + }, } for _, c := range cases { t.Run(c.TestName, func(t *testing.T) { @@ -2359,16 +2351,25 @@ func TestRun_ValidateLoginToken_PrimaryDatacenter(t *testing.T) { ComponentName: "sync-catalog", TokenFlags: []string{"-sync-catalog"}, Roles: []string{resourcePrefix + "-sync-catalog-acl-role"}, + GlobalToken: false, }, { ComponentName: "api-gateway-controller", TokenFlags: []string{"-api-gateway-controller"}, Roles: []string{resourcePrefix + "-api-gateway-controller-acl-role"}, + GlobalToken: false, }, { ComponentName: "snapshot-agent", TokenFlags: []string{"-snapshot-agent"}, Roles: []string{resourcePrefix + "-snapshot-agent-acl-role"}, + GlobalToken: false, + }, + { + ComponentName: "mesh-gateway", + TokenFlags: []string{"-mesh-gateway"}, + Roles: []string{resourcePrefix + "-mesh-gateway-acl-role"}, + GlobalToken: false, }, } for _, c := range cases { @@ -2463,18 +2464,28 @@ func TestRun_ValidateLoginToken_SecondaryDatacenter(t *testing.T) { TokenFlags: []string{"-sync-catalog"}, Roles: []string{resourcePrefix + "-sync-catalog-acl-role-dc2"}, GlobalAuthMethod: false, + GlobalToken: false, }, { ComponentName: "api-gateway-controller", TokenFlags: []string{"-api-gateway-controller"}, Roles: []string{resourcePrefix + "-api-gateway-controller-acl-role-dc2"}, GlobalAuthMethod: false, + GlobalToken: false, }, { ComponentName: "snapshot-agent", TokenFlags: []string{"-snapshot-agent"}, Roles: []string{resourcePrefix + "-snapshot-agent-acl-role-dc2"}, GlobalAuthMethod: false, + GlobalToken: false, + }, + { + ComponentName: "mesh-gateway", + TokenFlags: []string{"-mesh-gateway"}, + Roles: []string{resourcePrefix + "-mesh-gateway-acl-role-dc2"}, + GlobalAuthMethod: true, + GlobalToken: true, }, } for _, c := range cases {