Skip to content

POC: AWS WAF and ALB with TLS Re-encryption to NGINX Backend #1774

@vandjelk

Description

@vandjelk

Objective

Demonstrate end-to-end HTTPS using SNI where traffic flows:

Client → HTTPS → AWS WAF → AWS ALB → HTTPS (SNI) → NGINX → application

The ALB terminates TLS for WAF inspection and re-encrypts traffic to the NGINX backend using HTTPS. NGINX presents its own certificate and routes based on SNI/Host header.


Architecture

Traffic flow:

Client
   │ HTTPS (SNI nginx.test.example.com)
   ▼
AWS WAF
   │
   ▼
ALB
   │ HTTPS re-encryption
   ▼
Worker Node
   │ NodePort 30443
   ▼
NGINX
   │
   ▼
Application

TLS sessions:

  • Client ↔ ALB: ACM certificate
  • ALB ↔ NGINX: Kubernetes TLS secret

Host header and SNI are preserved end-to-end.


Prerequisites

Generate Certificates

Certificates:

Located in ../certs/ directory:

  • wildcard.test.example.com.crt
  • wildcard.test.example.com.key

Tools required:

  • kubectl
  • aws CLI
  • openssl

Variables used in examples:

export REGION=eu-central-1
export DOMAIN=nginx.test.example.com

1 Import Certificate into AWS ACM

ALB requires certificates from ACM.

cd ../certs
aws acm import-certificate \
  --certificate fileb://wildcard.test.example.com.crt \
  --private-key fileb://wildcard.test.example.com.key \
  --region $REGION

Save returned ARN:

export CERT_ARN=<returned-arn>

2 Create Kubernetes TLS Secret

Used by NGINX backend.

kubectl create secret tls nginx-tls \
  --cert=../certs/wildcard.test.example.com.crt \
  --key=../certs/wildcard.test.example.com.key

3 Create AWS WAF WebACL

Create WebACL:

aws wafv2 create-web-acl \
  --name eks-waf-test \
  --scope REGIONAL \
  --default-action Allow={} \
  --visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=waf-test \
  --region $REGION

Add AWS managed rule set (example from AWS blog):

aws wafv2 create-rule-group

Common managed rules typically used:

AWSManagedRulesCommonRuleSet
AWSManagedRulesKnownBadInputsRuleSet
AWSManagedRulesSQLiRuleSet

Capture returned ARN:

export WAF_ARN=<web-acl-arn>

4 Create NGINX ConfigMap

kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  nginx.conf: |
    events {}

    http {
      server {
        listen 443 ssl;
        server_name nginx.test.example.com;

        ssl_certificate /etc/nginx/tls/tls.crt;
        ssl_certificate_key /etc/nginx/tls/tls.key;

        location / {
          return 200 "Hello from NGINX TLS backend\n";
        }
      }
    }
EOF

5 Create NGINX Deployment

kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 443
        volumeMounts:
        - name: config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
        - name: tls
          mountPath: /etc/nginx/tls
      volumes:
      - name: config
        configMap:
          name: nginx-conf
      - name: tls
        secret:
          secretName: nginx-tls
EOF

6 Create NGINX Service

NodePort required for instance target type.

kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 443
    targetPort: 443
    nodePort: 30443
EOF

7 Create ALB Ingress

kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-alb
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: instance
    alb.ingress.kubernetes.io/backend-protocol: HTTPS
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/ssl-redirect: '443'
    alb.ingress.kubernetes.io/certificate-arn: "$CERT_ARN"
    alb.ingress.kubernetes.io/wafv2-acl-arn: "$WAF_ARN"
spec:
  ingressClassName: alb
  rules:
  - host: nginx.test.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 443
EOF

8 Retrieve ALB Address

export ALB_DNS=$(kubectl get ingress nginx-alb -o jsonpath="{.status.loadBalancer.ingress[0].hostname}")
echo "ALB DNS: $ALB_DNS"

Example output:

k8s-default-nginx-123456.eu-central-1.elb.amazonaws.com

9 Local Testing via /etc/hosts

Resolve ALB IP:

dig $ALB_DNS +short

Edit hosts:

sudo nano /etc/hosts

Add:

<ALB_IP> nginx.test.example.com

10 Test HTTPS + SNI

curl -k https://nginx.test.example.com

Expected response:

Hello from NGINX TLS backend

Result

This POC demonstrates:

  • WAF inspection at ALB
  • End-to-end HTTPS
  • SNI based routing
  • Kubernetes backend using NodePort
  • Integration of ALB with Kubernetes ingress controller

Debug Commands

Check ingress:

kubectl get ingress -A

Check ingress details:

kubectl describe ingress nginx-alb

Check NGINX pods:

kubectl get pods -l app=nginx

Check NGINX logs:

kubectl logs -l app=nginx

Check ALB target groups (via AWS Console or CLI):

aws elbv2 describe-target-health --target-group-arn <target-group-arn> --region $REGION

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions