×
Community Blog Setting up Let's Encrypt on Alibaba Cloud

Setting up Let's Encrypt on Alibaba Cloud

This tutorial shows how you can set up Let's Encrypt to secure your Kubernetes application on Alibaba Cloud.

By Anish Nath.

Alibaba cloud's built-in Kubernetes engine does not offer an out-of-the-box HTTPS solution or TLS/SSL certificates for your website. For this, you can set up Let's Encrypt. Let's Encrypt is a handy, non-profit Certificate Authority that provides free TLS/SSL certificates that can be used to secure websites with HTTPS encryption. In tandem with Let's Encrypt, you will also need to set up cert-manager and nginx-ingress. cert-manager is a third-party Kubernetes controller that automates getting TLS/SSL certificates from Let's Encrypt and refreshing them. Next, nginx-ingress, which is an Ingress Controller, is a daemon, deployed as a Kubernetes Pod, which watches the apiserver's /ingresses endpoint for updates to the Ingress resource. Its job is to satisfy requests for Ingresses.

The following diagram shows how all of these can work together.

1

So in this tutorial, you will learn how you can set up Let's Encrypt along with cert-manager and nginx-ingress on Alibaba Cloud to achieve the above architecture and secure your Kubernetes application.

Requirements

For this tutorial, you will need the following items. Note that, in the below steps, I will go over how you can set up your Kubernetes cluster.

  • A registered Alibaba Cloud Account.
  • A registered domain name, such as zariga.com, that is pointing to a Kubernetes Service Type loadbalancer.
  • An Alibaba Cloud Kubernetes cluster. Note that the following setup, pictured below, is created in Alibaba Cloud and will be used for this demo.

2

Setting up a Kubernetes Cluster

If you don't have a Kubernetes cluster and want to set up a Kubernetes cluster, you can follow these steps:

Initialize the master using the following command.

master# sudo kubeadm init --pod-network-cidr=192.168.0.0/16

Execute the following commands to configure kubectl (also returned by kubeadm init).

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Install an etcd instance.

master# kubectl apply -f \
https://docs.projectcalico.org/v3.5/getting-started/kubernetes/installation/hosted/etcd.yaml

Install Calico.

master# kubectl apply -f \
https://docs.projectcalico.org/v3.5/getting-started/kubernetes/installation/hosted/calico.yaml

Confirm that all of the pods are running with the following command.

NAMESPACE    NAME                                       READY  STATUS   RESTARTS  AGE
kube-system  calico-etcd-x2482                          1/1    Running  0         2m45s
kube-system  calico-kube-controllers-6ff88bf6d4-tgtzb   1/1    Running  0         2m45s
kube-system  calico-node-24h85                          2/2    Running  0         2m43s
kube-system  coredns-846jhw23g9-9af73                   1/1    Running  0         4m5s
kube-system  coredns-846jhw23g9-hmswk                   1/1    Running  0         4m5s
kube-system  etcd-jbaker-1                              1/1    Running  0         6m22s
kube-system  kube-apiserver-jbaker-1                    1/1    Running  0         6m12s
kube-system  kube-controller-manager-jbaker-1           1/1    Running  0         6m16s
kube-system  kube-proxy-8fzp2                           1/1    Running  0         5m16s
kube-system  kube-scheduler-jbaker-1                    1/1    Running  0         5m41s

On the minion node join the cluster (also returned by kubeadm init).

minion# kubeadm join 172.20.240.112:6443 --token 2xg5nx.zv65d9mnz4g1802b --discovery-token-ca-cert-hash sha256:1cae1effbad759b7c70572dd509936340db5cc7d38ff1951422d45b91b3de03c

Installing Helm

Now, let's set up and install Hel. To do this, follow these steps:

Download the helm binary from the official helm repo.

root@kube-master:~# wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.0-linux-amd64.tar.gz

Extract the helm tar file.

root@kube-master:~# tar -zxvf helm-v2.13.0-linux-amd64.tar.gz 
linux-amd64/
linux-amd64/LICENSE
linux-amd64/README.md
linux-amd64/helm
linux-amd64/tiller

Move the helm to your $PATH location.

