DEV Community

Cover image for Set up nginx ingress with letsencrypt certificate on VMs or bare metal kubernetes cluster
pongsatt
pongsatt

Posted on

Set up nginx ingress with letsencrypt certificate on VMs or bare metal kubernetes cluster

This post is a guide to setup ingress with cert-manager on kubernetes cluster (VMs based) so that the application deploy on the cluster can apply for https certificate automatically.

When we use kubernetes cluster using cloud providers, they already provide ingress mechanism based on their load balancer technology. If we want this capability on VMs or bare metal based cluster, we need to set it up ourselves.

It is part of series "Setup your own kubernetes cluster on VMs".

Prerequisite:

  • A running kubernetes cluster
  • A domain name with you have administration access

Note:

For those who follow along, you need to run everything on master node

Install helm

First of all, we need helm, a cluster package manager, that will help us install ingress and cert-manager.

1. Create service account and its permission

Run command.

echo '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' | kubectl apply -f -

2. Install helm

Run below command to install helm from official bash script.

Note: You will need to enter root password.

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get | bash

3. Initialize helm

We need to initialize helm to install server application on the cluster.

helm init --service-account tiller

4. Check installation

Run helm version.

If things are ok, you should see.

Install Ingress

We will install nginx ingress using host network on all worker nodes (DaemonSet).

See this document to understand more about nginx ingress Bare-metal considerations

1. Install Ingress pod

Install using helm command below.

helm install --name nginx-ingress --namespace nginx-ingress stable/nginx-ingress --set controller.hostNetwork=true --set controller.kind=DaemonSet

Open one of your worker node IP address in the browser. If ingress installation successful, you will see.

2. Configure domain name

Configure your dns to point your test domain name to one of your worker node.

In my example, I point my route53 test dns record to my public IP.

I also need to configure my router to forword port 80 and 443 to one of my worker node. Let's say 192.168.1.110.

3. Deploy test application

Run this command to deploy hello world application to the cluster.

kubectl run hello-world --image=gcr.io/google-samples/node-hello:1.0  --port=8080
kubectl expose deployment hello-world --type=NodePort --name=example-service

Try access this application using node port http://<master or worker ip>:<node port>. You should see.

4. Deploy test ingress

Run command below to install ingress for test application.

Note:

Please replace "testingress.yourdomain.com" with your real domain.

echo 'apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  tls:
  - hosts:
    - testingress.yourdomain.com
    secretName: testingress-tls
  rules:
  - host: testingress.yourdomain.com
    http:
      paths:
      - path: /
        backend:
          # The name of your service
          serviceName: example-service
          servicePort: 8080' | kubectl apply -f -

If everything is ok, open url http://testingress.yourdomain.com and you should see.

Install cert-manager

We will install cert-manager to the cluster then create cluster issuer for letsencrypt. The cluster issuer will automatically detect our ingress with tls configure then try to acquire certificate and store keys in secret name "testingress-tls".

1. Install cert-manager

Run this command using helm.

helm install --name cert-manager --namespace kube-system stable/cert-manager

2. Create cluster issuer (use http01 protocol)

Run this command to create cluster issuer.

Note:

Please replace "yourreal@email.com" to your real email

echo 'apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
  namespace: default
spec:
  acme:
    email: yourreal@email.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}' | kubectl apply -f -

Run below to update cert-manager to use cluster issuer created above.

helm upgrade cert-manager stable/cert-manager --namespace kube-system --set ingressShim.defaultIssuerName=letsencrypt-prod --set ingressShim.defaultIssuerKind=ClusterIssuer

Wait for sometimes maybe an hour. Then run kubectl get secret. If you see secret name "testingress-tls", this mean it works. You should be able to access https://testingress.yourdomain.com successfully.

3. Create cluster issuer (use dns01 protocol)

In case that step 2 with http02 protocol does not work, we will need a more advance protocol "dns01".

"dns01" protocol support many cloud providers, this example will be for route53.

3.1 Import IAM policy

Import this to your IAM user that you have access key.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "route53:GetChange",
            "Resource": "arn:aws:route53:::change/*"
        },
        {
            "Effect": "Allow",
            "Action": "route53:ChangeResourceRecordSets",
            "Resource": "arn:aws:route53:::hostedzone/*"
        },
        {
            "Effect": "Allow",
            "Action": "route53:ListHostedZonesByName",
            "Resource": "*"
        }
    ]
}

3.2 Create AWS secret

Create kubernetes secret using below.

Note:

Replace with your real secret key

kubectl create secret -n kube-system generic aws-secret --from-literal=secret-key=<IAM User Secret Key>

3.3 Create Cluster Issuer (DNS01)

Note:

Replace yourreal@email.com with your real email
Replace and and with your real data

echo 'apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
  namespace: default
spec:
  acme:
    email: yourreal@email.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod
    dns01:
      providers:
      - name: aws-route53
        route53:
          hostedZoneID: <Route53 hosted zone ID>
          region: <Route53 region>
          accessKeyID: <IAM User Access key>
          secretAccessKeySecretRef:
            name: aws-secret
            key: secret-key' | kubectl apply -f -

3.4 Update test ingress to use DNS01

Note:

Replace yourdomain.com to your real domain

echo 'apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    certmanager.k8s.io/acme-challenge-type: "dns01"
    certmanager.k8s.io/acme-dns01-provider: "aws-route53"
spec:
  tls:
  - hosts:
    - testingress.yourdomain.com
    secretName: testingress-tls
  rules:
  - host: testingress.yourdomain.com
    http:
      paths:
      - path: /
        backend:
          # The name of your service
          serviceName: example-service
          servicePort: 8080' | kubectl apply -f -

Wait until kubectl get secret return secret name "testingress-tls", this mean it works. You should be able to access https://testingress.yourdomain.com successfully.

Summary

At this point, we have a kubernete cluster that we can deploy application that support https. Next, we will set up a static front-end application in the kubernetes cluster.

Top comments (1)

Collapse
 
acepsaepudin profile image
Acep Saepudin

thanks for writing this post! this is help me a lot for almost 3 days in every night!