Knowledgebase

How to Secure a VKE Cluster Using Traefik, Cert-Manager and Let's Encrypt Print

  • 0

Introduction

Traefik is an open-source reverse proxy and load balancer known for its user-friendly approach to deploying microservices. It seamlessly integrates with existing infrastructure components such as cloud-native, and Kubernetes environments to secure underlying applications.

Traefik offers a range of features that enhance its capabilities. These include load balancing, API gateway, orchestrator ingress, east-west service communication, among others. To add certificates and certificate issuers in a Kubernetes clusters, Traefik integrates with cert-manager to provide a streamlined solution.

Cert-manager can issue certificates from different sources such as Let's Encrypt, HashiCorp Vault, Venafi, or private PKI. It also ensures certificates are valid and up to date by actively attempting to renew them before they expire.

In this article, you will secure a web application in a RCS Kubernetes Engine (VKE) cluster using Traefik, cert-manager, and Let's Encrypt. You will configure automatic HTTPS redirection to enhance your application security and securely serve all external requests.

Prerequisites

Before you begin, make sure you:

Install Cert-manager

  1. To install the latest cert-manager version to your cluster. Run the following command.

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

    In the above command, version v1.12.2 is used. To find the latest Cert-manager version, visit the cert-manager GitHub repository, and keep note of the latest version number to use in your cluster.

  2. Verify that all cert-manager components are installed and running.

    $ kubectl get pods --namespace cert-manager
    

    Your output should look like the one below:

    NAME                                       READY   STATUS    RESTARTS   AGE
    
    cert-manager-66d9545484-2tbv7              1/1     Running   0          28s
    
    cert-manager-cainjector-7d8b6bd6fb-w9p8v   1/1     Running   0          28s
    
    cert-manager-webhook-669b96dcfd-gffrg      1/1     Running   0          28s
    

    As displayed in the above output, the cert-manager, cert-manager-cainjector, and cert-manager-webhook pods are running, and ready to use.

Set Up the Let's Encrypt Issuer

  1. Using a text editor such as Nano, create a new file named cluster-issuer.yaml.

    $ nano cluster-issuer.yaml
    
  2. Add the following contents to the file. Replace <hello@example.com> with your actual email address.

    apiVersion: cert-manager.io/v1
    
    kind: ClusterIssuer
    
    metadata:
    
    name: letsencrypt-prod
    
    spec:
    
    acme:
    
      email: hello@example.com
    
      server: https://acme-v02.api.letsencrypt.org/directory
    
      privateKeySecretRef:
    
        name: letsencrypt-prod-key
    
      solvers:
    
       - http01:
    
           ingress:
    
             class: traefik
    

    Save and close the file.

    Below is what the above configuration declarations represent:

    • acme: Specifies the ACME configuration for Let's Encrypt.

    • email: Your email address to associate with a Let's Encrypt account.

    • server: The Let's Encrypt server URL.

    • privateKeySecretRef: Specifies secret that holds the Let's Encrypt account private key.

    • solvers: Sets the method for solving the ACME challenge.

    • http01: Sets HTTP-01 as the challenge solver to verify domain ownership.

    • ingress: Sets the ingress class to use for solving the challenge.

  3. Apply the ClusterIssuer.

    $ kubectl apply -f cluster-issuer.yaml
    
  4. Verify that the ClusterIssuer is created.

    $ kubectl get clusterissuer
    

    Output:

    NAME               READY   AGE
    
    letsencrypt-prod   True    2m44s
    

Create the Traefik Namespace

In this section, create the Traefik namespace to deploy the Traefik proxy. This allows you to separate Traefik resources from the default namespace for easy management of resources in your cluster as described in the steps below.

  1. Create a new file named traefik-namespace.yaml.

    $ nano traefik-namespace.yaml
    
  2. Add the following contents to the file.

    apiVersion: v1
    
    kind: Namespace
    
    metadata:
    
      name: traefik-namespace
    

    Save and close the file.

  3. Apply the namespace configuration.

    $ kubectl apply -f traefik-namespace.yaml
    

    The above command creates the traefik-namespace in your cluster.

