Getting encryption from your end-user to your load balancer with SSL Termination is usually a piece of cake, and for most applications, it's good enough. But how much more effort is it to get complete end-to-end encryption all the way down to the container?
I assume, for simplicity's sake, that either the load balancer or some other mechanism is forcing the HTTP -> HTTPS upgrades, so all inbound connections to the container are already HTTPS.
NGINX Configuration
First things first, we need to update the NGINX configuration to listen on port 443 and have an SSL Certificate configured.
For this example, I am assuming that you have a PHP-FPM container downstream, but the same concepts can be applied to anything.
server {
listen 443 ssl;
index index.php index.html;
root /var/www/public;
ssl_certificate /etc/ssl/certs/certificate.pem;
ssl_certificate_key /etc/ssl/private/privatekey.pem;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
SSL Certificates
Now that your web server is expecting a certificate, we have to get it one. I'll walk through two methods of doing this: within the Dockerfile (as an entrypoint) and via Kubernetes ConfigMaps.
SSL Certificates via Dockerfile
While not recommended for production use, this is an ideal option for more ephemeral environments (e.g. local or CI/CD) as every container spun up creates its certificate. The downside, however, is that the container boot-up time increases.
Your new Dockerfile
will look something like this:
FROM nginx:alpine
WORKDIR /etc/nginx
RUN apk add openssl
ADD generate-certs.sh /etc/nginx/generate-certs.sh
RUN chmod +x /etc/nginx/generate-certs.sh
ADD vhost.conf /etc/nginx/conf.d/default.conf
CMD /bin/sh -c /etc/nginx/generate-certs.sh && nginx -g 'daemon off;'
We need to install openssl
and then call the generate-certs.sh
file which will generate the private key and certificate:
#!/bin/sh
openssl \
req -out /etc/ssl/private/certificate.csr \
-new -newkey rsa:2048 -nodes -keyout /etc/ssl/private/privatekey.pem \
-subj "/C=US/ST=OR/L=Portland/O=Docker/CN=my.domain.com"
openssl \
req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/privatekey.pem \
-out /etc/ssl/private/certificate.crt \
-subj "/C=US/ST=OR/L=Portland/O=Docker/CN=my.domain.com"
SSL Certificates via Kubernetes ConfigMaps
If you prefer to have the same certificate across all containers or otherwise centrally manage where the certificate comes from, you can use a ConfigMap created from files and mount it to the container
kubectl -n charts create configmap nginx-ssl --from-file=/folder/containing/cert-and-privatekey
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
minReadySeconds: 5
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: ##CONTAINER_IMAGE##
imagePullPolicy: Always
ports:
- containerPort: 443
volumeMounts:
- name: nginx-ssl
mountPath: /etc/ssl/private/certificate.pem
readOnly: true
subPath: certificate.pem
- name: nginx-ssl
mountPath: /etc/ssl/private/privatekey.pem
readOnly: true
subPath: privatekey.pem
resources:
requests:
cpu: 250m
limits:
cpu: 500m
volumes:
- name: nginx-ssl
configMap:
name: nginx-ssl
Complete, functional examples can be found here:
Comments