root@kube-master:~# mv linux-amd64/helm /usr/local/bin/helm

Install the Helm server-side components (Tiller) on your Alibaba Cloud cluster.

kubectl create serviceaccount -n kube-system tiller
kubectl create clusterrolebinding tiller-binding \
    --clusterrole=cluster-admin \
    --serviceaccount kube-system:tiller
helm init --service-account tiller

Once tiller pod becomes ready, update chart repositories:

helm repo update

Installing Cert-Manager

Now, it's time to set up cert-manager. To do so follow these steps:

Install cert-manager using the helm chart.

root@kube-master:~# helm install --name cert-manager --version v0.5.2  --namespace kube-system stable/cert-manager

The output is as follows:

NAME:   cert-manager
LAST DEPLOYED: Tue Mar 12 15:29:21 2019
NAMESPACE: kube-system
STATUS: DEPLOYED

RESOURCES:
==> v1/Pod(related)
NAME                           READY  STATUS             RESTARTS  AGE
cert-manager-6464494858-4lhjg  0/1    ContainerCreating  0         1s

==> v1/ServiceAccount
NAME          SECRETS  AGE
cert-manager  1        1s

==> v1beta1/ClusterRole
NAME          AGE
cert-manager  1s

==> v1beta1/ClusterRoleBinding
NAME          AGE
cert-manager  1s

==> v1beta1/Deployment
NAME          READY  UP-TO-DATE  AVAILABLE  AGE
cert-manager  0/1    1           0          1s


NOTES:
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.readthedocs.io/en/latest/reference/issuers.html

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.readthedocs.io/en/latest/reference/ingress-shim.html

Configuring the Let's Encrypt Cluster Issuer

And, now, let's configure the Let's Encrypt Cluster Issuer for the staging and production environment. To start, adjust the email according to your specific needs.

root@kube-master:~# cat letsencrypt-issuer.yaml 
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: 'zarigatongy@gmail.com'
    privateKeySecretRef:
      name: letsencrypt-staging
    http01: {}
---
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: 'zarigatongy@gmail.com'
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}

Apply the cluster Issuer in your Kubernetes cluster.

root@kube-master:~# kubectl apply -f letsencrypt-issuer.yaml 
clusterissuer.certmanager.k8s.io/letsencrypt-staging created
clusterissuer.certmanager.k8s.io/letsencrypt-prod created

Deploying a Web App on a Domain Name

To deploy a web app on a doemain name, for testing purposes, create a NGINX deployment and exposing over clusterIP.

kubectl create deployment --image nginx my-nginx
kubectl expose deployment my-nginx --port=80 --type=ClusterIP
root@kube-master:~# kubectl get svc
NAME TYPE  CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1  <none>  443/TCP 28h
my-nginx ClusterIP 10.101.150.247 <none>  80/TCP  25h

Installing the NGINX Ingress Controller

Now, let's move on to installing the NGINX ingress control. To do this, first use helm chart stable/nginx-ingress for the installation.

helm install stable/nginx-ingress --namespace kube-system

On successful install, the helm chart will show that nginx-ingress is deployed.

root@kube-master:~# helm ls
NAME REVISION  UPDATED STATUS  CHART  APP VERSION  NAMESPACE
cert-manager 1 Tue Mar 12 19:44:24 2019  DEPLOYED  cert-manager-v0.5.2  v0.5.2 kube-system
nginx-ingress  1 Tue Mar 12 19:38:19 2019  DEPLOYED  nginx-ingress-1.3.1  0.22.0 kube-system

Last, confirm that your LoadBalancer IP for nginx-ingress-controller is no longer pending by using the following command.

root@kube-master:~# kubectl get svc -n kube-system 
NAME                             TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE
calico-etcd                      ClusterIP      10.96.232.136   <none>           6666/TCP                     28h
kube-dns                         ClusterIP      10.96.0.10      <none>           53/UDP,53/TCP                28h
nginx-ingress-controller         LoadBalancer   10.105.8.20     172.20.240.112   80:31151/TCP,443:32087/TCP   23h
nginx-ingress-controller-stats   ClusterIP      10.96.180.163   <none>           18080/TCP                    23h
nginx-ingress-default-backend    ClusterIP      10.99.138.158   <none>           80/TCP                       23h
tiller-deploy                    ClusterIP      10.104.47.231   <none>           44134/TCP                    27h

