Securing Your First Application Exposed Using TEG
This guide builds upon the steps in Expose Your Application, where the httpbin
application is exposed to external clients using Tetrate Envoy Gateway (TEG). Initially, traffic was sent in clear text (HTTP). In this guide, you will learn how to secure that communication using:
- TLS (HTTPS)
- Mutual TLS (mTLS)
Self-signed certificates are used for demonstration purposes only. For production, always use certificates issued by a trusted Certificate Authority (CA).
Enabling HTTPS (Server-side TLS Termination)
In this section, you will enable HTTPS access to your application using TLS termination at the gateway. The communication between the client and the gateway will be encrypted.
Generate Self-Signed Certificates
openssl req -x509 -sha256 -nodes -days 365 \
-newkey rsa:2048 \
-subj "/O=example Inc./CN=example.com" \
-keyout example.com.key \
-out example.com.crt
openssl req -out www.example.com.csr \
-newkey rsa:2048 -nodes \
-keyout www.example.com.key \
-subj "/CN=www.example.com/O=example organization"
openssl x509 -req -days 365 \
-CA example.com.crt \
-CAkey example.com.key \
-set_serial 0 \
-in www.example.com.csr \
-out www.example.com.crtCreate a TLS Secret in Kubernetes
kubectl create secret tls example-cert \
--key=www.example.com.key \
--cert=www.example.com.crt \
-n httpbinAdd an HTTPS Listener to the Gateway
kubectl patch gateway dedicated-gateway -n httpbin --type=json --patch '[{
"op": "add",
"path": "/spec/listeners/-",
"value": {
"name": "https",
"protocol": "HTTPS",
"port": 443,
"tls": {
"mode": "Terminate",
"certificateRefs": [{
"kind": "Secret",
"group": "",
"name": "example-cert"
}]
}
}
}]'Test HTTPS Access
As described in Expose Your Application, the client needs Tetrate Envoy Gateway's external IP address or port-forwarded address.
- For LB with External IP
- For LB with Hostname
- For Local without LB (Port-Forward)
We will set the
$GATEWAY_ADDRESS
to the external IP.export GATEWAY_ADDRESS=$(kubectl get gateway/dedicated-gateway -n httpbin -o jsonpath='{.status.addresses[0].value}')
Test https access:
curl --head -HHost:www.example.com \
--resolve "www.example.com:443:${GATEWAY_ADDRESS}" \
--cacert example.com.crt \
https://www.example.com/httpbin/status/200If your provider does not provide an ingress IP address, but rather a hostname (e.g., AWS) use the following to set the
$GATEWAY_ADDRESS
:export GATEWAY_ADDRESS=$(kubectl get service -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-namespace=httpbin -o jsonpath='{.items[0].status.loadBalancer.ingress[0].hostname}')
This tells curl to resolve www.example.com to the given hostname/IP on port 443.
Test https access:
curl --head -HHost:www.example.com \
--resolve "www.example.com:443:${GATEWAY_ADDRESS}" \
--cacert example.com.crt \
https://www.example.com/httpbin/status/200Set
$ENVOY_SERVICE
variable:export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=httpbin,gateway.envoyproxy.io/owning-gateway-name=dedicated-gateway -o jsonpath='{.items[0].metadata.name}')
Test https access:
kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8443:443 &
curl --head -HHost:www.example.com \
--resolve "www.example.com:8443:127.0.0.1" \
--cacert example.com.crt \
https://www.example.com:8443/httpbin/status/200Expected Output
HTTP/2 200
access-control-allow-credentials: true
access-control-allow-origin: *
content-type: text/plain; charset=utf-8
date: ...
Enforcing Mutual TLS (mTLS) for External Clients
Mutual TLS ensures both client and server authenticate each other. This section demonstrates configuring mTLS between external clients and the gateway.
Generate TLS Certificates
Reuse
example.com.crt
andexample.com.key
from previous steps.Create CA and client certs:
openssl req -out client.example.com.csr \
-newkey rsa:2048 -nodes \
-keyout client.example.com.key \
-subj "/CN=client.example.com/O=example organization"
openssl x509 -req -days 365 \
-CA example.com.crt \
-CAkey example.com.key \
-set_serial 0 \
-in client.example.com.csr \
-out client.example.com.crtCreate Required Secrets
kubectl create secret generic example-ca-cert --from-file=ca.crt=example.com.crt -n httpbin
Create ClientTrafficPolicy
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: enable-mtls
namespace: httpbin
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: dedicated-gateway
tls:
clientValidation:
caCertificateRefs:
- kind: "Secret"
group: ""
name: "example-ca-cert"kubectl apply -f client-traffic-policy.yaml
Test mTLS Access
- For LB with External IP
- For LB with Hostname
- For Local without LB (Port-Forward)
We will set the
$GATEWAY_ADDRESS
to the external IP.export GATEWAY_ADDRESS=$(kubectl get gateway/dedicated-gateway -n httpbin -o jsonpath='{.status.addresses[0].value}')
curl --head -HHost:www.example.com \
--resolve "www.example.com:443:${GATEWAY_ADDRESS}" \
--cert client.example.com.crt \
--key client.example.com.key \
--cacert example.com.crt \
https://www.example.com/httpbin/status/200If your provider does not provide an ingress IP address, but rather a hostname (e.g., AWS) use the following to set the
$GATEWAY_ADDRESS
:export GATEWAY_ADDRESS=$(kubectl get service -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-namespace=httpbin -o jsonpath='{.items[0].status.loadBalancer.ingress[0].hostname}')
This tells curl to resolve www.example.com to the given hostname/IP on port 443.
Test mTLS:
curl --head -HHost:www.example.com \
--resolve "www.example.com:443:${GATEWAY_ADDRESS}" \
--cert client.example.com.crt \
--key client.example.com.key \
--cacert example.com.crt \
https://www.example.com/httpbin/status/200Set
$ENVOY_SERVICE
variable:export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=httpbin,gateway.envoyproxy.io/owning-gateway-name=dedicated-gateway -o jsonpath='{.items[0].metadata.name}')
Test mTLS:
kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8443:443 &
curl --head -HHost:www.example.com \
--resolve "www.example.com:8443:127.0.0.1" \
--cert client.example.com.crt \
--key client.example.com.key \
--cacert example.com.crt \
https://www.example.com:8443/httpbin/status/200Expected output:
HTTP/2 200
access-control-allow-credentials: true
access-control-allow-origin: *
content-type: text/plain; charset=utf-8
date: ...Repeat the curl test without providing the client certificate and key (omit the
--cert client.example.com.crt
and--key client.example.com.key
options).Expected error:
curl: (35) Peer does not recognize and trust the CA that issued your certificate.
Troubleshooting
This section will be handy if you are experiencing any issues, such as certificate verification failures, 404 errors, or connectivity problems when accessing your application over HTTPS or mTLS.
- Error: Certificate verify failed
Ensure
--cacert
is correctly pointing to your CA certificate. - Gateway returns 404
Check
Host
header matches the Route configuration. - No response / timeout Confirm Gateway external IP is reachable and Listener is on port 443.