This user guide walks you through an example of how to configure TLS for all routes attached to an ingress gateway.
This step uses tooling from the Kuadrant Operator component to create a containerized Kubernetes server locally using Kind, where it installs Istio, Kubernetes Gateway API, CertManager and Kuadrant itself.
Clone the project:
git clone https://github.com/Kuadrant/kuadrant-operator && cd kuadrant-operator
Setup the environment:
make local-setup
Create a namespace:
kubectl create namespace my-gateways
Create a gateway:
kubectl -n my-gateways apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-web
spec:
gatewayClassName: istio
listeners:
- allowedRoutes:
namespaces:
from: All
name: api
hostname: "*.toystore.local"
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- name: toystore-local-tls
kind: Secret
EOF
The TLSPolicy requires a reference to an existing CertManager Issuer.
Create a CertManager Issuer:
kubectl apply -n my-gateways -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
EOF
Note: We are using a self-signed issuer here but any supported CerManager issuer or cluster issuer can be used.
kubectl get issuer selfsigned-issuer -n my-gateways
Response:
NAME READY AGE
selfsigned-issuer True 18s
Create a Kuadrant TLSPolicy
to configure TLS:
kubectl apply -n my-gateways -f - <<EOF
apiVersion: kuadrant.io/v1alpha1
kind: TLSPolicy
metadata:
name: prod-web
spec:
targetRef:
name: prod-web
group: gateway.networking.k8s.io
kind: Gateway
issuerRef:
group: cert-manager.io
kind: Issuer
name: selfsigned-issuer
EOF
Check policy status:
kubectl get tlspolicy -o wide -n my-gateways
Response:
NAME STATUS TARGETREFKIND TARGETREFNAME AGE
prod-web Accepted Gateway prod-web 13s
Check a Certificate resource was created:
kubectl get certificates -n my-gateways
Response
NAME READY SECRET AGE
toystore-local-tls True toystore-local-tls 7m30s
Check a TLS Secret resource was created:
kubectl get secrets -n my-gateways --field-selector="type=kubernetes.io/tls"
Response:
NAME TYPE DATA AGE
toystore-local-tls kubernetes.io/tls 3 7m42s
Deploy the sample API:
kubectl -n my-gateways apply -f examples/toystore/toystore.yaml
kubectl -n my-gateways wait --for=condition=Available deployments toystore --timeout=60s
Route traffic to the API from our gateway:
kubectl -n my-gateways apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: toystore
spec:
parentRefs:
- name: prod-web
namespace: my-gateways
hostnames:
- "*.toystore.local"
rules:
- backendRefs:
- name: toystore
port: 80
EOF
Get the gateway address@
GWADDRESS=`kubectl get gateway/prod-web -n my-gateways -o=jsonpath='{.status.addresses[?(@.type=="IPAddress")].value}'`
echo $GWADDRESS
Response:
172.18.200.1
Verify we can access the service via TLS:
curl -vkI https://api.toystore.local --resolve "api.toystore.local:443:$GWADDRESS"
Response:
* Added api.toystore.local:443:172.18.200.1 to DNS cache
* Hostname api.toystore.local was found in DNS cache
* Trying 172.18.200.1:443...
* Connected to api.toystore.local (172.18.200.1) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
* subject: [NONE]
* start date: Feb 15 11:46:50 2024 GMT
* expire date: May 15 11:46:50 2024 GMT
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* h2h3 [:method: HEAD]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: api.toystore.local]
* h2h3 [user-agent: curl/7.85.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x5623e4fe5bf0)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> HEAD / HTTP/2
> Host: api.toystore.local
> user-agent: curl/7.85.0
> accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection state changed (MAX_CONCURRENT_STREAMS == 2147483647)!
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 200
HTTP/2 200
< content-type: application/json
content-type: application/json
< server: istio-envoy
server: istio-envoy
< date: Thu, 15 Feb 2024 12:13:27 GMT
date: Thu, 15 Feb 2024 12:13:27 GMT
< content-length: 1658
content-length: 1658
< x-envoy-upstream-service-time: 1
x-envoy-upstream-service-time: 1
<
* Connection #0 to host api.toystore.local left intact
make local-cleanup