Testing the NGINX Ingress Controller

At this stage, you have already forwarded your domain name to the IP address where your Kubernetes cluster is running. Now, you can test your domain in your preferred browser. Note that the NGINX ingress controller has issued a fake certificate. This confirms that nginx ingress is up and running and ready to use to configure let's Encrypt issuers.

3

Getting a Staging Let's Encrypt Certificate for Your Domain Name

Now, let's get a staging Let's Encrypt certificate for your domain name. For this, first create the Ingress resource with the annotations and the required service.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress-staging
  annotations:
    kubernetes.io/ingress.class: nginx
    certmanager.k8s.io/cluster-issuer: letsencrypt-staging
    kubernetes.io/tls-acme: 'true'
  labels:
    app: 'my-nginx'
spec:
  rules:
  - host: zariga.com
    http:
      paths:
      - path: /
        backend:
          serviceName: my-nginx
          servicePort: 80
  tls:
  - secretName: tls-staging-cert
    hosts:
    - zariga.com

Next, create the ingress in the Kubernetes cluster.

root@kube-master:~# kubectl create -f nginx-ingress-staging.yaml 
ingress.extensions/nginx-ingress-staging created
root@kube-master:~# vim nginx-ingress-staging.yaml 

You can view the Certificate resource which was create automatically.

root@kube-master:~# kubectl get certificate 
NAME               AGE
tls-staging-cert   1m

After somewhere between two and ten minutes, kubectl describe certificate should show that the Certificate has been issued successfully.

root@kube-master:~# kubectl describe certificate 
Name:         tls-staging-cert
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  certmanager.k8s.io/v1alpha1
Kind:         Certificate
Metadata:
  Creation Timestamp:  2019-03-12T10:17:13Z
  Generation:          4
  Owner References:
    API Version:           extensions/v1beta1
    Block Owner Deletion:  true
    Controller:            true
    Kind:                  Ingress
    Name:                  nginx-ingress-staging
    UID:                   fe528f28-44af-11e9-b431-00163e005d19
  Resource Version:        16843
  Self Link:               /apis/certmanager.k8s.io/v1alpha1/namespaces/default/certificates/tls-staging-cert
  UID:                     014f9299-44b0-11e9-b431-00163e005d19
Spec:
  Acme:
    Config:
      Domains:
        zariga.com
      Http 01:
        Ingress:        
        Ingress Class:  nginx
  Dns Names:
    zariga.com
  Issuer Ref:
    Kind:       ClusterIssuer
    Name:       letsencrypt-staging
  Secret Name:  tls-staging-cert
Status:
  Acme:
    Order:
      URL:  https://acme-staging-v02.api.letsencrypt.org/acme/order/8535504/26384081
  Conditions:
    Last Transition Time:  2019-03-12T10:17:51Z
    Message:               Certificate issued successfully
    Reason:                CertIssued
    Status:                True
    Type:                  Ready
    Last Transition Time:  <nil>
    Message:               Order validated
    Reason:                OrderValidated
    Status:                False
    Type:                  ValidateFailed
Events:
  Type    Reason          Age   From          Message
  ----    ------          ----  ----          -------
  Normal  CreateOrder     103s  cert-manager  Created new ACME order, attempting validation...
  Normal  DomainVerified  69s   cert-manager  Domain "zariga.com" verified with "http-01" validation
  Normal  IssueCert       69s   cert-manager  Issuing certificate...
  Normal  CertObtained    68s   cert-manager  Obtained certificate from ACME server
  Normal  CertIssued      68s   cert-manager  Certificate issued successfully

The important things to note here are:

  • spec.secretName: The secret in which the certificate will be stored. Usually, this will be prefixed with -tls so it doesn't get mixed up with other secrets.
  • spec.issuerRef.name: The named we defined earlier for our ClusterIssuer.
  • spec.issuerRef.kind: This specifies that the issuer is a ClusterIssuer.
  • spec.acme.config.http01.ingress: The name of the ingress deployed with NGINX.

