How to Install a Wildcard Let's Encrypt SSL Certificate on Vultr Kubernetes Engine

Author: Quan Hua

Last Updated: Tue, Nov 15, 2022
Kubernetes Security

Introduction

This article explains how to install a wildcard Let's Encrypt SSL Certificate on Vultr Kubernetes Engine.

A wildcard SSL Certificate is a single SSL Certificate that can secure unlimited subdomains. Let's Encrypt is a free certificate authority that offers free SSL Certificates.

The example application is an Nginx web server that serves HTTP traffic on port 80 through a Kubernetes service. An Nginx Ingress Controller handles the HTTPS traffic with a wildcard Let's Encrypt SSL certificate through a Vultr Load Balancer.

Prerequisites

Before you begin, you should:

  • Deploy a Vultr Kubernetes Cluster.

  • Configure kubectl, helm, and git in your machine.

  • Have a domain name.

Install Nginx Ingress Controller

  1. Install NGINX Ingress Controller

    helm upgrade --install ingress-nginx ingress-nginx --repo https://kubernetes.github.io/ingress-nginx --namespace ingress-nginx --create-namespace
    
  2. Go to your Load Balancers dashboard and get the IP address of the newly created Load Balancer. This is the Load Balancer created for the NGINX Ingress Controller.

  3. (Optional) Get the IP address of the Load Balancer using the following command. The IP address is in the External IP column.

    kubectl get services/ingress-nginx-controller -n ingress-nginx
    

Change Domain Nameservers to Vultr DNS

  1. Visit https://www.vultr.com/docs/vultr-dns-servers/ to get the latest Vultr nameservers, such as ns1.vultr.com and ns2.vultr.com.

  2. Go to the domain provider and change your domain's nameserver to Vultr nameservers.

  3. Go to https://my.vultr.com/dns/add/. Enter your domain in the Domain field and the IP address of the load balancer in the New IP Address field.

Get the Personal Access Token API

  1. Visit https://my.vultr.com/settings/#settingsapi

  2. Click Enable API.

  3. Copy the API Key. You need this API key in the next step.

  4. Click Allow All IPv4 to allow all IP addresses to access the API. To improve security, you can add the IP address of each node in your Kubernetes cluster.

Install cert-manager and cert-manager-webhook-vultr

This section shows how to install the Cert Manager to handle SSL Certificates with Let's Encrypt.

  1. Install cert-manager to manage SSL certificates

    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.yaml
    
  2. Create a secret named vultr-credentials using the following command. Replace <YOUR_API_KEY> with your API key from the previous section.

    kubectl create secret generic "vultr-credentials" --from-literal=apiKey=<YOUR_API_KEY> --namespace=cert-manager
    
  3. Download cert-manager-webhook-vultr from GitHub

    git clone https://github.com/vultr/cert-manager-webhook-vultr
    
    cd cert-manager-webhook-vultr
    
  4. Install the Vultr Cert Manager Webhook

    helm install --namespace cert-manager cert-manager-webhook-vultr ./deploy/cert-manager-webhook-vultr
    

Create a Let's Encrypt ClusterIssuer

This example uses the Let's Encrypt production environment. For the staging environment, replace https://acme-v02.api.letsencrypt.org/directory with https://acme-staging-v02.api.letsencrypt.org/directory

  1. Create a manifest file named issuer.yaml with the following content. Replace <YOUR_EMAIL_ADDRESS> with your email address

    apiVersion: cert-manager.io/v1
    
    kind: ClusterIssuer
    
    metadata:
    
      name: letsencrypt-issuer
    
    spec:
    
      acme:
    
        # You must replace this email address with your own.
    
        # Let's Encrypt will use this to contact you about expiring
    
        # certificates, and issues related to your account.
    
        email: <YOUR_EMAIL_ADDRESS>
    
        server: https://acme-v02.api.letsencrypt.org/directory
    
        privateKeySecretRef:
    
          # Secret resource that will be used to store the account's private key.
    
          name: letsencrypt-issuer
    
        solvers:
    
          - dns01:
    
              webhook:
    
                groupName: acme.vultr.com
    
                solverName: vultr
    
                config:
    
                  apiKeySecretRef:
    
                    key: apiKey
    
                    name: vultr-credentials
    
    ---
    
    apiVersion: rbac.authorization.k8s.io/v1
    
    kind: Role
    
    metadata:
    
      name: cert-manager-webhook-vultr:secret-reader
    
      namespace: cert-manager
    
    rules:
    
      - apiGroups: [""]
    
        resources: ["secrets"]
    
        resourceNames: ["vultr-credentials"]
    
        verbs: ["get", "watch"]
    
    ---
    
    apiVersion: rbac.authorization.k8s.io/v1
    
    kind: RoleBinding
    
    metadata:
    
      name: cert-manager-webhook-vultr:secret-reader
    
      namespace: cert-manager
    
    roleRef:
    
      apiGroup: rbac.authorization.k8s.io
    
      kind: Role
    
      name: cert-manager-webhook-vultr:secret-reader
    
    subjects:
    
      - apiGroup: ""
    
        kind: ServiceAccount
    
        name: cert-manager-webhook-vultr
    
  2. Deploy the issuer.yaml using Kubectl

    kubectl apply -f issuer.yaml
    

