I have a simple web server exposed publicly on Kubernetes on GKE and a domain registered. I'm looking to add TLS to this so it's accessible via HTTPS. I've heard a lot about using Let's Encrypt and ended up attempting this: https://github.com/jetstack/cert-manager/blob/master/docs/tutorials/acme/quick-start/index.rst but found it totally over-whelming. Is there a simpler approach to using Let's Encrypt given that my deployment is just a single service and pod?
The config I'm using is:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: gcr.io/my-repo
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: /healthz
port: 8080
---
apiVersion: v1
kind: Service
metadata:
name: web-balancer-service
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
run: web
type: NodePort
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress-app
spec:
rules:
- host: my.domain.com
http:
paths:
- path: /*
backend:
serviceName: web-balancer-service
servicePort: 8080
\========================================
EDIT: Following @Utku Özdemir's suggestion I tried to codify those changes into YAML. I created the IP address with
gcloud compute addresses create example-ip-address --global
And the certificate and provisioning with: https://gist.github.com/nickponline/ab74d3d179e21474551b7596c6478eea
Everything provisions correctly but when I inspect the ManagedCertificates with kubectl describe ManagedCertificates example-certificate
is says
Spec:
Domains:
app.domain.xyz
Status:
Certificate Name: xxxxxxxxxxxxxxxxxx
Certificate Status: Provisioning
Domain Status:
Domain: app.domain
Status: FailedNotVisible
Events: <none>
I've waited 24 hours so assume that this isn't going to change.
Since you use the ingress controller of the GKE itself, when you create an Ingress resource, it triggers the creation of a Load Balancer resource in the Google Cloud Platform. Normally, SSL termination is a responsibility of the ingress controller, therefore that GCP load balancer is responsible of doing the SSL termination.
This means, cert-manager will not work for your case, since the certificates will live outside of your cluster, and the traffic will be already SSL terminated before coming in your cluster.
Luckily, GCP has self-provisioned SSL (Let's Encrypt) support. To make use of that, yo need to follow the steps below:
Go to the Load Balancing screen on GCP, switch to advanced view, and jump to the Certificates tab (or simply click here).
Create a new SSL certificate, with "Create Google-managed certificate" chosen. To the domain field, write down the exact domain you want the SSL certificate for. It should look like this:
34.95.84.106
)Go to your domain registrar, and add an A
type record for your domain (the one in the SSL certificate) to point to the static IP you allocated. In this example, it would be my-app.example.com -> 34.95.84.106
.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress-app
annotations:
ingress.gcp.kubernetes.io/pre-shared-cert: my-ssl-certificate # the name of the SSL certificate resource you created
kubernetes.io/ingress.global-static-ip-name: my-static-ip # the name of the static ip resource you created
kubernetes.io/ingress.allow-http: "false" # if you want to block plain http
spec:
rules:
- host: my-app.example.com
http:
paths:
- path: /*
backend:
serviceName: web-balancer-service
servicePort: 8080
Apply it, and verify that the changes are reflected by going to the Load Balancers screen on GCP.
If there already is a GCP Load Balancer that is created by an Ingress, the changes you do (annotations) on the ingress will not reflect to the existing load balancer. Therefore, delete your existing ingress, make sure the existing load-balancer disappears, and create the ingress with correct annotations, so the load balancer will be configured correctly.
For the Let's Encrypt provisioning to work, your DNS record should be in place. It checks the owner of the domain using DNS before issuing the certificate. Also, the initial provisioning can take quite some time (up to half an hour).