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

Updated on November 21, 2023
How to Install a Wildcard Let's Encrypt SSL Certificate on Vultr Kubernetes Engine header image

Introduction

Let's Encrypt is an automated, open certificate authority that offers free TLS/SSL certificates for public benefit. The service is provided by the Internet Security Research Group (ISRG). You can generate a wildcard SSL certificate to secure unlimited subdomains that belong to the same domain name. For example, a wildcard SSL certificate generated for example.com can secure www.example.com, app.example.com, test.example.com, and so on.

This article demonstrates the steps to install the required plugins, generate a wildcard SSL certificate and secure a sample deployment using the Nginx Ingress controller and the generated certificate.

Prerequisites

Before you begin, you should:

Install the ExternalDNS Add-On

The ExternalDNS add-on allows the Kubernetes cluster to manage the Vultr DNS zones and synchronize the exposed services/ingresses with the DNS records. You need to install this add-on as Let's Encrypt requires you to prove the full ownership of the domain name. In this case, the ACME client, cert-manager verifies the ownership by adding a special DNS record in the domain name.

Create a new manifest file named 1-dns.yaml.

# nano 1-dns.yaml

Add the following contents to the file.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services","endpoints","pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: k8s.gcr.io/external-dns/external-dns:v0.12.2
        args:
        - --source=ingress # service also possible
        - --provider=vultr
        env:
        - name: VULTR_API_KEY
          value: "" # Populate with your API key.

The above manifest deploys the ExternalDNS add-on on the Kubernetes cluster. Be sure to populate the VULTR_API_KEY value with your API key. You can locate the API key by navigating to the Vultr Customer Portal > Account > API.

Apply the manifest file.

# kubectl apply -f 01-dns.yaml

Install the Nginx Ingress Controller

The nginx-ingress controller is a Kubernetes resource that provisions a load balancer and configures it to expose the ingress resources outside the cluster. It is a cluster-wise resource that you can use to expose multiple services using ingress resources.

Install the nginx-ingress controller.

# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/cloud/deploy.yaml

Verify the installation.

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

Install the cert-manager Plugin

The cert-manager plugin adds the certificates and certificate issuers as resource types in the Kubernetes cluster. It simplifies the process of obtaining, renewing, and using the certificates.

Install the cert-manager plugin.

# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml

Verify the installation.

# kubectl get pods --namespace cert-manager

Install the Vultr Webhook for the cert-manager Plugin

The Vultr Webhook allows using the ACME DNS01 solver by Vultr with the cert-manager plugin to issue the Let's Encrypt certificates. You must perform this step after installing the cert-manager plugin on the cluster.

Clone the GitHub repository.

# git clone https://github.com/vultr/cert-manager-webhook-vultr.git

Create a secret resource.

# kubectl create secret generic "vultr-credentials" --from-literal=apiKey=<VULTR API KEY> --namespace=cert-manager

The above command creates a secret resource for defining the Vultr credentials. Replace <VULTR API KEY> with your API key.

Install the webhook.

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

Create a new manifest file named 2-webhook.yaml.

$ nano 2-webhook.yaml

Add the following contents to the file.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: "" # Populate with your email address.
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod
    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

The above manifest creates the ClusterIssuer resource for issuing Let's Encrypt certificates. It also defines the necessary role bindings for the webhook to function properly. Populate the spec.acme.email field with your email address.

Apply the manifest file.

# kubectl apply -f 02-webhook.yaml

Verify the installation.

# kubectl get clusterissuer

Create a Wildcard Certificate

This section demonstrates the steps to create a Certificate resource which requests the Let's Encrypt CA to issue a wildcard SSL certificate for *.example.com and store it in a secret resource named wildcard-tls.

Create a new manifest file named 3-certificate.yaml.

# nano 3-certificate.yaml

Add the following contents to the file.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard
spec:
  dnsNames:
  - "*.example.com" # Populate with the domain name followed by an asterisk symbol.
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  secretName: wildcard-tls

The above manifest creates a Certificate resource for *.example.com that you use in the later steps to secure a sample Nginx deployment.

Apply the manifest file.

# kubectl apply -f 3-certificate.yaml

Create an Nginx Deployment

You create a sample Deployment resource in this section using the official Nginx image. You can swap this step with the deployment of your existing web application and change the name of the service in the next section.

Create a new manifest file named 4-nginx.yaml.

# nano 4-nginx.yaml

Add the following contents to the file.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Service
apiVersion: v1
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx
  ports:
    - port: 80 

The above manifest creates a Deployment resource to run a sample Nginx container and a Service resource to expose the connections inside the cluster.

Apply the manifest file.

# kubectl apply -f 4-nginx.yaml

Create an Ingress Resource

In the previous steps, you installed the nginx-ingress controller to expose Kubernetes services outside the cluster. In this section, you create an ingress resource to expose the nginx-svc service outside the cluster bound with the test.example.com subdomain and secure it with the wildcard SSL certificate.

Create a new manifest file named 5-ingress.yaml.

# nano 5-ingress.yaml

Add the following contents to the file.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    external-dns.alpha.kubernetes.io/hostname: "test.example.com" # Populate with the subdomain.
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    certmanager.k8s.io/issuer: "letsencrypt-prod"
    certmanager.k8s.io/acme-challenge-type: dns01
    certmanager.k8s.io/acme-dns01-provider: vultr
  name: nginx-ingress
spec:
  rules:
  - host: "test.example.com" # Populate with the subdomain.
    http:
      paths:
      - backend:
          service:
            name: nginx-svc
            port:
              number: 80
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - "test.example.com" # Populate with the subdomain.
    secretName: wildcard-tls

The above manifest creates an Ingress resource to expose the nginx-svc outside the cluster and secure it with the wildcard certificate stored in the wildcard-tls secret resource.

Apply the manifest file.

# kubectl apply -f 5-ingress.yaml

You can verify the deployment by opening test.example.com on your web browser a few minutes after applying the manifest file.

Conclusion

This article demonstrated the steps to install the required plugins, generate a wildcard SSL certificate and secure a sample deployment using the Nginx Ingress controller and the generated certificate. You can follow these steps to generate a wildcard SSL certificate for your domain name and secure your Kubernetes deployments.

More Information