Create a Wildcard Certificate

This section creates a free wildcard Let's Encrypt SSL certificate for *.example.com. This certificate can secure any subdomain of example.com. A secret named wildcard-example-com-tls stores the wildcard certificate.

  1. Create a manifest file named certificate.yaml with the following content. Replace example.com with your domain.

    apiVersion: cert-manager.io/v1
    
    kind: Certificate
    
    metadata:
    
      name: wildcard-example-com-tls
    
      namespace: default
    
    spec:
    
      commonName: "*.example.com"
    
      dnsNames:
    
        - "*.example.com"
    
      issuerRef:
    
        name: letsencrypt-issuer
    
        kind: ClusterIssuer
    
      secretName: wildcard-example-com-tls
    
  2. Deploy the certificate.yaml using Kubectl

    kubectl apply -f certificate.yaml
    
  3. Check the status

    kubectl describe certificate wildcard-example-com-tls
    
  4. Wait for the challenges

    $ kubectl get challenges -w
    
    NAME                                                    STATE     DOMAIN            AGE
    
    wildcard-example-com-tls-4rwk7-1141133851-2526175681   pending   YOUR_DOMAIN   103s
    
    wildcard-example-com-tls-4rwk7-1141133851-2526175681   valid     YOUR_DOMAIN   2m33s
    
  5. (Optional) Describe the challenge to find the problem. Replace the challenge name with the value from previous step.

    kubectl describe challenge wildcard-example-com-tls-4rwk7-1141133851-2526175681
    

Deploy an Nginx Web Server

This section deploys an Nginx web server and exposes it on port 80 through a Kubernetes Service, nginx-service.

  1. Create a file named nginx.yaml with the following content

    apiVersion: apps/v1
    
    kind: Deployment
    
    metadata:
    
      name: nginx-deployment
    
    spec:
    
      selector:
    
        matchLabels:
    
          name: nginx
    
      template:
    
        metadata:
    
          labels:
    
            name: nginx
    
        spec:
    
          containers:
    
            - name: nginx
    
              image: nginx
    
              ports:
    
                - containerPort: 80
    
    ---
    
    apiVersion: v1
    
    kind: Service
    
    metadata:
    
      name: nginx-service
    
    spec:
    
      ports:
    
        - name: http
    
          port: 80
    
      selector:
    
        name: nginx
    
  2. Deploy the nginx.yaml using Kubectl

    kubectl apply -f nginx.yaml
    

Deploy an Ingress for the Nginx server

This section deploys an Ingress that exposes the above Kubernetes Service, nginx-service, through a domain nginx.example.com. You can use any subdomain of your domain in this section. The certificate for this subdomain is from the secret wildcard-example-com-tls in the previous section.

  1. Create a file named ingress.yaml with the following content. Replace nginx.example.com with your domain.

    apiVersion: networking.k8s.io/v1
    
    kind: Ingress
    
    metadata:
    
      annotations:
    
        kubernetes.io/ingress.class: nginx
    
        cert-manager.io/cluster-issuer: letsencrypt-issuer
    
      name: nginx-example-com
    
      namespace: default
    
    spec:
    
      tls:
    
        - hosts:
    
            - nginx.example.com
    
          secretName: wildcard-example-com-tls
    
      rules:
    
        - host: nginx.example.com
    
          http:
    
            paths:
    
              - path: /
    
                pathType: Prefix
    
                backend:
    
                  service:
    
                    name: nginx-service
    
                    port:
    
                      number: 80
    
  2. Deploy the ingress.yaml using Kubectl

    kubectl apply -f ingress.yaml
    
  3. Navigate to https://<YOUR_DOMAIN> to access your Nginx server.

  4. (Optional) View the logs.

    kubectl logs deploy/ingress-nginx-controller --namespace ingress-nginx
    

Want to contribute?

You could earn up to $600 by adding new articles.