Ingress Example with TLS Termination
This example builds on the HTTP and gRPC ingress examples, adding TLS termination.
# TLS ingress example, requires the below two applications
# https://raw.githubusercontent.com/istio/istio/release-1.11/samples/bookinfo/platform/kube/bookinfo.yaml
# https://github.com/GoogleCloudPlatform/microservices-demo
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
namespace: default
spec:
ingressClassName: cilium
rules:
- host: hipstershop.cilium.rocks
http:
paths:
- backend:
service:
name: productcatalogservice
port:
number: 3550
path: /hipstershop.ProductCatalogService
pathType: Prefix
- backend:
service:
name: currencyservice
port:
number: 7000
path: /hipstershop.CurrencyService
pathType: Prefix
- host: bookinfo.cilium.rocks
http:
paths:
- backend:
service:
name: details
port:
number: 9080
path: /details
pathType: Prefix
- backend:
service:
name: productpage
port:
number: 9080
path: /
pathType: Prefix
tls:
- hosts:
- bookinfo.cilium.rocks
- hipstershop.cilium.rocks
secretName: demo-cert
Create TLS Certificate and Private Key
For demonstration purposes we will use a TLS certificate signed by a made-up,
self-signed
certificate authority (CA). One easy way to do this is with minica.
We want a certificate that will validate bookinfo.cilium.rocks
and
hipstershop.cilium.rocks
, as these are the host names used in this example.
$ minica -domains '*.cilium.rocks'
On first run, minica
generates a CA certificate and key (minica.pem
and
minica-key.pem
). It also creates a directory called _.cilium.rocks
containing a key and certificate file that we will use for the TLS configuration.
Create a Kubernetes secret with this demo key and certificate:
$ kubectl create secret tls demo-cert --key=_.cilium.rocks/key.pem --cert=_.cilium.rocks/cert.pem
Let us install cert-manager:
$ helm repo add jetstack https://charts.jetstack.io
$ helm install cert-manager jetstack/cert-manager --version v1.10.0 \
--namespace cert-manager \
--set installCRDs=true \
--create-namespace \
--set "extraArgs={--feature-gates=ExperimentalGatewayAPISupport=true}"
Now, create a CA Issuer:
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/servicemesh/ca-issuer.yaml
Deploy the Ingress
The Ingress configuration for this demo provides the same routing as those demos but with the addition of TLS termination.
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/servicemesh/tls-ingress.yaml
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/kubernetes/servicemesh/tls-ingress.yaml
To tell cert-manager that this Ingress needs a certificate, annotate the Ingress with the name of the CA issuer we previously created:
$ kubectl annotate ingress tls-ingress cert-manager.io/issuer=ca-issuer
This creates a Certificate object along with a Secret containing the TLS certificate.
$ kubectl get certificate,secret demo-cert
NAME READY SECRET AGE
certificate.cert-manager.io/demo-cert True demo-cert 33m
NAME TYPE DATA AGE
secret/demo-cert kubernetes.io/tls 3 33m
External IP address will be shown up in Ingress
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
tls-ingress cilium hipstershop.cilium.rocks,bookinfo.cilium.rocks 35.195.24.75 80, 443 6m5s
In this Ingress configuration, the host names hipstershop.cilium.rocks
and
bookinfo.cilium.rocks
are specified in the path routing rules. The client
needs to specify which host it wants to access. This can be achieved by
editing your local /etc/hosts`
file. (You will almost certainly need to be
superuser to edit this file.) Add entries using the IP address
assigned to the ingress service, so your file looks something like this:
$ sudo perl -ni -e 'print if !/\.cilium\.rocks$/d' /etc/hosts; sudo tee -a /etc/hosts \
<<<"$(kubectl get ing tls-ingress -o=jsonpath='{.status.loadBalancer.ingress[0].ip}') bookinfo.cilium.rocks hipstershop.cilium.rocks"
Make HTTPS Requests
By specifying the CA’s certificate on a curl request, you can say that you trust certificates signed by that CA.
$ curl --cacert minica.pem -v https://bookinfo.cilium.rocks/details/1
If you prefer, instead of supplying the CA you can specify -k
to tell the
curl client not to validate the server’s certificate. Without either, you
will get an error that the certificate was signed by an unknown authority.
Specifying -v on the curl request, you can see that the TLS handshake took place successfully.
Similarly you can specify the CA on a gRPC request like this:
# Download demo.proto file if you have not done before
$ curl -o demo.proto https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/protos/demo.proto
$ grpcurl -proto ./demo.proto -cacert minica.pem hipstershop.cilium.rocks:443 hipstershop.ProductCatalogService/ListProducts
$ curl https://bookinfo.cilium.rocks/details/1
Similarly you can specify the CA on a gRPC request like this:
grpcurl -proto ./demo.proto -cacert minica.pem hipstershop.cilium.rocks:443 hipstershop.ProductCatalogService/ListProducts
Note
See the gRPC Ingress example if you don’t already have the demo.proto
file downloaded.
You can also visit https://bookinfo.cilium.rocks in your browser. The browser might warn you that the certificate authority is unknown but if you proceed past this, you should see the bookstore application home page.
Note that requests will time out if you don’t specify https://
.