2020-07-22 21:02:47 +00:00
---
layout: docs
page_title: Terminating Gateways - Kubernetes
description: Configuring Terminating Gateways on Kubernetes
---
# Terminating Gateways on Kubernetes
2021-01-08 22:30:41 +00:00
-> 1.9.0+: This feature is available in Consul versions 1.9.0 and higher
2020-07-22 21:02:47 +00:00
~> This topic requires familiarity with [Terminating Gateways](/docs/connect/terminating-gateway).
Adding a terminating gateway is a multi-step process:
2021-04-16 19:49:02 +00:00
- Update the Helm chart with terminating gateway config options
- Deploy the Helm chart
2021-01-08 22:30:41 +00:00
- Access the Consul agent
2020-08-18 22:22:29 +00:00
- Register external services with Consul
2020-07-22 21:02:47 +00:00
## Update the helm chart with terminating gateway config options
Minimum required Helm options:
2021-07-31 01:37:33 +00:00
<CodeBlockConfig filename="config.yaml">
2020-07-22 21:02:47 +00:00
```yaml
global:
name: consul
connectInject:
enabled: true
2021-01-08 22:30:41 +00:00
controller:
enabled: true
2020-07-22 21:02:47 +00:00
terminatingGateways:
enabled: true
```
2021-07-31 01:37:33 +00:00
</CodeBlockConfig>
2021-04-16 19:49:02 +00:00
## Deploying the Helm chart
2020-07-22 21:02:47 +00:00
Ensure you have the latest consul-helm chart and install Consul via helm using the following
2020-09-14 17:37:35 +00:00
[guide](/docs/k8s/installation/install#installing-consul) while being sure to provide the yaml configuration
2020-07-22 21:02:47 +00:00
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.
```shell-session
2021-01-08 22:30:41 +00:00
$ kubectl port-forward consul-server-0 8500 &
2020-07-22 21:02:47 +00:00
```
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
If TLS is enabled use port 8501:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
2021-01-08 22:30:41 +00:00
$ kubectl port-forward consul-server-0 8501 &
2020-07-22 21:02:47 +00:00
```
-> Be sure the latest consul binary is installed locally on your host.
[https://releases.hashicorp.com/consul/](https://releases.hashicorp.com/consul/)
```shell-session
$ export CONSUL_HTTP_ADDR=http://localhost:8500
```
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
If TLS is enabled set:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
$ export CONSUL_HTTP_ADDR=https://localhost:8501
$ export CONSUL_HTTP_SSL_VERIFY=false
```
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
If ACLs are enabled also set:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
2021-07-28 15:40:35 +00:00
$ export CONSUL_HTTP_TOKEN=$(kubectl get secret consul-bootstrap-acl-token -o jsonpath={.data.token} | base64 --decode)
2020-07-22 21:02:47 +00:00
```
## Register external services with Consul
Registering the external services with Consul is a multi-step process:
2020-08-18 22:22:29 +00:00
- Register external services with Consul
- Update the terminating gateway ACL token if ACLs are enabled
2021-01-08 22:30:41 +00:00
- Create a [`TerminatingGateway`](/docs/connect/config-entries/terminating-gateway) resource to configure the terminating gateway
- Create a [`ServiceIntentions`](/docs/connect/config-entries/service-intentions) resource to allow access from services in the mesh to external service
2020-08-18 22:22:29 +00:00
- Define upstream annotations for any services that need to talk to the external services
2020-07-22 21:02:47 +00:00
### Register external services with Consul
2021-06-14 16:15:40 +00:00
-> **Note:** Normal Consul services are registered with the Consul client on the node that
they're running on. Since this is an external service, there is no Consul node
to register it onto. Instead, we will make up a node name and register the
service to that node.
2020-07-22 21:02:47 +00:00
Create a sample external service and register it with Consul.
2020-08-18 22:22:29 +00:00
2021-07-31 01:37:33 +00:00
<CodeBlockConfig filename="external.json">
2020-07-22 21:02:47 +00:00
```json
{
2021-06-14 16:15:40 +00:00
"Node": "example_com",
2020-08-18 22:22:29 +00:00
"Address": "example.com",
"NodeMeta": {
"external-node": "true",
"external-probe": "true"
},
"Service": {
2021-06-14 16:15:40 +00:00
"Address": "example.com",
2020-08-18 22:22:29 +00:00
"ID": "example-https",
"Service": "example-https",
"Port": 443
}
2020-07-22 21:02:47 +00:00
}
```
2021-07-31 01:37:33 +00:00
</CodeBlockConfig>
2021-06-14 16:15:40 +00:00
- `"Node": "example_com"` is our made up node name.
- `"Address": "example.com"` is the address of our node. Services registered to that node will use this address if
their own address isn't specified. If you're registering multiple external services, ensure you
use different node names with different addresses or set the `Service.Address` key.
- `"Service": { "Address": "example.com" ... }` is the address of our service. In this example this doesn't need to be set
since the address of the node is the same, but if there were two services registered to that same node
then this should be set.
2020-07-22 21:02:47 +00:00
Register the external service with Consul:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
$ curl --request PUT --data @external.json -k $CONSUL_HTTP_ADDR/v1/catalog/register
2021-01-08 22:30:41 +00:00
true
2020-07-22 21:02:47 +00:00
```
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
If ACLs and TLS are enabled :
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
$ curl --request PUT --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" --data @external.json -k $CONSUL_HTTP_ADDR/v1/catalog/register
2021-01-08 22:30:41 +00:00
true
2020-07-22 21:02:47 +00:00
```
### Update terminating gateway ACL token if ACLs are enabled
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
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:
2020-08-18 22:22:29 +00:00
- Create a new policy that includes these permissions
- Update the existing token to include the new policy
2020-07-23 16:19:33 +00:00
2020-07-22 21:02:47 +00:00
~> 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
2021-07-31 01:37:33 +00:00
<CodeBlockConfig filename="write-policy.hcl">
2020-07-22 21:02:47 +00:00
```hcl
service "example-https" {
policy = "write"
}
```
2020-08-18 22:22:29 +00:00
2021-07-31 01:37:33 +00:00
</CodeBlockConfig>
2020-07-22 21:02:47 +00:00
```shell-session
$ consul acl policy create -name "example-https-write-policy" -rules @write-policy.hcl
2021-01-08 22:30:41 +00:00
ID: xxxxxxxxxxxxxxx
Name: example-https-write-policy
Description:
Datacenters:
Rules:
service "example-https" {
policy = "write"
}
2020-07-22 21:02:47 +00:00
```
2020-08-18 22:22:29 +00:00
2021-04-16 19:49:02 +00:00
Now fetch the ID of the terminating gateway token
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
2021-01-08 22:30:41 +00:00
consul acl token list | grep -B 6 -- "- terminating-gateway-terminating-gateway-token" | grep AccessorID
AccessorID: <token id>
2020-07-22 21:02:47 +00:00
```
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
Update the terminating gateway acl token with the new policy
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
$ consul acl token update -id <token-id> -policy-name example-https-write-policy -merge-policies -merge-roles -merge-service-identities
2021-01-08 22:30:41 +00:00
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
2020-07-22 21:02:47 +00:00
```
### Create the configuration entry for the terminating gateway
2020-08-18 22:22:29 +00:00
2021-01-13 20:48:48 +00:00
Once the tokens have been updated, create the [TerminatingGateway](/docs/connect/config-entries/terminating-gateway)
2021-01-08 22:30:41 +00:00
resource to configure the terminating gateway:
2020-08-18 22:22:29 +00:00
2021-07-31 01:37:33 +00:00
<CodeBlockConfig filename="terminating-gateway.yaml">
```yaml
2021-01-08 22:30:41 +00:00
apiVersion: consul.hashicorp.com/v1alpha1
kind: TerminatingGateway
metadata:
name: terminating-gateway
spec:
services:
- name: example-https
caFile: /etc/ssl/cert.pem
2020-07-22 21:02:47 +00:00
```
2020-08-18 22:22:29 +00:00
2021-07-31 01:37:33 +00:00
</CodeBlockConfig>
2021-01-08 22:30:41 +00:00
~> 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`).
2020-07-22 21:02:47 +00:00
2021-01-08 22:30:41 +00:00
Apply the `TerminatingGateway` resource with `kubectl apply`:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
2021-01-08 22:30:41 +00:00
$ kubectl apply -f terminating-gateway.yaml
2020-07-22 21:02:47 +00:00
```
2021-01-08 22:30:41 +00:00
If using ACLs and TLS, create a [`ServiceIntentions`](/docs/connect/config-entries/service-intentions) resource to allow access from services in the mesh to the external service
2021-07-31 01:37:33 +00:00
<CodeBlockConfig filename="service-intentions.yaml">
2021-01-08 22:30:41 +00:00
```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
name: example-https
spec:
destination:
name: example-https
sources:
- name: static-client
action: allow
```
2021-07-31 01:37:33 +00:00
</CodeBlockConfig>
2021-01-08 22:30:41 +00:00
Apply the `ServiceIntentions` resource with `kubectl apply`:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
2021-01-08 22:30:41 +00:00
$ kubectl apply -f service-intentions.yaml
2020-07-22 21:02:47 +00:00
```
### Define the external services as upstreams for services in the mesh
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
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.
2021-07-31 01:37:33 +00:00
<CodeBlockConfig filename="static-client.yaml">
2020-07-22 21:02:47 +00:00
```yaml
apiVersion: v1
2021-04-16 19:49:02 +00:00
kind: Service
metadata:
name: static-client
spec:
selector:
app: static-client
ports:
- port: 80
---
apiVersion: v1
2020-07-22 21:02:47 +00:00
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:
2020-08-18 22:22:29 +00:00
'consul.hashicorp.com/connect-inject': 'true'
'consul.hashicorp.com/connect-service-upstreams': 'example-https:1234'
2020-07-22 21:02:47 +00:00
spec:
containers:
- name: static-client
2021-06-29 20:23:36 +00:00
image: curlimages/curl:latest
2020-08-18 22:22:29 +00:00
command: ['/bin/sh', '-c', '--']
args: ['while true; do sleep 30; done;']
2020-07-22 21:02:47 +00:00
serviceAccountName: static-client
```
2021-07-31 01:37:33 +00:00
</CodeBlockConfig>
2020-07-22 21:02:47 +00:00
Run the service via `kubectl apply`:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
$ kubectl apply -f static-client.yaml
```
2021-01-08 22:30:41 +00:00
Wait for the service to be ready:
```shell-session
$ kubectl rollout status deploy static-client --watch
deployment "static-client" successfully rolled out
```
2020-07-22 21:02:47 +00:00
You can verify connectivity of the static-client and terminating gateway via a curl command:
2020-08-18 22:22:29 +00:00
2020-07-22 21:02:47 +00:00
```shell-session
2020-07-23 16:19:33 +00:00
$ kubectl exec deploy/static-client -- curl -vvvs -H "Host: example-https.com" http://localhost:1234/
2020-07-22 21:02:47 +00:00
```