There are times when you need to create your own certificate authority. This could be for your own private servers or maybe if you want to setup mTLS, and you need to issue client certificates. This note will be split into these sections:
Intro Link to heading
I have found that using makefiles is a really nice approach to manage your CA. We will of course use the Makefile Help template to create our CA and then we end up with this nice interface:
$ make
Makefile targets:
help Show this help
ca.key Create CA private key for 'My Certificate Authority'
ca.crt Create CA certificate for 'My Certificate Authority'
ca.crt-info Print cert for 'My Certificate Authority'
myserver.com.key Create key for '*.myserver.com'
myserver.com.csr Create CSR for '*.myserver.com'
myserver.com.cert Sign CSR for '*.myserver.com'
myserver.com.cert-info Print cert for '*.myserver.com'
Setup Link to heading
How do we accomplish this? Well we are going to create 3 Makefiles:
<DIR>
├── Makefile
├── Makefile-ca.mk
└── Makefile-cert1.mk
Each makefile definition is explained below!
Makefile Link to heading
Lets start with Makefile
. This is the file that glues everything together:
NOTE: The
help
target is slightly modified version of Makefile Help to work with theinclude
statements!
.PHONY: help ${CA_CERT}-print ${CERT_1_CERT}-print
.DEFAULT_GOAL:=help
CA_DIR=ca
CERTS_DIR=certs
include Makefile-ca.mk
include Makefile-cert1.mk
help: ## Show this help
$(eval HELP_COL_WIDTH:=30)
@echo "Makefile targets:"
@grep -E '[^\s]+:.*?## .*$$' ${MAKEFILE_LIST} | sed 's/Makefile://g' | sed 's/.*\.mk://g' | grep -v grep | envsubst | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-${HELP_COL_WIDTH}s\033[0m %s\n", $$1, $$2}'
Makefile-ca.mk Link to heading
Next we can setup Makefile-ca.mk
. This file handles the definition of our certificate authority:
# The password can (and probably should) be read from the environment
CA_PASS=mysecretpassword
# Files
export CA_CERT=${CA_DIR}/ca.crt
export CA_KEY=${CA_DIR}/ca.key
# Certificate properties
export CA_CN=My Certificate Authority
CA_SUBJ="/C=NO/ST=OSLO/L=OSLO/O=Gummi/OU=Gummi/CN=${CA_CN}"
CA_EXPIRES_IN=3560
${CA_KEY}: ## Create CA private key for '${CA_CN}'
# Create CA key ...
@test ${CA_PASS} || (echo "Set env variable CA_PASS"; exit 1;)
@mkdir -p ${CA_DIR}
openssl genrsa \
-des3 \
-passout pass:${CA_PASS} \
-out ${CA_KEY} \
4096
${CA_CERT}: ${CA_KEY} ## Create CA certificate for '${CA_CN}'
# Create CA certificate ...
@test ${CA_PASS} || (echo "Set env variable CA_PASS"; exit 1;)
@mkdir -p ${CA_DIR}
openssl req \
-x509 -new -nodes \
-key ${CA_KEY} \
-sha256 -days ${CA_EXPIRES_IN} \
-passin pass:${CA_PASS} \
-out ${CA_CERT} \
-subj ${CA_SUBJ}
${CA_CERT}-print: ${CA_CERT} ## Print cert for '${CA_CN}'
@openssl x509 -in ${CA_CERT} -noout -text
Makefile-cert1.mk Link to heading
Finally lets create Makefile-cert1.mk
, that issues a certificate for us:
# Files
export CERT_1_KEY=${CERTS_DIR}/myserver.com.key
export CERT_1_CSR=${CERTS_DIR}/myserver.com.csr
export CERT_1_CERT=${CERTS_DIR}/myserver.com.cert
# Certificate properties
export CERT_1_CN=*.myserver.com
CERT_1_SUBJ="/C=NO/ST=OSLO/L=OSLO/O=Gummi/OU=Gummi/CN=${CERT_1_CN}"
CERT_1_CA_EXPIRES_IN=3650
${CERT_1_KEY}: ## Create key for '${CERT_1_CN}'
# Create key ...
@mkdir -p ${CERTS_DIR}
openssl genrsa \
-out ${CERT_1_KEY} \
4096
${CERT_1_CSR}: ${CERT_1_KEY} ## Create CSR for '${CERT_1_CN}'
# Create certificate request ...
@mkdir -p ${CERTS_DIR}
openssl req -new \
-key ${CERT_1_KEY} \
-out ${CERT_1_CSR} \
-subj ${CERT_1_SUBJ}
${CERT_1_CERT}: ${CA_CERT} ${CERT_1_CSR} ## Sign CSR for '${CERT_1_CN}'
# Create certificate ...
@test ${CA_PASS} || (echo "Set env variable CA_PASS"; exit 1;)
@mkdir -p ${CERTS_DIR}
openssl x509 \
-req -CAcreateserial \
-in ${CERT_1_CSR} \
-CA ${CA_CERT} \
-CAkey ${CA_KEY} \
-passin pass:${CA_PASS} \
-out ${CERT_1_CERT} \
-days ${CERT_1_CA_EXPIRES_IN} -sha256
${CERT_1_CERT}-print: ${CERT_1_CERT} ## Print cert for '${CERT_1_CN}'
@openssl x509 -in ${CERT_1_CERT} -noout -text
Usage Link to heading
Now that we have set our makefiles up, we can create everything in a single command:
$ make certs/myserver.com.cert
# Create CA key ...
openssl genrsa \
-des3 \
-passout pass:mysecretpassword \
-out ca/ca.key \
4096
Generating RSA private key, 4096 bit long modulus (2 primes)
..................................................................++++
.................................................++++
e is 65537 (0x010001)
# Create CA certificate ...
openssl req \
-x509 -new -nodes \
-key ca/ca.key \
-sha256 -days 3560 \
-passin pass:mysecretpassword \
-out ca/ca.crt \
-subj "/C=NO/ST=OSLO/L=OSLO/O=Gummi/OU=Gummi/CN=My Certificate Authority"
# Create key ...
openssl genrsa \
-out certs/myserver.com.key \
4096
Generating RSA private key, 4096 bit long modulus (2 primes)
........................................................................++++
.........................++++
e is 65537 (0x010001)
# Create certificate request ...
openssl req -new \
-key certs/myserver.com.key \
-out certs/myserver.com.csr \
-subj "/C=NO/ST=OSLO/L=OSLO/O=Gummi/OU=Gummi/CN=*.myserver.com"
# Create certificate ...
openssl x509 \
-req -CAcreateserial \
-in certs/myserver.com.csr \
-CA ca/ca.crt \
-CAkey ca/ca.key \
-passin pass:mysecretpassword \
-out certs/myserver.com.cert \
-days 3650 -sha256
Signature ok
subject=C = NO, ST = OSLO, L = OSLO, O = Gummi, OU = Gummi, CN = *.myserver.com
Getting CA Private Key
… and this will make our directory look like this:
$ tree
.
├── ca
│ ├── ca.crt
│ ├── ca.key
│ └── ca.srl
├── certs
│ ├── myserver.com.cert
│ ├── myserver.com.csr
│ └── myserver.com.key
├── Makefile
├── Makefile-ca.mk
└── Makefile-cert1.mk
2 directories, 9 files
Adding certs Link to heading
Now if you want to add more certs, just copy the Makefile-cert1.mk
file and search/replace CERT_1
with something else, i.e:
$ cat Makefile-cert1.mk | sed s/CERT_1/CERT_2/g > Makefile-cert2.mk
Then change the files and properties at the top of the new makefile:
...
# Files
export CERT_2_KEY=${CERTS_DIR}/myserver2.com.key
export CERT_2_CSR=${CERTS_DIR}/myserver2.com.csr
export CERT_2_CERT=${CERTS_DIR}/myserver2.com.cert
# Certificate properties
export CERT_2_CN=*.myserver2.com
CERT_2_SUBJ="/C=NO/ST=OSLO/L=OSLO/O=Gummi/OU=Gummi/CN=${CERT_2_CN}"
CERT_2_CA_EXPIRES_IN=3650
...
And include the new makefile in Makefile
like so:
...
include Makefile-ca.mk
include Makefile-cert1.mk
include Makefile-cert2.mk
...
And voilà, your new targets show up:
$ make
Makefile targets:
help Show this help
ca/ca.key Create CA private key for 'My Certificate Authority'
ca/ca.crt Create CA certificate for 'My Certificate Authority'
ca/ca.crt-print Print cert for 'My Certificate Authority'
certs/myserver.com.key Create key for '*.myserver.com'
certs/myserver.com.csr Create CSR for '*.myserver.com'
certs/myserver.com.cert Sign CSR for '*.myserver.com'
certs/myserver.com.cert-print Print cert for '*.myserver.com'
certs/myserver2.com.key Create key for '*.myserver2.com'
certs/myserver2.com.csr Create CSR for '*.myserver2.com'
certs/myserver2.com.cert Sign CSR for '*.myserver2.com'
certs/myserver2.com.cert-print Print cert for '*.myserver2.com'