Configure mutual TLS authentication for applications running on Amazon EKS - AWS Prescriptive Guidance

Configure mutual TLS authentication for applications running on Amazon EKS

Created by Mahendra Siddappa (AWS)

Environment: PoC or pilot

Technologies: DevOps; Security, identity, compliance

AWS services: Amazon EKS; Amazon Route 53

Summary

Certificate-based mutual Transport Layer Security (TLS) is an optional TLS component that provides two-way peer authentication between servers and clients. With mutual TLS, clients must provide an X.509 certificate during the session negotiation process. The server uses this certificate to identify and authenticate the client.

Mutual TLS is a common requirement for Internet of Things (IoT) applications and can be used for business-to-business applications or standards such as Open Banking.

This pattern describes how to configure mutual TLS for applications running on an Amazon Elastic Kubernetes Service (Amazon EKS) cluster by using an NGINX ingress controller. You can enable built-in mutual TLS features for the NGINX ingress controller by annotating the ingress resource. For more information about mutual TLS annotations on NGINX controllers, see Client certificate authentication in the Kubernetes documentation.

Important: This pattern uses self-signed certificates. We recommend that you use this pattern only with test clusters, and not in production environments. If you want to use this pattern in a production environment, you can use AWS Private Certificate Authority (AWS Private CA) or your existing public key infrastructure (PKI) standard to issue private certificates.

Prerequisites and limitations

Prerequisites 

  • An active Amazon Web Services (AWS) account.

  • An existing Amazon EKS cluster.

  • AWS Command Line Interface (AWS CLI) version 1.7 or later, installed and configured on macOS, Linux, or Windows.

  • The kubectl command line utility, installed and configured to access the Amazon EKS cluster. For more information about this, see Installing kubectl in the Amazon EKS documentation.

  • An existing Domain Name System (DNS) name to test the application.

Limitations 

  • This pattern uses self-signed certificates. We recommend that you use this pattern only with test clusters, and not in production environments.

Architecture

Configuring mutual TLS authentication for applications running on Amazon EKS

Technology stack

  • Amazon EKS

  • Amazon Route 53

  • Kubectl

Tools

Epics

TaskDescriptionSkills required

Generate the CA key and certificate.

Generate the certificate authority (CA) key and certificate by running the following command.

openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=Test Cert Authority'
DevOps engineer

Generate the server key and certificate, and sign with the CA certificate.

Generate the server key and certificate, and sign with the CA certificate by running the following command.

openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN= <your_domain_name> ' && openssl x509 -req -sha256 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

Important: Make sure sure that you replace <your_domain_name> with your existing domain name.

DevOps engineer

Generate the client key and certificate, and sign with the CA certificate.

Generate the client key and certificate, and sign with the CA certificate by running the following command.

openssl req -new -newkey rsa:4096 -keyout client.key -out client.csr -nodes -subj '/CN=Test' && openssl x509 -req -sha256 -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt
DevOps engineer
TaskDescriptionSkills required

Deploy the NGINX ingress controller in your Amazon EKS cluster.

Deploy the NGINX ingress controller by using the following command.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.7.0/deploy/static/provider/aws/deploy.yaml
DevOps engineer

Verify that the NGINX ingress controller service is running.

Verify that the NGINX ingress controller service is running by using the following command.

kubectl get svc -n ingress-nginx

Important: Make sure that the field of service address contains the Network Load Balancer’s domain name.

DevOps engineer
TaskDescriptionSkills required

Create a namespace in the Amazon EKS cluster.

Create a namespace called mtls in your Amazon EKS cluster by running the following command.

kubectl create ns mtls

This deploys the sample application to test mutual TLS.

DevOps engineer
TaskDescriptionSkills required

Create the Kubernetes deployment and service in the mtls namespace.

Create a file named mtls.yaml. Paste the following code into the file.

kind: Deployment apiVersion: apps/v1 metadata: name: mtls-app labels: app: mtls spec: replicas: 1 selector: matchLabels: app: mtls template: metadata: labels: app: mtls spec: containers: - name: mtls-app image: hashicorp/http-echo args: - "-text=mTLS is working" --- kind: Service apiVersion: v1 metadata: name: mtls-service spec: selector: app: mtls ports: - port: 5678 # Default port for image

Create the Kubernetes deployment and service in the mtls namespace by running the following command.

kubectl create -f mtls.yaml -n mtls
DevOps engineer

Verify that the Kubernetes deployment is created.

Run the following command to verify that the deployment is created and has one pod in available status.

kubectl get deploy -n mtls
DevOps engineer

Verify that the Kubernetes service is created.

Verify that the Kubernetes service is created by running the following command.

kubectl get service -n mtls
DevOps engineer
TaskDescriptionSkills required

Create a secret for the ingress resource.

Run the folllowing command to create a secret for the NGINX ingress controller by using the certificates that you created earlier.

kubectl create secret generic mtls-certs --from-file=tls.crt=server.crt --from-file=tls.key=server.key --from-file=ca.crt=ca.crt -n mtls

Your secret has a server certificate for the client to identify the server and a CA certificate for the server to verify the client certificates.

DevOps engineer
TaskDescriptionSkills required

Create the ingress resource in the mtls namespace.

Create a file named ingress.yaml. Paste the following code into the file (replace <your_domain_name> with your existing domain name).

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" nginx.ingress.kubernetes.io/auth-tls-secret: mtls/mtls-certs name: mtls-ingress spec: ingressClassName: nginx rules: - host: "*.<your_domain_name>" http: paths: - path: / pathType: Prefix backend: service: name: mtls-service port: number: 5678 tls: - hosts: - "*.<your_domain_name>" secretName: mtls-certs

Create the ingress resource in the mtls namespace  by running the following command.

kubectl create -f ingress.yaml -n mtls

This means that the NGINX ingress controller can route traffic to your sample application.

DevOps engineer

Verify that the ingress resource is created.

Verify that the ingress resource is created by running the following command.

kubectl get ing -n mtls

Important: Make sure that the address of the ingress resource shows the load balancer created for the NGINX ingress controller.

DevOps engineer
TaskDescriptionSkills required

Create CNAME record that points to the load balancer for the NGINX ingress controller.

Sign in to the AWS Management Console, open the Amazon Route 53 console, and create a Canonical Name (CNAME) record that points mtls.<your_domain_name> to the load balancer for the NGINX ingress controller.

For more information, see Creating records by using the Route 53 console in the Route 53 documentation.

DevOps engineer
TaskDescriptionSkills required

Test mutual TLS setup without certificates.

Run the following command.

curl -k https://mtls.<your_domain_name>

You should receive the "400 No required SSL certificate was sent" error response.

DevOps engineer

Test mutual TLS setup with certificates.

Run the following command.

curl -k https://mtls.<your_domain_name> --cert client.crt --key client.key

You should receive the "mTLS is working" response.

DevOps engineer

Related resources