Install and Configure Traefik

  1. Add the Traefik Helm repository.

    $ helm repo add traefik https://helm.traefik.io/traefik
    

    Output:

    "traefik" has been added to your repositories
    
  2. Update your Helm chart repositories.

    $ helm repo update
    
  3. Using helm, install Traefik.

    $ helm install --namespace=traefik-namespace traefik traefik/traefik
    

    The above command installs Traefik to the traefik-namespace you created earlier in your cluster.

    Output:

    STATUS: deployed
    
    REVISION: 1
    
    TEST SUITE: None
    
    NOTES:
    
    Traefik Proxy v2.10.1 has been deployed successfully on traefik-namespace namespace !
    
  4. Verify that Traefik is installed, and all resources are available in the namespace.

    $ kubectl get -n traefik-namespace all
    

    Your output should look like the one below:

    NAME                          READY   STATUS    RESTARTS   AGE
    
    pod/traefik-dfb6cf6bb-z9bl7   1/1     Running   0          20s
    
    
    
    NAME              TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
    
    service/traefik   LoadBalancer   10.96.37.224   <pending>     80:31574/TCP,443:31926/TCP   20s
    
    
    
    NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
    
    deployment.apps/traefik   1/1     1            1           20s
    
    
    
    NAME                                DESIRED   CURRENT   READY   AGE
    
    replicaset.apps/traefik-dfb6cf6bb   1         1         1       20s
    

Set up your Domain Name and Verify the Traefik Installation

  1. Verify the Traefik service external IP Address.

    $ kubectl get svc -n traefik-namespace traefik
    

    Your output should look like the one below:

    NAME      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    
    traefik   LoadBalancer   10.108.209.185   192.168.0.101    80:30046/TCP,443:30279/TCP   78s
    

    Copy theservice/traefik External IP. In the above output 192.168.0.101. If the IP is in <pending> state, wait a few minutes, and run the command again to view the external IP again.

  2. Visit your Domain DNS registrar. For example, RCS DNS.

  3. Set up a domain A record pointing to the Traefik LoadBalancer external IP Address.

Deploy a Sample Application

In this section, deploy the sample application Nginx to test your Traefik configuration and the cert-manager certificate issuance process as described below.

  1. To organize your cluster, create a new namespace YAML file for the application.

    $ nano example-app-namespace.yaml
    
  2. Add the following contents to the file.

    apiVersion: v1
    
    kind: Namespace
    
    metadata:
    
      name: example-app-namespace
    

    Save and close the file.

  3. Apply the namespace configuration.

    $ kubectl apply -f example-app-namespace.yaml
    
  4. Create a new deployment file named example-app-deployment.yaml.

    $ nano example-app-deployment.yaml
    
  5. Add the following contents to the file.

    apiVersion: apps/v1
    
    kind: Deployment
    
    metadata:
    
     namespace: example-app-namespace
    
     name: example-app-deployment
    
    spec:
    
     replicas: 3
    
     selector:
    
       matchLabels:
    
         app: example-app
    
      template:
    
       metadata:
    
         labels:
    
           app: example-app
    
       spec:
    
         containers:
    
           - name: web-app
    
             image: nginx
    
             ports:
    
               - containerPort: 80
    

    Save and close the file.

    Below is what the deployment configurations represent:

    • replicas: The number of replicas (pods) to be created for the Deployment.

    • selector: The labels used for selecting the pods controlled by the Deployment.

    • template: Specifies the template for creating the pods.

    • metadata: Specifies the labels for the pods.

    • spec: Specification for the pods.

    • containers: Specifies the containers within the pods.

    • name: Specifies the container name.

    • image: Container image to be used in the pods.

    • ports: Ports opened in the container.

  6. Apply the deployment.

    $ kubectl apply -f example-app-deployment.yaml
    

    The above command creates the example application deployment and the associated pods in the example-app-namespace.

  7. Verify that the example application pods are running.

    $ kubectl get -n example-app-namespace pods
    

    Output:

    NAME                                      READY   STATUS    RESTARTS   AGE
    
    example-app-deployment-5f8bc66b96-bzzrp   1/1     Running   0          5m11s
    
    example-app-deployment-5f8bc66b96-lq96g   1/1     Running   0          5m11s
    
    example-app-deployment-5f8bc66b96-n5cdf   1/1     Running   0          5m11s
    

