Configure Terminating Gateways for Consul 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:
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.
If TLS is enabled use port 8501:
Be sure the latest consul binary is installed locally on your host. https://releases.hashicorp.com/consul/
If TLS is enabled set:
If ACLs are enabled also set:
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
There are two ways to register an external service with Consul:
- If
TransparentProxy
is enabled, the preferred method is to declare external endpoints in thedestination
field ofServiceDefaults
. - You can add the service as a node in the Consul catalog.
Register an external service as a destination
The destination
field of the ServiceDefaults
Custom Resource Definition (CRD) allows clients to dial the external service directly. It is valid only in TransparentProxy
) mode.
The following table describes traffic behaviors when using destination
s to route traffic through a terminating gateway:
External Services Layer | Client dials | Client uses TLS | Allowed | Notes |
---|---|---|---|---|
L4 | Hostname | Yes | Allowed | CAFiles are not allowed because traffic is already end-to-end encrypted by the client. |
L4 | IP | Yes | Allowed | CAFiles are not allowed because traffic is already end-to-end encrypted by the client. |
L4 | Hostname | No | Not allowed | The sidecar is not protocol aware and can not identify traffic going to the external service. |
L4 | IP | No | Allowed | There are no limitations on dialing IPs without TLS. |
L7 | Hostname | Yes | Not allowed | Because traffic is already encrypted before the sidecar, it cannot route as L7 traffic. |
L7 | IP | Yes | Not allowed | Because traffic is already encrypted before the sidecar, it cannot route as L7 traffic. |
L7 | Hostname | No | Allowed | A Host or :authority header is required. |
L7 | IP | No | Allowed | There are no limitations on dialing IPs without TLS. |
You can provide a caFile
to secure traffic between unencrypted clients that connect to external services through the terminating gateway.
Refer to Create the configuration entry for the terminating gateway for details.
Also note that regardless of the protocol
specified in the ServiceDefaults
, L7 intentions are not currently supported with ServiceDefaults
destinations.
Create a ServiceDefaults
custom resource for the external service:
Apply the ServiceDefaults
resource with kubectl apply
:
All other terminating gateway operations can use the name of the ServiceDefaults
in place of a typical Consul service name.
Register an external service as a Catalog Node
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.
Create a sample external service and register it with Consul.
"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 theService.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.
Register the external service with Consul:
If ACLs and TLS are enabled :
Update terminating gateway ACL role if ACLs are enabled
If ACLs are enabled, update the terminating gateway acl role 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 role to include the new policy
Now fetch the ID of the terminating gateway token
Update the terminating gateway acl token with the new policy
Create the configuration entry for the terminating gateway
Once the roles have been updated, create the TerminatingGateway resource to configure the terminating gateway:
If TLS is enabled for external services registered through the Consul catalog and you are not using transparent proxy destination
, you must include the caFile
parameter that points to the system trust store of the terminating gateway container.
By default, the trust store is located in the /etc/ssl/certs/ca-certificates.crt
directory.
Configure the caFile
parameter in the TerminatingGateway
config entry to point to the /etc/ssl/cert.pem
directory if TLS is enabled and you are using one of the following components:
- Consul Helm chart 0.43 or older
- An Envoy image with an alpine base image
For ServiceDefaults
destinations, refer to Register an external service as a destination.
Apply the TerminatingGateway
resource with kubectl apply
:
If using ACLs and TLS, create a ServiceIntentions
resource to allow access from services in the mesh to the external service:
NOTE: L7 Intentions are not currently supported for ServiceDefaults
destinations.
Apply the ServiceIntentions
resource with kubectl apply
:
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.
Run the service via kubectl apply
:
Wait for the service to be ready:
You can verify connectivity of the static-client and terminating gateway via a curl command: