This is a quick recipe for deploying cert-manager and nginx-ingress on GKE to obtain SSL certificates from Lets Encrypt. Whilst this recipe is designed for Google Cloud Platform, it can easily be adapted for other cloud platforms.
We'll begin with a Kubernetes cluster, and we'll obtain authentication credentials.
gcloud container clusters get-credentials my-test-app
kubectl config current-context
kubectl get nodes
Next we're going to initialize Helm, adding RBAC support. A working example is shown below.
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
Next we apply these resources and initalize Helm on the cluster.
kubectl apply -f helm-rbac.yaml
helm init --service-account tiller --upgrade
kubectl -n kube-system get pods -l name=tiller
Once Tiller has been deployed, we're going to deploy the cert-manager package. Note we're going to disable ingress-shim as we are going to use Nginx class instead.
git clone https://github.com/jetstack/cert-manager
git checkout v0.2.3
helm install --name cert-manager contrib/charts/cert-manager --set ingressShim.extraArgs='{--default-issuer-name=letsencrypt-prod,--default-issuer-kind=ClusterIssuer}' --set ingressShim.enabled=false --namespace kube-system
kubectl -n kube-system get pods
Once the cert-manager pod is running we can go ahead and deploy the nginx-ingress helm package, providing a service with Load Balancer type and the controller.
helm install --name ingress-my-test-app stable/nginx-ingress --set rbac.create='true'
Wait for the LB service to deploy, and obtain the External IP for the load balancer
kubectl get svc -l app=nginx-ingress,component=controller -o=jsonpath='{$.items[*].status.loadBalancer.ingress[].ip}'
Now head over to your DNS provider and point test.example.com at the IP address returned above. Allow enough time for DNS propagation before proceeding to the next step.
We can now create our Issue (Lets Encrypt prod) and Certificate resources.
Issuer example:
apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
name: letsencrypt-prod
namespace: default
spec:
acme:
# The ACME server URL
server: https://acme-v01.api.letsencrypt.org/directory
# Email address used for ACME registration
email: [email protected]
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod-key
# Enable HTTP01 validations
http01: {}
Deployed using
kubectl apply -f issuer.yaml
An example Certificate resource
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: my-test-app
namespace: default
spec:
secretName: my-test-app-crt
commonName: test.example.com
dnsNames:
- test.example.com
issuerRef:
name: letsencrypt-prod
kind: Issuer
acme:
config:
- http01:
ingressClass: nginx
domains:
- test.example.com
Deployed by:
kubectl apply -f certificate.yaml
The next step is to deploy our Ingress resource, using this example:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: my-test-app
namespace: default
spec:
rules:
- host: test.example.com
http:
paths:
- backend:
serviceName: echoserver
servicePort: 8080
path: /echo
tls:
- hosts:
- test.example.com
secretName: my-test-app-crt
Deploy this ingress
kubectl apply -f ingress.yaml
The penultimate step is to deploy your backend App. For this example we'll use echoserver, but you can substitute it with your own app/service.
This example:
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: echoserver
spec:
replicas: 1
template:
metadata:
labels:
app: echoserver
spec:
containers:
- image: gcr.io/google_containers/echoserver:1.0
imagePullPolicy: Always
name: echoserver
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: echoserver
spec:
ports:
- port: 8080
targetPort: 8080
protocol: TCP
selector:
app: echoserver
can be deployed with
kubectl apply -f echoserver.yaml
Now, assuming everything above has worked you can test it.
# This should return 404 Not Found (the default backend)
curl -s https://test.example.com/
and
# This should return your request parameters (echoserver)
curl -s https://test.example.com/echo
Hopefully profit! and congratulations, your app is now served via TLS support.