Now visit the domain name again, you should notice now that a stage certificate is being issued and configured to your domain name.

4

Getting a Production Let's Encrypt Certificate for Your Domain Name

Next, let's get a production Let's Encrypt certificate for your domain name. To do this, first define ingress with required annotations and service to lookup.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress-prod
  annotations:
    kubernetes.io/ingress.class: nginx
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/tls-acme: 'true'
  labels:
    app: 'my-nginx'
spec:
  rules:
  - host: zariga.com
    http:
      paths:
      - path: /
        backend:
          serviceName: my-nginx
          servicePort: 80
  tls:
  - secretName: tls-prod-cert
    hosts:
    - zariga.com 

Next, apply the ingress in the kubernetes cluster.

kubectl apply -f letsencrypt-nginx-prod.yaml

View the ingress.

root@kube-master:~# kubectl get ingress
NAME HOSTS  ADDRESS PORTS AGE
nginx-ingress-prod zariga.com 80, 443 23h

Get the certificate.

root@kube-master:~# kubectl get certificate
NAME  AGE
tls-prod-cert 23h

After somewhere between two and ten minutes, kubectl describe certificate should show Certificate issued successfully.

root@kube-master:~# kubectl describe certs 
Name:         tls-prod-cert
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  certmanager.k8s.io/v1alpha1
Kind:         Certificate
Metadata:
  Creation Timestamp:  2019-03-12T10:26:58Z
  Generation:          2
  Owner References:
    API Version:           extensions/v1beta1
    Block Owner Deletion:  true
    Controller:            true
    Kind:                  Ingress
    Name:                  nginx-ingress-prod
    UID:                   5ab11929-44b1-11e9-b431-00163e005d19
  Resource Version:        17687
  Self Link:               /apis/certmanager.k8s.io/v1alpha1/namespaces/default/certificates/tls-prod-cert
  UID:                     5dad4740-44b1-11e9-b431-00163e005d19
Spec:
  Acme:
    Config:
      Domains:
        zariga.com
      Http 01:
        Ingress:        
        Ingress Class:  nginx
  Dns Names:
    zariga.com
  Issuer Ref:
    Kind:       ClusterIssuer
    Name:       letsencrypt-prod
  Secret Name:  tls-prod-cert
Status:
  Acme:
    Order:
      URL:  https://acme-v02.api.letsencrypt.org/acme/order/53135536/352104603
  Conditions:
    Last Transition Time:  2019-03-12T10:27:00Z
    Message:               Order validated
    Reason:                OrderValidated
    Status:                False
    Type:                  ValidateFailed
    Last Transition Time:  <nil>
    Message:               Certificate issued successfully
    Reason:                CertIssued
    Status:                True
    Type:                  Ready
Events:
  Type    Reason        Age   From          Message
  ----    ------        ----  ----          -------
  Normal  CreateOrder   27s   cert-manager  Created new ACME order, attempting validation...
  Normal  IssueCert     27s   cert-manager  Issuing certificate...
  Normal  CertObtained  25s   cert-manager  Obtained certificate from ACME server
  Normal  CertIssued    25s   cert-manager  Certificate issued successfully

Visit the URL the domain name is issued with production certificate.

5

Cleanup

Finally, let's do some cleanup. First, delete the Ingress, Service and Deployment:

kubectl delete ingress,deployment my-nginx
kubectl delete service my-nginx

Use this command to uninstall cert-manager deployment:

helm del --purge cert-manager

Use this command to uninstall Helm:

helm reset

Use this command to delete the TLS certificates:

kubectl delete secret <NAME>

The views expressed herein are for reference only and don't necessarily represent the official views of Alibaba Cloud.

1 0 0
Share on

Alibaba Clouder

2,605 posts | 747 followers

You may also like

Comments

RICKY11 September 26, 2020 at 5:45 pm

that is a lot of work to simply get ssl certificates isnt it?Also to maintain the instance may cost you more then purchasing a ssl certificate from alibaba ssl itself vs lets encrpt?