Skip to content

Instantly share code, notes, and snippets.

@mindovermiles262
Created February 15, 2021 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mindovermiles262/0dd47d2cc6e53d18e604820b08050d3a to your computer and use it in GitHub Desktop.
Save mindovermiles262/0dd47d2cc6e53d18e604820b08050d3a to your computer and use it in GitHub Desktop.

Deploying an HTTPS Website with Istio and Cert-Manager Part 2

In this tutorial I'll be walking you through you how to deploy an HTTPS microservice website using Kubernetes, Istio and Kubernetes cert-manager.

Overview

This is part 2 of a two-part series. The first part takes you through the Kubernetes cluster setup, installing and configuring Istio on that cluster, and deploying your first application on the cluster. In part 2 we'll learn how to use Istio gateways, routes, and how to secure your website with Kubernetes cert-manager.

Cert-Manager

In order for our website to use HTTPS, we need to configure our Kubernetes cluster to use the cert-manager plugin. This plugin allows you to generate SSL certificates for your website automatically. To install cert-manager we'll use our Kubernetes package manager and friend Helm. Run the following 3 commands:

$ helm repo add jetstack https://charts.jetstack.io
$ helm repo update
$ helm install cert-manager jetstack/cert-manager \
  --namespace istio-system \
  --set installCRDs=true

When successful you'll see a message:

cert-manager has been deployed successfully!

In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).

More information on the different types of issuers and how to configure them
can be found in our documentation:

https://cert-manager.io/docs/configuration/

For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:

https://cert-manager.io/docs/usage/ingress/

Issuer

The cert-manager relies on a new Kubernetes api-resource called an Issuer to... well... issue certificates. It will then store the certificate inside of a Kubernetes Secret, defined in the YAML of the issuer (called my-certificate-key in this example). Be sure to update your email address

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: my-issuer
  namespace: istio-system
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: YOUR-EMAIL
    privateKeySecretRef:
      name: my-certificate-key
    solvers:
    - selector: {}
      http01:
        ingress:
          class: istio

Save the YAML and apply it:

$ kubectl apply -f my-issuer.yml

issuer.cert-manager.io/my-issuer created

You can verify the certificate was created by listing the secrets in the istio-system namespace. You should see an entry for my-certificate-key:

$ kubectl -n istio-system get secrets

NAME                                               TYPE                                  DATA   AGE
[ ... ]
my-certificate-key                                 Opaque                                1      5s

Certificates

We've finally made it to where we can get our SSL certificate. To do this, we'll create a new Certificate Kubernetes API resource. This certificate resource will, in this example, be called my-cert and live in the istio-system namespace. It will save it's certificate's .key and .crt files in a Kubernetes secret named my-ingress-cert. The issuerRef name must match the Issuer we created above, and the certificate must live in the same namespace as the istio-ingressgateway. Also don't forget to update your dnsNames.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-cert
  namespace: istio-system
spec:
  secretName: my-ingress-cert              
  issuerRef:
    name: my-issuer
  dnsNames:
  - YOURDOMAIN.com

Before applying your certificate YAML, double check that your domain is resolvable to your Istio Ingress Gateway IP address

$ nslookup YOURDOMAIN.COM

Non-authoritative answer:
Name:   YOURDOMAIN.COM
Address: 34.123.203.201

Once confirmed, apply your certificate:

$ kubectl apply -f my-certificate.yml

certificate.cert-manager.io/my-cert created

Listing the secrets of istio-system namespace should now include the my-ingress-cert secret:

$ kubectl get secret -n istio-system
NAME                                               TYPE                                  DATA   AGE
[ ... ]
my-certificate-key                                 Opaque                                1      15m
my-ingress-cert                                    kubernetes.io/tls                     2      15s

Gateways

With our SSL certificate in place, the last thing we need to do is route the incoming traffic to our pods. This is all done by Istio Gateways and VirtualServices. Let's create our first Istio gateway. We'll create a new Gateway named bookinfo-gateway-https which will reside in the default Kubernetes namespace. The gateway will listen on port 80 for YOURDOMAIN.COM and redirect traffic to HTTPS Port 443. The gateway will also be listening on HTTPS/443 for YOURDOMAIN.COM and use the certificate we created in the previous step, my-ingress-cert

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway-https
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "YOURDOMAIN.COM"
    tls:
      httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
      - "YOURDOMAIN.COM"
    tls:
      mode: SIMPLE
      credentialName: my-ingress-cert

Apply the gateway YAML file:

$ kubectl apply -f my-gateway.yml

gateway.networking.istio.io/bookinfo-gateway-https created

Virtual Services

The last component of this that we need to set up are the Virtual Services. Similar to those in NGINX or Apache, we need to configure the routes that Istio will direct traffic that comes in on YOURDOMAIN.COM to. These routes are called "Virtual Services" and are defined by yet another YAML file. The virtual service will route all requests to /productpage, /static, /login, /logout, and /api/v1/products through the bookinfo-gateway-https gateway we created above and route it to the productpage service of the application. This productpage service was created when we deployed the bookinfo application in part 1 of this tutorial.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo-virtualservice
spec:
  hosts:
  - "YOURDOMAIN.COM"
  gateways:
  - bookinfo-gateway-https
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080

Apply your virtual services:

$ kubectl apply -f my-virtualservice.yml

virtualservice.networking.istio.io/bookinfo-virtualservice created

Hooray! You've done it! You should be able to go to https://YOURDOMAIN.COM/productpage and see the beautiful bookinfo example application deployed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment