Skip to content

Instantly share code, notes, and snippets.

@moolen
Last active December 21, 2022 07:40
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save moolen/d940dd909dbc633a1413ef0715386f99 to your computer and use it in GitHub Desktop.
Save moolen/d940dd909dbc633a1413ef0715386f99 to your computer and use it in GitHub Desktop.
cfssl: multiple CA w/ nginx mutual tls
#!/bin/bash
set -e
readonly SERVER_HOST_NAME="localhost"
readonly COMBINED_CA="combined.ca.pem"
readonly CA_ROOT_CERT_KEY="ca-root"
readonly CA_INTERMEDIATE1_CERT_KEY="ca-intermediate1"
readonly CA_INTERMEDIATE2_CERT_KEY="ca-intermediate2"
readonly CA_INTERMEDIATE3_CERT_KEY="ca-intermediate3"
readonly SERVER_CERT_KEY="localhost"
readonly CLIENT_CERT_KEY="localhost.client"
# cleanup
rm -rf ca1 ca2 ca3 $COMBINED_CA
# create
mkdir ca1 ca2 ca3
touch $COMBINED_CA
for ca in "ca1" "ca2" "ca3"; do
cd $ca;
tee ca-config.json 1> /dev/null <<-CONFIG
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"server": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
},
"client": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
},
"client-server": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
CONFIG
tee ca-root-to-intermediate-config.json 1> /dev/null <<-CONFIG
{
"signing": {
"default": {
"expiry": "43800h",
"ca_constraint": {
"is_ca": true,
"max_path_len": 3
},
"usages": [
"digital signature",
"cert sign",
"crl sign",
"signing"
]
}
}
}
CONFIG
cfssl genkey \
-initca \
- \
<<-CONFIG | cfssljson -bare ${CA_ROOT_CERT_KEY}
{
"CN": "(LOCAL) ROOT CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "--",
"ST": "STATE",
"L": "LOCALITY",
"O": "ORGANISATION",
"OU": "LOCAL"
}
],
"ca": {
"expiry": "131400h"
}
}
CONFIG
cfssl gencert \
-initca \
- \
<<-CONFIG | cfssljson -bare ${CA_INTERMEDIATE1_CERT_KEY}
{
"CN": "(LOCAL) INTERMEDIATE 1 CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "--",
"ST": "STATE",
"L": "LOCALITY",
"O": "ORGANISATION",
"OU": "LOCAL"
}
],
"ca": {
"expiry": "43800h"
}
}
CONFIG
cfssl gencert \
-initca \
- \
<<-CONFIG | cfssljson -bare ${CA_INTERMEDIATE2_CERT_KEY}
{
"CN": "(LOCAL) INTERMEDIATE 2 CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "--",
"ST": "STATE",
"L": "LOCALITY",
"O": "ORGANISATION",
"OU": "LOCAL"
}
],
"ca": {
"expiry": "43800h"
}
}
CONFIG
cfssl gencert \
-initca \
- \
<<-CONFIG | cfssljson -bare ${CA_INTERMEDIATE3_CERT_KEY}
{
"CN": "(LOCAL) INTERMEDIATE 3 CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "--",
"ST": "STATE",
"L": "LOCALITY",
"O": "ORGANISATION",
"OU": "LOCAL"
}
],
"ca": {
"expiry": "43800h"
}
}
CONFIG
# Sign intermediate certificate with root certificate
cfssl sign \
-ca ${CA_ROOT_CERT_KEY}.pem \
-ca-key ${CA_ROOT_CERT_KEY}-key.pem \
-config ca-root-to-intermediate-config.json \
${CA_INTERMEDIATE1_CERT_KEY}.csr \
| cfssljson -bare ${CA_INTERMEDIATE1_CERT_KEY}
cfssl sign \
-ca ${CA_INTERMEDIATE1_CERT_KEY}.pem \
-ca-key ${CA_INTERMEDIATE1_CERT_KEY}-key.pem \
-config ca-root-to-intermediate-config.json \
${CA_INTERMEDIATE2_CERT_KEY}.csr \
| cfssljson -bare ${CA_INTERMEDIATE2_CERT_KEY}
cfssl sign \
-ca ${CA_INTERMEDIATE2_CERT_KEY}.pem \
-ca-key ${CA_INTERMEDIATE2_CERT_KEY}-key.pem \
-config ca-root-to-intermediate-config.json \
${CA_INTERMEDIATE3_CERT_KEY}.csr \
| cfssljson -bare ${CA_INTERMEDIATE3_CERT_KEY}
## Server certificate
cfssl gencert \
-ca ${CA_INTERMEDIATE3_CERT_KEY}.pem \
-ca-key ${CA_INTERMEDIATE3_CERT_KEY}-key.pem \
-config ca-config.json \
-profile server \
-hostname "${SERVER_HOST_NAME}" \
- \
<<-CONFIG | cfssljson -bare ${SERVER_CERT_KEY}
{
"CN": "${SERVER_HOST_NAME}",
"key": {
"algo": "rsa",
"size": 2048
}
}
CONFIG
## Client certificate
cfssl gencert \
-ca ${CA_INTERMEDIATE1_CERT_KEY}.pem \
-ca-key ${CA_INTERMEDIATE1_CERT_KEY}-key.pem \
-config ca-config.json \
-profile client \
-hostname "MY_CLIENT" \
- \
<<-CONFIG | cfssljson -bare ${CLIENT_CERT_KEY}
{
"CN": "CLIENT_NAME",
"key": {
"algo": "rsa",
"size": 2048
}
}
CONFIG
cd ..;
cat $ca/${CA_INTERMEDIATE1_CERT_KEY}.pem >> $COMBINED_CA
cat $ca/${CA_INTERMEDIATE2_CERT_KEY}.pem >> $COMBINED_CA
cat $ca/${CA_ROOT_CERT_KEY}.pem >> $COMBINED_CA
cat $ca/${CA_INTERMEDIATE3_CERT_KEY}.pem >> $COMBINED_CA
done
docker build -t ca_nginx .
docker rm -f nginx-container || true
docker run --name nginx-container \
-d \
-v $(pwd)/ca1:/etc/nginx/certs/ \
-v $(pwd)/combined.ca.pem:/etc/nginx/combined.ca.pem \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
-p 8000:443 -d ca_nginx
echo "testung ca certs"
for ca in "ca1" "ca2" "ca3"; do
curl \
-o /dev/null -w "%{http_code}\n" \
--cacert ./combined.ca.pem \
--cert ./$ca/localhost.client.pem \
--key ./$ca/localhost.client-key.pem \
https://localhost:8000
done
FROM ubuntu:14.04
# install nginx
RUN apt-get update && \
apt-get install software-properties-common -y && \
add-apt-repository ppa:nginx/stable -y && \
apt-get update && \
apt-get install -y nginx=1.12.2-0+trusty0
RUN rm -rf /etc/nginx/sites-enabled/default
# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
user nobody nogroup;
worker_processes auto;
events {
worker_connections 512;
}
http {
server {
listen *:443;
ssl on;
server_name "localhost";
ssl_certificate /etc/nginx/certs/localhost.pem;
ssl_certificate_key /etc/nginx/certs/localhost-key.pem;
ssl_client_certificate /etc/nginx/combined.ca.pem;
ssl_verify_depth 100;
ssl_verify_client on;
root /usr/share/nginx/html;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment