Kubernetes App using mTLS Encryption

To implement mutual TLS (mTLS) encryption in a Kubernetes application using Python’s FastAPI without performing TLS termination at the Ingress Controller, you’ll need to configure both the FastAPI server and clients to handle mutual authentication. This involves setting up the server to require a client certificate and the client to present a certificate that the server trusts.

Overview of mTLS Implementation

  1. Generate TLS Certificates: Create a Certificate Authority (CA), server certificate, and client certificates.
  2. Configure FastAPI with mTLS: Set up the FastAPI application to require and validate client certificates.
  3. Deploy FastAPI with mTLS: Dockerize your application and deploy it to Kubernetes, using secrets to manage certificates.
  4. Set Up a Service to Expose the Application: Use a LoadBalancer or NodePort service to expose the application directly without an Ingress.
  5. Test the mTLS Setup: Ensure that the application properly requires client certificates and refuses connections without them.

Step-by-Step Implementation

1. Generate TLS Certificates

You’ll need to generate a CA, a server certificate, and a client certificate. Here’s how you can do it using OpenSSL:

# Create a Certificate Authority (CA)
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 365 -out ca.crt -subj "/CN=my-ca"

# Generate server key and certificate signing request (CSR)
openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr -subj "/CN=fastapi-server"

# Sign the server CSR with the CA
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256

# Generate client key and certificate signing request (CSR)
openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr -subj "/CN=fastapi-client"

# Sign the client CSR with the CA
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 -sha256

This will create:

  • ca.crt and ca.key: The CA’s public certificate and private key.
  • server.crt and server.key: The server’s public certificate and private key.
  • client.crt and client.key: The client’s public certificate and private key.

2. Configure FastAPI with mTLS

Next, set up your FastAPI application to use mTLS by configuring Uvicorn with SSL/TLS settings.

Create a basic FastAPI application (app.py):

from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse

app = FastAPI()

@app.get("/")
async def root(request: Request):
    return {"message": "Hello, mTLS World!"}

Configure Uvicorn to require client certificates (start.sh):

uvicorn app:app \
    --host 0.0.0.0 \
    --port 443 \
    --ssl-keyfile /certs/server.key \
    --ssl-certfile /certs/server.crt \
    --ssl-ca-certs /certs/ca.crt \
    --ssl-cert-reqs=2  # Requires a client certificate

The --ssl-cert-reqs=2 option enforces that a valid client certificate must be presented for a successful connection.

3. Dockerize the FastAPI Application

Create a Dockerfile:

FROM python:3.11-slim

WORKDIR /app

COPY . /app

RUN pip install fastapi uvicorn

# Copy your SSL certificates
COPY server.crt /certs/server.crt
COPY server.key /certs/server.key
COPY ca.crt /certs/ca.crt

# Run the start script with SSL configuration
CMD ["bash", "start.sh"]

4. Deploy FastAPI with mTLS to Kubernetes

Create Kubernetes Secrets for Certificates:

To avoid baking certificates directly into your Docker image, use Kubernetes secrets:

kubectl create secret generic fastapi-tls \
  --from-file=server.crt=server.crt \
  --from-file=server.key=server.key \
  --from-file=ca.crt=ca.crt

Deployment YAML (fastapi-deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: fastapi
  template:
    metadata:
      labels:
        app: fastapi
    spec:
      containers:
      - name: fastapi
        image: your-docker-image
        ports:
        - containerPort: 443
        volumeMounts:
        - name: tls-certs
          mountPath: /certs
      volumes:
      - name: tls-certs
        secret:
          secretName: fastapi-tls

Service YAML (fastapi-service.yaml):

apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
spec:
  type: LoadBalancer  # or NodePort if preferred
  ports:
  - port: 443
    targetPort: 443
  selector:
    app: fastapi

5. Apply Deployment and Service

Deploy your application and service:

kubectl apply -f fastapi-deployment.yaml
kubectl apply -f fastapi-service.yaml

6. Test the mTLS Setup

  • Client Configuration: Use curl or any HTTP client library to test the mTLS setup.

To test with curl:

curl -v --key client.key --cert client.crt --cacert ca.crt https://<LoadBalancer-IP>

Ensure you replace <LoadBalancer-IP> with the external IP of your Kubernetes service.

Benefits and Considerations

  • Benefits: Full end-to-end encryption with both server and client authentication, ensuring secure communications.
  • Considerations: This approach requires managing and distributing client certificates securely and handling the complexities of mTLS, such as certificate rotation and revocation.

By following these steps, you can successfully implement mTLS in a Kubernetes application using FastAPI, providing a secure communication channel that is encrypted end-to-end without relying on the Ingress Controller for TLS termination.

Please read our other blogs on Kubernetes

Leave a Comment