Terminating Gateways on Kubernetes
1.9.0+: This feature is available in Consul versions 1.9.0 and higher
This topic requires familiarity with Terminating Gateways.
Adding a terminating gateway is a multi-step process:
- Update the helm chart with terminating gateway config options
- Deploy the helm chart
- Access the Consul agent
- Register external services with Consul
Update the helm chart with terminating gateway config options
Minimum required Helm options:
global:
name: consul
connectInject:
enabled: true
controller:
enabled: true
terminatingGateways:
enabled: true
Deploying the helm chart
Ensure you have the latest consul-helm chart and install Consul via helm using the following guide while being sure to provide the yaml configuration as previously discussed.
Accessing the Consul agent
You can access the Consul server directly from your host via kubectl port-forward
. This is helpful for interacting with your Consul UI locally as well as to validate connectivity of the application.
$ kubectl port-forward consul-server-0 8500 &
If TLS is enabled use port 8501:
$ kubectl port-forward consul-server-0 8501 &
Be sure the latest consul binary is installed locally on your host. https://releases.hashicorp.com/consul/
$ export CONSUL_HTTP_ADDR=http://localhost:8500
If TLS is enabled set:
$ export CONSUL_HTTP_ADDR=https://localhost:8501
$ export CONSUL_HTTP_SSL_VERIFY=false
If ACLs are enabled also set:
$ export CONSUL_HTTP_TOKEN=$(kubectl get secret consul-bootstrap-acl-token -o jsonpath={.data.token} | base64 -D)
Register external services with Consul
Registering the external services with Consul is a multi-step process:
- Register external services with Consul
- Update the terminating gateway ACL token if ACLs are enabled
- Create a TerminatingGateway resource to configure the terminating gateway
- Create a ServiceIntentions resource to allow access from services in the mesh to external service
- Define upstream annotations for any services that need to talk to the external services
Register external services with Consul
Create a sample external service and register it with Consul.
{
"Node": "legacy_node",
"Address": "example.com",
"NodeMeta": {
"external-node": "true",
"external-probe": "true"
},
"Service": {
"ID": "example-https",
"Service": "example-https",
"Port": 443
}
}
Register the external service with Consul:
$ curl --request PUT --data @external.json -k $CONSUL_HTTP_ADDR/v1/catalog/register
true
If ACLs and TLS are enabled :
$ curl --request PUT --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" --data @external.json -k $CONSUL_HTTP_ADDR/v1/catalog/register
true
Update terminating gateway ACL token if ACLs are enabled
If ACLs are enabled, update the terminating gateway acl token to have service: write
permissions on all of the services being represented by the gateway:
- Create a new policy that includes these permissions
- Update the existing token to include the new policy
The CLI command should be run with the -merge-policies
, -merge-roles
and -merge-service-identities
so nothing is removed from the terminating gateway token
service "example-https" {
policy = "write"
}
$ consul acl policy create -name "example-https-write-policy" -rules @write-policy.hcl
ID: xxxxxxxxxxxxxxx
Name: example-https-write-policy
Description:
Datacenters:
Rules:
service "example-https" {
policy = "write"
}
Now fetch the id of the terminating gateway token
consul acl token list | grep -B 6 -- "- terminating-gateway-terminating-gateway-token" | grep AccessorID
AccessorID: <token id>
Update the terminating gateway acl token with the new policy
$ consul acl token update -id <token-id> -policy-name example-https-write-policy -merge-policies -merge-roles -merge-service-identities
AccessorID: <token id>
SecretID: <secret id>
Description: terminating-gateway-terminating-gateway-token Token
Local: true
Create Time: 2021-01-08 21:18:47.957450486 +0000 UTC
Policies:
63bf1d9b-a87d-8672-ddcb-d25e2d88adb8 - terminating-gateway-terminating-gateway-token
f63d1ae6-ffe7-44bd-bf7a-704a86939a63 - example-https-write-policy
Create the configuration entry for the terminating gateway
Once the tokens have been updated, create the TerminatingGateway resource to configure the terminating gateway:
apiVersion: consul.hashicorp.com/v1alpha1
kind: TerminatingGateway
metadata:
name: terminating-gateway
spec:
services:
- name: example-https
caFile: /etc/ssl/cert.pem
If TLS is enabled a caFile
must be provided, it must point to the system trust store of the terminating gateway container (/etc/ssl/cert.pem
).
Apply the TerminatingGateway
resource with kubectl apply
:
$ kubectl apply -f terminating-gateway.yaml
If using ACLs and TLS, create a ServiceIntentions resource to allow access from services in the mesh to the external service
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
name: example-https
spec:
destination:
name: example-https
sources:
- name: static-client
action: allow
Apply the ServiceIntentions
resource with kubectl apply
:
$ kubectl apply -f service-intentions.yaml
Define the external services as upstreams for services in the mesh
Finally define and deploy the external services as upstreams for the internal mesh services that wish to talk to them. An example deployment is provided which will serve as a static client for the terminating gateway service.
apiVersion: v1
kind: ServiceAccount
metadata:
name: static-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: static-client
spec:
replicas: 1
selector:
matchLabels:
app: static-client
template:
metadata:
name: static-client
labels:
app: static-client
annotations:
'consul.hashicorp.com/connect-inject': 'true'
'consul.hashicorp.com/connect-service-upstreams': 'example-https:1234'
spec:
containers:
# This name will be the service name in Consul.
- name: static-client
image: tutum/curl:latest
command: ['/bin/sh', '-c', '--']
args: ['while true; do sleep 30; done;']
# If ACLs are enabled, the serviceAccountName must match the Consul service name.
serviceAccountName: static-client
Run the service via kubectl apply
:
$ kubectl apply -f static-client.yaml
Wait for the service to be ready:
$ kubectl rollout status deploy static-client --watch
deployment "static-client" successfully rolled out
You can verify connectivity of the static-client and terminating gateway via a curl command:
$ kubectl exec deploy/static-client -- curl -vvvs -H "Host: example-https.com" http://localhost:1234/