Spread the word

Step to set Let’s Encrypt on Alibaba Cloud Kubernetes

August 26, 2020 0 comments

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.

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 ashokkuikel.com, that is pointing to a Kubernetes Service Type load balancer.
  • An Alibaba Cloud Kubernetes cluster. Note that the following setup, pictured below, is created in Alibaba Cloud and will be used for this demo.

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: 'ashokkuikeltongy@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: 'ashokkuikeltongy@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.

 

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: ashokkuikel.com
http:
paths:
- path: /
backend:
serviceName: my-nginx
servicePort: 80
tls:
- secretName: tls-staging-cert
hosts:
- ashokkuikel.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:
ashokkuikel.com
Http 01:
Ingress:
Ingress Class: nginx
Dns Names:
ashokkuikel.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 "ashokkuikel.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.

 

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: ashokkuikel.com
http:
paths:
- path: /
backend:
serviceName: my-nginx
servicePort: 80
tls:
- secretName: tls-prod-cert
hosts:
- ashokkuikel.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 ashokkuikel.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:
ashokkuikel.com
Http 01:
Ingress:
Ingress Class: nginx
Dns Names:
ashokkuikel.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.

 

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>

 

Source

Ashok kuikel

Hi, I am Ashok Kuikel, WordPress Developer for WordPress Community. While Cloud Computing Associate and Alibaba MVP and ACA for Cloud Professional. You can follow me on Social Media, GitHub, and via my Blog Channels.

0 Comments

    Leave a Reply

    Your email address will not be published. Required fields are marked *