Configure HTTPS using Traefik

  1. Create a new service file named example-app-service.yaml.

    $ nano example-app-service.yaml
    
  2. Add the following contents to the file.

    apiVersion: v1
    
    kind: Service
    
    metadata:
    
     namespace: example-app-namespace
    
     name: example-app-service
    
    spec:
    
     selector:
    
       app: example-app
    
     ports:
    
       - protocol: TCP
    
         port: 80
    
         targetPort: 80
    

    Save and close the file.

    Below is what the service declarations represent:

    • spec: Describes the specification for the Service.

    • selector: Specifies a set of labels used for selecting the pods that the service should route traffic to.

    • app: Specifies a label named app with the value example-app.

    • ports: Defines the ports exposed by the Service.

    • protocol: Specifies the protocol to use for the ports.

    • port: The port number the Service should listen on.

    • targetPort: Specifies the port number to which traffic should be forwarded within the pods.

  3. Apply the service configuration.

    $ kubectl apply -f example-app-service.yaml
    
  4. Verify that the service is created.

    $ kubectl get services -n example-app-namespace
    

    Output:

    NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
    
    example-app-service   ClusterIP   10.97.221.68   <none>        80/TCP    81s
    
  5. Create a new Ingress file named example-app-ingress.yaml.

    $ nano example-app-ingress.yaml
    
  6. Add the following contents to the file. Replace example.com with your actual domain.

    apiVersion: networking.k8s.io/v1
    
    kind: Ingress
    
    metadata:
    
     name: web-app-ingress
    
     namespace: example-app-namespace
    
     annotations:
    
       traefik.ingress.kubernetes.io/router.entrypoints: websecure
    
       traefik.ingress.kubernetes.io/router.tls: "true"
    
       cert-manager.io/cluster-issuer: letsencrypt-prod
    
    spec:
    
     rules:
    
       - host: example.com
    
         http:
    
           paths:
    
             - path: /
    
               pathType: Prefix
    
               backend:
    
                 service:
    
                   name: example-app-service
    
                   port:
    
                      number: 80
    
    tls:
    
      - secretName: web-app-cert
    
        hosts:
    
          - example.com
    

    Save and close the file.

    Below is what the Ingress declarations represent.

    • annotations: Specifies the annotations for the Ingress, including Traefik-specific and cert-manager-specific annotations.

    • traefik.ingress.kubernetes.io/router.entrypoints: websecure: Configures the Traefik ingress controller to route incoming traffic to the websecure entrypoint. It specifies the entrypoint to use for handling HTTPS traffic.

    • traefik.ingress.kubernetes.io/router.tls: "true": Specifies that the router should handle HTTPS traffic. It enables TLS termination and ensures secure communication between clients and the application.

    • cert-manager.io/cluster-issuer: letsencrypt-prod: Specifies the cert-manager cluster issuer to use for obtaining SSL/TLS certificates. It associates the Ingress resource with the letsencrypt-prod cluster issuer you created earlier.

    • spec: Specifies the specification for the Ingress.

      • rules: Specifies the rules for routing the traffic.

        • host: Specifies a domain/host to match the rule.

        • http: Specifies the HTTP routing for the host.

          • paths: Specifies the paths to match within the host.

            • path: Specifies the path to match.

            • backend: Specifies the backend service to route the traffic to.

              • service: Specifies the name of the service to forward the traffic to.

              • port: Specifies the port number of the service to use.

    • tls: Specifies the TLS configuration for the Ingress resource.

    • secretName: Specifies the name of the secret that stores the TLS certificate and private key. This secret should be created and managed by cert-manager.

    • hosts: Specifies the hostnames associated with the TLS certificate. Replace <PUT YOUR DOMAIN NAME HERE> with your actual domain name.

  7. Apply the ingress configuration.

    $ kubectl apply -f example-app-ingress.yaml
    
  8. Verify that the Ingress resource is created.

    $ kubectl get ingress -n example-app-namespace
    

    Output:

    NAME                        CLASS     HOSTS                ADDRESS   PORTS     AGE
    
    web-app-ingress             traefik   example.com                    80, 443    9s
    
  9. Verify that a Let's Encrypt SSL certificate is registered for your domain.

    $ kubectl get -n example-app-namespace certificates
    

    Output:

    NAME           READY   SECRET         AGE
    
    web-app-cert   True    web-app-cert   41s
    

    If the READY column returns True, your SSL certificate is successfully issued and ready to use.

  10. Verify that the certificate auto-renews on expiry.

    $ kubectl describe -n example-app-namespace certificate web-app-cert
    

    The about command prints information about the certificate. Find the Renewal Time setting, and make sure its value is a date as below:

    Renewal Time:            2023-09-17T15:23:45Z
    
  11. In a web browser such as Chrome, visit you can securely access your application.

    https://example.com
    

    When successful, the default Nginx welcome page displays in your browser.

