Skip to content

Instantly share code, notes, and snippets.

@jameswhite
Created August 28, 2014 23:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jameswhite/4c15c9b99819e18bb5d3 to your computer and use it in GitHub Desktop.
Save jameswhite/4c15c9b99819e18bb5d3 to your computer and use it in GitHub Desktop.
#!/bin/bash
DOMAIN=$1; shift
if [ -z "${DOMAIN}" ]; then
echo "No domain specified, assuming github.net"
DOMAIN="github.net"
fi
BASE=$(pwd)
ROOT_CA_KEYSIZE=4096
MID_CA_KEYSIZE=4096
HOST_KEYSIZE=2048
CA_TREE_TRUNK="${BASE}/certificate_authority"
VAULT_DIR="${BASE}/vault"
WEB_ROOT="${BASE}/www"
SSL_ROOT="${BASE}/ssl"
for elf in `echo "dig openssl gpg"`; do
if [ -z $(which ${elf}) ];then
echo "${elf} not found. Aborting...";
exit -1
fi
done
# abort if the trunk is already in place
if [ -d ${CA_TREE_TRUNK}/root-ca.${DOMAIN} ];then
echo "I've already got a pki infrastructure... Aborting"
exit 0;
fi
###################################################################
# These need to be set up in DNS or exported, or live with the defaults
###################################################################
[ -z "${CA_COUNTRY}" ] && CA_COUNTRY=$(dig +short -t txt ca-country.${DOMAIN}|sed -e's/"//g'); [ -z "${CA_COUNTRY}" ] && CA_COUNTRY="US"
[ -z "${CA_STATE}" ] && CA_STATE=$(dig +short -t txt ca-state.${DOMAIN}|sed -e's/"//g'); [ -z "${CA_STATE}" ] && CA_STATE="California"
[ -z "${CA_LOCALITY}" ] && CA_LOCALITY=$(dig +short -t txt ca-locality.${DOMAIN}|sed -e's/"//g'); [ -z "${CA_LOCALITY}" ] && CA_LOCALITY="San Francisco"
[ -z "${CA_ORG}" ] && CA_ORG=$(dig +short -t txt ca-org.${DOMAIN}|sed -e's/"//g'); [ -z "${CA_ORG}" ] && CA_ORG="GitHub Inc."
[ -z "${CA_ORGUNIT}" ] && CA_ORGUNIT=$(dig +short -t txt ca-orgunit.${DOMAIN}|sed -e's/"//g'); [ -z "${CA_ORGUNIT}" ] && CA_ORGUNIT="Information Security"
[ -z "${CA_EMAIL}" ] && CA_EMAIL=$(dig +short -t txt ca-email.${DOMAIN}|sed -e's/"//g'); [ -z "${CA_EMAIL}" ] && CA_ORGUNIT="ops@github.com"
[ -z "${CA_CRL}" ] && CA_EMAIL=$(dig +short -t txt ca-crl.${DOMAIN}|sed -e's/"//g'); [ -z "${CA_CRL}" ] && CA_CRL="github-ca.s3.amazonaws.com/${DOMAIN}/crl"
if [ -z "${SECRET}" ]; then SECRET=$(/${HOME}/bin/secret); fi
if [ -z "${SECRET}" ]; then
echo "please set SECRET"
exit 1;
fi
###################################################################
# We use the same secret for everything that we do on a system.
###################################################################
WORKDIR="${BASE}/${DOMAIN}"
[ ! -d "${WORKDIR}" ] && mkdir -p "${WORKDIR}"
###################################################################
# OpenSSL configuration Template
###################################################################
if [ ! -f "${WORKDIR}/openssl.tpl" ] ;then
cat<<EOTPL > ${WORKDIR}/openssl.tpl
HOME = .
RANDFILE = \$ENV::HOME/.rnd
DOMAIN = ${DOMAIN}
ca-domain = ~LEVEL~.${DOMAIN}
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = .
certs = \$dir/certs
crl_dir = \$dir/crl
database = \$dir/index.txt
new_certs_dir = \$dir/newcerts
certificate = \$dir/~LEVEL~.\${DOMAIN}.pem
serial = \$dir/serial
crlnumber = \$dir/crlnumber
crl = \$dir/crl.\${DOMAIN}.pem
private_key = \$dir/private/~LEVEL~.\${DOMAIN}.key
RANDFILE = \$dir/private/.rand
x509_extensions = usr_cert
name_opt = ca_default
cert_opt = ca_default
default_days = ~DAYS~
default_crl_days= ~DAYS~
default_md = sha1
preserve = no
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 2048
default_keyfile = \${DOMAIN}.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = ${CA_COUNTRY}
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = ${CA_STATE}
localityName = Locality Name (eg, city)
localityName_default = ${CA_LOCALITY}
0.organizationName = Organization Name (eg, company)
0.organizationName_default = ${CA_ORG}
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = ~TEXTLEVEL~
commonName = Common Name (eg, YOUR name)
commonName_max = 64
commonName_default = ~COMMON_NAME~
emailAddress = Email Address
emailAddress_max = 64
emailAddress_default = ~EMAIL~
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
[ usr_cert ]
basicConstraints=CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
nsCaRevocationUrl = ${CA_CRL}/~LEVEL~
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsCaRevocationUrl = ${CA_CRL}/~LEVEL~
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints = CA:true
nsCaRevocationUrl = ${CA_CRL}/~LEVEL~
EOTPL
fi
###################################################################
# Create the Root Certificate Authority
###################################################################
ROOT_CA="${WORKDIR}/root-ca"
if [ ! -d ${ROOT_CA} ];then
mkdir -p ${ROOT_CA};fi
echo "01" > ${ROOT_CA}/serial
cp /dev/null ${ROOT_CA}/index.txt
for dir in `echo "certs crl newcerts private"`;do
if [ ! -d ${ROOT_CA}/${dir} ];then
mkdir ${ROOT_CA}/${dir}
fi
done
sed -e 's/~LEVEL~/root-ca/g' \
-e "s/~COMMON_NAME~/root-ca.${DOMAIN}/g" \
-e 's/~TEXTLEVEL~/Root Certificate Authority/g' \
-e 's/~EMAIL~/certmaster@${DOMAIN}/g' \
-e 's/~DAYS~/3650/g' \
${WORKDIR}/openssl.tpl > ${ROOT_CA}/openssl.cnf
# root ca
echo ${SECRET} | openssl genrsa -des3 -passout fd:0 \
-out ${ROOT_CA}/private/root-ca.${DOMAIN}.key ${ROOT_CA_KEYSIZE}
echo ${SECRET} | openssl req -new -x509 -nodes -sha1 \
-days 3650 -passin fd:0 \
-key ${ROOT_CA}/private/root-ca.${DOMAIN}.key \
-out ${ROOT_CA}/root-ca.${DOMAIN}.pem \
-config ${ROOT_CA}/openssl.cnf -batch
###################################################################
# Create the Intermediate Certificate Authority
###################################################################
MID_CA="${WORKDIR}/intermediate-ca"
if [ ! -d ${MID_CA} ];then mkdir -p ${MID_CA};fi
echo "01" > ${MID_CA}/serial
cp /dev/null ${MID_CA}/index.txt
for dir in `echo "certs crl newcerts private"`;do
if [ ! -d ${MID_CA}/${dir} ];then
mkdir ${MID_CA}/${dir}
fi
done
sed -e 's/~LEVEL~/intermediate-ca/g' \
-e "s/~COMMON_NAME~/intermediate-ca.${DOMAIN}/g" \
-e 's/~TEXTLEVEL~/Intermediate Certificate Authority/g' \
-e 's/~EMAIL~/certmaster@${DOMAIN}/g' \
-e 's/~DAYS~/1825/g' \
${WORKDIR}/openssl.tpl > ${MID_CA}/openssl.cnf
# mid ca
cd ${MID_CA}
echo "${SECRET}" | openssl genrsa -des3 -passout fd:0 \
-out ${MID_CA}/private/intermediate-ca.${DOMAIN}.key ${MID_CA_KEYSIZE}
echo "${SECRET}" | openssl req -new -sha1 -days 1825 -passin fd:0 \
-key ${MID_CA}/private/intermediate-ca.${DOMAIN}.key \
-out ${MID_CA}/intermediate-ca.${DOMAIN}.csr \
-config ${MID_CA}/openssl.cnf -batch
###################################################################
# sign the Intermediate CA with the Root CA
###################################################################
mv ${MID_CA}/intermediate-ca.${DOMAIN}.csr ${ROOT_CA}
cd ${ROOT_CA}
echo "${SECRET}" | openssl ca -extensions v3_ca -days 1825 \
-passin fd:0 \
-out ${ROOT_CA}/intermediate-ca.${DOMAIN}.crt \
-in ${ROOT_CA}/intermediate-ca.${DOMAIN}.csr \
-config ${ROOT_CA}/openssl.cnf -batch
# create the chain
cat ${ROOT_CA}/intermediate-ca.${DOMAIN}.crt ${ROOT_CA}/root-ca.${DOMAIN}.pem > ${MID_CA}/${DOMAIN}-trust-chain.crt
# put them back where they go
mv ${ROOT_CA}/intermediate-ca.${DOMAIN}.crt ${MID_CA}/intermediate-ca.${DOMAIN}.pem
mv ${ROOT_CA}/intermediate-ca.${DOMAIN}.csr ${MID_CA}/intermediate-ca.${DOMAIN}.csr
###################################################################
# Create the Domain Certificate Authority for $(dnsdomainname)
###################################################################
DOM_CA="${WORKDIR}/domain-ca"
if [ ! -d ${DOM_CA} ];then mkdir -p ${DOM_CA};fi
echo "01" > ${DOM_CA}/serial
cp /dev/null ${DOM_CA}/index.txt
for dir in `echo "certs crl newcerts private"`;do
if [ ! -d ${DOM_CA}/${dir} ];then
mkdir ${DOM_CA}/${dir}
fi
done
sed -e "s/~LEVEL~/domain-ca/g" \
-e "s/~COMMON_NAME~/domain-ca.${DOMAIN}/g" \
-e "s/~TEXTLEVEL~/Domain Certificate Authority/g" \
-e 's/~EMAIL~/certmaster@${DOMAIN}/g' \
-e 's/~DAYS~/1095/g' \
${WORKDIR}/openssl.tpl > ${DOM_CA}/openssl.cnf
# domain ca
cd ${DOM_CA}
# the domain ca key doesn't get a passphrase:
openssl genrsa -out ${DOM_CA}/private/domain-ca.${DOMAIN}.key ${DOM_CA_KEYSIZE}
echo "${SECRET}" | openssl req -new -sha1 -days 1095 -passin fd:0 \
-key ${DOM_CA}/private/domain-ca.${DOMAIN}.key \
-out ${DOM_CA}/domain-ca.${DOMAIN}.csr \
-config ${DOM_CA}/openssl.cnf -batch
###################################################################
# sign the Domain CA with the Intermediate CA
###################################################################
mv ${DOM_CA}/domain-ca.${DOMAIN}.csr ${MID_CA}
cd ${MID_CA}
echo "${SECRET}" | openssl ca -extensions v3_ca -days 1825 \
-passin fd:0 \
-out ${MID_CA}/domain-ca.${DOMAIN}.crt \
-in ${MID_CA}/domain-ca.${DOMAIN}.csr \
-config ${MID_CA}/openssl.cnf -batch
mv ${MID_CA}/domain-ca.${DOMAIN}.crt ${DOM_CA}/domain-ca.${DOMAIN}.pem
mv ${MID_CA}/domain-ca.${DOMAIN}.csr ${DOM_CA}/domain-ca.${DOMAIN}.csr
cat ${DOM_CA}/domain-ca.${DOMAIN}.pem ${MID_CA}/intermediate-ca.${DOMAIN}.pem \
${ROOT_CA}/root-ca.${DOMAIN}.pem > ${DOM_CA}/${DOMAIN}-trust-chain.crt
###################################################################
# Create Server Certificates for hosts
###################################################################
while [ ! -z "$*" ]; do
HNAME=$1; shift 1
MY_CERT="${WORKDIR}/server_certificates/${HNAME}"
if [ ! -d ${MY_CERT} ];then mkdir -p ${MY_CERT};fi
sed -e "s/~LEVEL~//g" \
-e "s/~COMMON_NAME~/${HNAME}/g" \
-e "s/~TEXTLEVEL~/${CA_ORGUNIT}/g" \
-e "s/~EMAIL~/${CA_EMAIL}/g" \
-e 's/~DAYS~/365/g' \
${WORKDIR}/openssl.tpl > ${MY_CERT}/openssl.cnf
echo ${SECRET} | openssl genrsa -des3 -passout fd:0 -out ${MY_CERT}/${HNAME}.key ${HOST_KEYSIZE}
echo ${SECRET} | openssl req -new -key ${MY_CERT}/${HNAME}.key \
-passin fd:0 \
-out ${MY_CERT}/${HNAME}.csr \
-config ${MY_CERT}/openssl.cnf -batch
###################################################################
# Sign Server Certificate with Domain Cerificate Authority
###################################################################
mv ${MY_CERT}/${HNAME}.csr ${DOM_CA}
# sign server cert with intermediate cert
cd ${DOM_CA}
openssl ca -config ${DOM_CA}/openssl.cnf \
-policy policy_anything \
-out ${DOM_CA}/${HNAME}.crt \
-batch \
-infiles ${DOM_CA}/${HNAME}.csr
mv ${DOM_CA}/${HNAME}.crt ${MY_CERT}
mv ${DOM_CA}/${HNAME}.csr ${MY_CERT}
echo ${SECRET} | openssl pkcs12 -export -passin fd:0 -passout pass:$(secret) -out ${MY_CERT}/${HNAME}.pfx -inkey ${MY_CERT}/${HNAME}.key -in ${MY_CERT}/${HNAME}.crt -certfile ${DOM_CA}/${DOMAIN}-trust-chain.crt
done
exit 0;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment