A very simple automated Certificate Authority. Such CA is useful on auto provisioned clusters secured by client certificates, like etcd and Kubernetes.
Run the CA:
docker run -d -p 80:8080 -p 443:8443 quay.io/jcmoraisjr/simple-ca
Create a private key and certificate request:
openssl req -new -newkey rsa:2048 -keyout host-key.pem -nodes -out host.csr -subj "/"
Sign the certificate -- change localhost to the IP if Docker Server is on a VM - eg Docker Machine:
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?cn=my-host&ns=my-host.localdomain"
Check the certificate:
openssl x509 -noout -text -in host.pem
Using dn instead cn:
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?dn=/CN=my-host&ns=my-host.localdomain"
Shortcut to organizationName and dn syntax - Note that ca.cnf changed on 0.7,
you should update or remove <local-ca-dir>/ssl/ca/ca.cnf before restart simple-ca:
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?cn=my-host&o=company&ns=my-host.localdomain"
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?dn=/CN=my-host/O=company&ns=my-host.localdomain"
One liner key and cert:
openssl req -new -newkey rsa:2048 -keyout host-key.pem -nodes -subj "/" | \
curl -fk --data-binary @- -o host.pem "https://localhost/sign?cn=my-host&ns=my-host.localdomain"
Using subject from the request - cn is optional since 0.7:
openssl req -new -newkey rsa:2048 -keyout host-key.pem -nodes -subj "/CN=my-host" | \
curl -fk --data-binary @- -o host.pem "https://localhost/sign?ns=my-host.localdomain"
Using alternative IP, NS or both:
Note: If neither IP nor NS is provided, a client certificate would be generated. Always provide IP, NS or both for server certificates.
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?cn=my-host&ip=10.0.0.1"
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?cn=my-host&ip=10.0.0.1,192.168.0.1"
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?cn=my-host&ns=localhost,my-host.localdomain"
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?cn=my-host&ip=10.0.0.1&ns=my-host.localdomain"
Using alternative number of days:
curl -fk --data-binary @host.csr -o host.pem "https://localhost/sign?cn=my-host&days=30"
The signing of certificates can also be protected with a token:
echo -n "mysupersecret" | md5sum
docker run -d -p 80:8080 -p 443:8443 \
-e TOKEN=md5:6dc90cbae61d22f5cd1ca3f4025c47a3 \
quay.io/jcmoraisjr/simple-ca
Now /sign method must provide &token=mysupersecret param, otherwise the certificate won't be signed. If using echo to generate the hash, remember to use -n so echo won't add a line break into your secret.
Since 0.8 simple-ca has support for multiple certificate authorities:
docker run -d -p 80:8080 -p 443:8443 \
-e CA_LIST=servers,etcd,kube \
-e CA_CN_servers="CA for servers" \
-e CA_CN_etcd="Etcd CA" \
-e CA_CN_kube="Kubernetes CA" \
quay.io/jcmoraisjr/simple-ca
openssl req -new -newkey rsa:2048 -keyout kube-etcd-key.pem -nodes -subj "/" | \
curl -fk --data-binary @- -o kube-etcd.pem "https://localhost/sign/etcd?cn=kube"
openssl req -new -newkey rsa:2048 -keyout kube-admin-key.pem -nodes -subj "/" | \
curl -fk --data-binary @- -o kube-admin.pem "https://localhost/sign/kube?cn=admin&o=system:masters"
When running 0.8 the first time on a schema of an old version, simple-ca will update to the new schema creating the CA default. All new certificate authorities are created as sub-directories of /ssl/ca.
Both syntax are still valid: /sign and /ca using default certificate authority, and the new /sign/<ca_id> and /ca/<ca_id>. The ID of the certificate authority of the first syntax can be changed declaring CA_DEFAULT environment variable.
If TLS certificate for https isn't provided, the CA which will sign the certificate will be chosen in the following order:
- Certificate authority declared with
CA_DEFAULT, which defaults todefault - If the above certificate authority ID does not exist, the first certificate authority declared on
CA_LISTwill be used
New certificate authorities can be included updating CA_LIST environment variable. The next start of simple-ca will update the schema.
Note that removing CAs from the CA_LIST will deny the access from /sign and /ca methods but won't remove it from the schema. If the CA is reincluded to the list, the same CA cert and private key will continue to sign certificates.
The following parameters can be used in the query string of the /sign method:
dn: Distinguished name in the following format:/O=.../OU=.../.../CN=...cn: Common name of the certificate - do not use the/CN=prefixo: Comma separated list of organizationName - do not use the/O=prefixip: Comma separated list of IPs of server certificatens: Comma separated list of name servers of server certificate. Eitheripornsmust be provided for server certificates, otherwise a client certificate will be generateddays: The number of days to certify the signed certificatetoken: Security token, should be provided when signing certificates if the server was started withTOKENenvvar
The following optional environment variables may be defined:
TOKEN: hash of the secret token. If defined the&token=is mandatory and must match the value. The token has the following format:<algorithm>:<hash-itself>. The currently supported algorithms aremd5,sha1,sha256andsha512CRT_DAYS: default number of days to certify signed certificates, defaults to 365, can be changed per signed certificate with&days=<days>CA_DAYS: number of days to certify the auto generated CA certificate, defaults to 3652 (10 years)CA_DIR: path to directory of all certificate authorities. A new cert and key will be created for any CA if not foundCA_CN: A self generated CA will useCA_CNas its common name, defaults tomy-caCERT_TLS: TLS certificate and key file used by web server to provide https, defaults to/ssl/www/localhost.pem. If not found, CA itself will sign a certificateCERT_TLS_DNS: name server of the CA server, used on auto generated TLS certificate. At least one ofCERT_TLS_DNSorCERT_TLS_IPshould be providedCERT_TLS_IP: public IP of the CA server, used on auto generated TLS certificate. At least one ofCERT_TLS_DNSorCERT_TLS_IPshould be providedCERT_TLS_DAYS: number of days to certify the CA server cert, used on auto generated TLS certificate, defaults to 365 days
When using multi certificate authority, the following environment variables might also be defined:
CA_LIST: comma separated list of IDs of CAs. IDs must match[a-z0-9_]. The default value is one certificate authority:defaultCA_DEFAULT: ID of the certificate authority that should be used on/signand/camethods.defaultis used if not provided. Note that ifCA_LISTdoesn't includedefaultandCA_DEFAULTisn't provided,/signand/camethods will issue404 Not Found.CRT_DAYS_<ca_id>: override defaultCRT_DAYSCA_DAYS_<ca_id>: override defaultCA_DAYSCA_CN_<ca_id>: override defaultCA_CN
- Mount the
/ssldirectory to ensure that nothing will be lost if the container is recreated - The external directory should be owned by container's
lighttpduser (uid 100)
This systemd unit has the most common configuration:
[Unit]
Description=Simple CA
After=docker.service
Requires=docker.service
[Service]
ExecStartPre=-/usr/bin/docker stop simple-ca
ExecStartPre=-/usr/bin/docker rm simple-ca
ExecStartPre=/usr/bin/mkdir -p /var/lib/simple-ca/ssl
ExecStartPre=/bin/bash -c 'chown $(docker run --rm quay.io/jcmoraisjr/simple-ca id -u lighttpd) /var/lib/simple-ca/ssl'
ExecStart=/usr/bin/docker run \
--name simple-ca \
-p 80:8080 \
-p 443:8443 \
-e CERT_TLS_DNS=ca.mycompany.com \
-e CA_CN=MyCompany-CA \
-v /var/lib/simple-ca/ssl:/ssl \
quay.io/jcmoraisjr/simple-ca:latest
RestartSec=10s
Restart=always
[Install]
WantedBy=multi-user.target