Redirect HTTP Requests to HTTPS

To redirect all HTTP requests to HTTPS, reconfigure Traefik using the following command.

$ helm upgrade --namespace=traefik-namespace traefik traefik/traefik --set 'ports.web.redirectTo=websecure'

In the above command:

  • helm upgrade: Upgrades the Traefik Helm release in the specified namespace traefik-namespace, using the traefik/traefik repository chart.

  • --set 'ports.web.redirectTo=websecure': Sets the redirectTo configuration of the Traefik deployment. This enables automatic HTTP to HTTPS redirection.

Test

  1. In your web browser, visit your configured domain name using HTTP.

    http://example.com
    

    Verify that your request auto-redirects to HTTPS to access the application.

  2. Alternatively, in your terminal session, use the curl utility to verify that the HTTPS redirection works correctly.

    $ curl http://example.com
    

    Output:

    Moved Permanently
    

When the tests are successful, Traefik is actively redirecting all HTTP traffic to HTTPS, and correctly serving user requests to configured services in your cluster.

Troubleshooting

To manage Traefik and your cluster resources, below are troubleshooting tips to fix common problems.

  • Unable to get Let's Encrypt Certificate: If your certificate column returns False, verify that your domain is correctly pointed to your Traefik LoadBalancer external IP Address. Additionally, to investigate further causes, view the cert-manager logs using the command below.

    $ kubectl logs deployment/cert-manager  -n cert-manager --tail=15 -f
    
  • Check Traefik logs: If you're experiencing issues with Traefik, check the logs for any error messages or warnings using the following command.

    $ kubectl logs -n <namespace> <traefik-pod>
    
  • Verify DNS configuration: Verify that your domain name is correctly pointed to the External IP address of your Traefik load balancer. Wrong DNS configurations prevent Traefik from handling incoming requests correctly.

  • Verify ingress configuration: In case Traefik does not route external traffic correctly, check your Ingress resource configuration and verify that the necessary annotations for Traefik and cert-manager are included in your YAML file.

    $ kubectl get ingress
    
  • Inspect Traefik resources: Occasionally, inspect the status of Traefik resources such as pods, services, and ingresses to ensure that they are running correctly.

    $ kubectl get pods -n traefik-namespace
    

Conclusion

In this article, you have secured a RCS Kubernetes Engine (VKE) cluster web application using Traefik, cert-manager, and Let's Encrypt. You enabled automatic HTTPS redirection to serve all client requests using SSL. For more information and configuration options, visit the following resources.


Was this answer helpful?
Back

Powered by WHMCompleteSolution