genCA.sh 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #!/bin/bash
  2. # Config
  3. CA_NAME="ca"
  4. DAYS=1825
  5. ROOT_POLICY="policy_root"
  6. ROOT_EXT="v3_ca"
  7. INTER_POLICY="policy_inter"
  8. INTER_EXT="v3_intermediate_ca"
  9. REQ_POLICY="policy_req"
  10. REQ_EXT="v3_req"
  11. PASS_DIR="${HOME}/.ansible/tls"
  12. ORG="Zi3"
  13. function makeDirExist {
  14. if [ -d "${1}" ] || [ "${1}" == "." ]; then
  15. return
  16. fi
  17. mkdir "${1}"
  18. if [ -n "${2}" ]; then
  19. chmod "${2}" "${1}"
  20. fi
  21. if [ -n "${3}" ]; then
  22. chown "${3}" "${1}"
  23. fi
  24. }
  25. # Decide what we're doing
  26. GEN_CA=1
  27. GEN_CERT=0
  28. if basename "${0}" | grep -q -i genCert; then
  29. GEN_CA=0
  30. GEN_CERT=1
  31. fi
  32. # Support intermediate CAs
  33. INTER="${1}"
  34. if [ -n "${INTER}" ] && [ "${INTER}" != "@" ]; then
  35. if [ ! -d "${INTER}" ]; then
  36. if [ ! -e $"${INTER}" ] && [ $GEN_CA -gt 0 ]; then
  37. echo "Creating intermediate CA directory: ${INTER}"
  38. makeDirExist "${INTER}" '0755'
  39. else
  40. echo "Intermediate CA directory does not exist: ${INTER}" 1>&2
  41. exit 1
  42. fi
  43. fi
  44. export CA_DIR="${INTER}"
  45. PRE_DASH="${INTER}-"
  46. PRE_DIR="${INTER}/"
  47. else
  48. export CA_DIR="@"
  49. INTER=""
  50. PRE_DASH=""
  51. PRE_DIR=""
  52. fi
  53. # Support alternate OUs
  54. if [ -z "${OU}" ]; then
  55. OU="${INTER}"
  56. fi
  57. # Calculate all our file paths
  58. CONF="openssl.conf"
  59. CA_CERT="${PRE_DIR}${CA_NAME}.pem"
  60. CERTS="${PRE_DIR}certs"
  61. KEYS="${PRE_DIR}keys"
  62. DB_DIR="${PRE_DIR}db"
  63. CRL="${DB_DIR}/crl/number"
  64. INDEX="${DB_DIR}/index.txt"
  65. SERIAL="${DB_DIR}/serial"
  66. # Ensure the passphrase file is available
  67. PASS_KEY="${PASS_DIR}/${PRE_DASH}key.pwd"
  68. PASS_CA="${PASS_DIR}/${PRE_DASH}ca-key.pwd"
  69. if [ $GEN_CA -gt 0 ]; then
  70. PASS_KEY="${PASS_DIR}/${PRE_DASH}ca-key.pwd"
  71. PASS_CA="${PASS_DIR}/ca-key.pwd"
  72. fi
  73. if [ ! -r "${PASS_KEY}" ]; then
  74. echo "Please create passphrase file: ${PASS_KEY}" 1>&2
  75. exit 3
  76. fi
  77. # If we're generating a normal certificate we need a name
  78. if [ $GEN_CERT -gt 0 ]; then
  79. CN="${2}"
  80. if [ -z "${CN}" ]; then
  81. echo "Certificate name not specified" 1>&2
  82. echo "Usage: ${0} INTERMEDIATE COMMON_NAME" 1>&2
  83. exit 1
  84. fi
  85. CERT="${CERTS}/${CN}.pem"
  86. KEY="${KEYS}/${CN}.key"
  87. fi
  88. # If we're generating a CA we know the name
  89. if [ $GEN_CA -gt 0 ]; then
  90. if [ -z "${INTER}" ]; then
  91. CN="Root_CA"
  92. else
  93. CN="Intermediate_CA"
  94. fi
  95. CERT="${CA_CERT}"
  96. KEY="${KEYS}/${CA_NAME}.key"
  97. # If we're signing with the root override the CA_CERT path
  98. CA_CERT="${CA_NAME}.pem"
  99. fi
  100. # Pick a subject
  101. if [ -n "${OU}" ]; then
  102. SUBJECT="/O=${ORG}/OU=${OU}/CN=${CN}"
  103. else
  104. SUBJECT="/O=${ORG}/CN=${CN}"
  105. fi
  106. # Remind admins what is happening
  107. if [ $GEN_CA -gt 0 ]; then
  108. echo
  109. echo "Generating new CA at ${PWD}/${PRE_DIR}"
  110. echo
  111. fi
  112. if [ $GEN_CERT -gt 0 ]; then
  113. echo
  114. echo "Generating certificate for ${CN} with ${INTER}"
  115. echo
  116. fi
  117. # Ensure this operation will be safe
  118. if [ ! -r "${CONF}" ]; then
  119. echo "Expected OpenSSL config: ${CONF}" 1>&2
  120. exit 1
  121. fi
  122. if [ -e "${CERT}" ]; then
  123. echo "Output certificate exists: ${CERT}" 1>&2
  124. exit 1
  125. fi
  126. if [ -e "${KEY}" ]; then
  127. echo "Output key exists: ${KEY}" 1>&2
  128. exit 1
  129. fi
  130. if [ $GEN_CA -gt 0 ]; then
  131. if [ -e "${SERIAL}" ] && [ "`cat "${SERIAL}"`" != "01" ]; then
  132. echo "Serial file exists and is not 0x01: ${SERIAL}" 1>&2
  133. exit 1
  134. fi
  135. if [ -e "${CRL}" ] && [ "`cat "${CRL}"`" != "01" ]; then
  136. echo "CRL number file exists and is not 0x01: ${CRL}" 1>&2
  137. exit 1
  138. fi
  139. if [ -e "${INDEX}" ] && [ -s "${INDEX}" ]; then
  140. echo "Index file exists and is not empty: ${INDEX}" 1>&2
  141. exit 1
  142. fi
  143. fi
  144. # Ensure the CA paths are available and valid
  145. if [ $GEN_CA -gt 0 ]; then
  146. makeDirExist "${CERTS}" '0755'
  147. makeDirExist "${KEYS}" '0700'
  148. # Setup the DB files
  149. makeDirExist "${DB_DIR}" '0755'
  150. echo "01" > "${SERIAL}"
  151. touch "${INDEX}"
  152. # And CRL for good measure
  153. makeDirExist "`dirname "${CRL}"`" '0755'
  154. echo "01" > "${CRL}"
  155. fi
  156. # Generate a new, encrypted key
  157. openssl ecparam -name secp521r1 -genkey | \
  158. openssl ec -aes256 -passout "file:${PASS_KEY}" -out "${KEY}"
  159. if [ ! -s "${KEY}" ]; then
  160. echo "Unable to generate private key" 1>&2
  161. exit 3
  162. fi
  163. # Generate and sign the certificate
  164. if [ -r "${CA_CERT}" ]; then
  165. CSR="${CERT}.csr"
  166. if [ -e "${CSR}" ]; then
  167. "CSR exists: ${CSR}" 1>&2
  168. exit 3
  169. fi
  170. # Generate a CSR
  171. openssl req -new \
  172. -config "${CONF}" \
  173. -subj "${SUBJECT}" \
  174. -key "${KEY}" \
  175. -passin "file:${PASS_KEY}" \
  176. -out "${CSR}"
  177. if [ ! -r "${CSR}" ]; then
  178. echo "Unable to generate CSR"
  179. exit 3
  180. fi
  181. # Remind admins what is happening
  182. echo
  183. echo "Signing ${CSR} with ${CA_CERT}"
  184. echo -en "Request:\n\t"
  185. openssl req -in "${CSR}" -text | grep 'Subject:'
  186. echo -en "CA:\n\t"
  187. openssl x509 -in "${CA_CERT}" -text | grep 'Subject:'
  188. echo
  189. # Sign with a CA
  190. DIR="${CA_DIR}"
  191. EXT="${REQ_EXT}"
  192. POLICY="${REQ_POLICY}"
  193. if [ "${DIR}" == "@" ] || [ $GEN_CA -gt 0 ]; then
  194. DIR="."
  195. EXT="${INTER_EXT}"
  196. POLICY="${INTER_POLICY}"
  197. fi
  198. CA_DIR="${DIR}" openssl ca -notext \
  199. -config "${CONF}" \
  200. -policy "${POLICY}" \
  201. -extensions "${EXT}" \
  202. -days "${DAYS}" \
  203. -passin "file:${PASS_CA}" \
  204. -in "${CERT}.csr" \
  205. -out "${CERT}"
  206. # Generate a chain certificate for validation
  207. if [ $GEN_CA -gt 0 ] && [ -r "${CERT}" ]; then
  208. cat "${CERT}" "${CA_CERT}" > "${PRE_DIR}ca-chain.pem"
  209. fi
  210. # Drop the CSR
  211. rm -f "${CERT}.csr"
  212. # Generate keys ansible can decrypt
  213. if [ -n "${INTER}" ] && [ $GEN_CA -le 0 ] && [ -s "${CERT}" ]; then
  214. echo
  215. echo "Encrypting ${KEY} for Ansible"
  216. echo
  217. ANSIBLE_KEY="`echo "${KEY}" | sed 's%.key$%.ansible%'`"
  218. openssl ec -in "${KEY}" -passin "file:${PASS_KEY}" -out "${ANSIBLE_KEY}"
  219. ansible-vault encrypt --encrypt-vault-id "${INTER}" "${ANSIBLE_KEY}"
  220. if ! head -n 1 "${ANSIBLE_KEY}" | grep -q "^\$ANSIBLE_VAULT"; then
  221. echo "Unable to generate ansible-encrypted key" 1>&2
  222. rm -f "${ANSIBLE_KEY}"
  223. fi
  224. fi
  225. else
  226. # Remind admins what is happening
  227. echo
  228. echo "Self-signing new root CA"
  229. echo
  230. # Root CA - self-sign
  231. openssl req -new -x509 \
  232. -config "${CONF}" \
  233. -subj "${SUBJECT}" \
  234. -extensions "${ROOT_EXT}" \
  235. -days "${DAYS}" \
  236. -key "${KEY}" \
  237. -passin "file:${PASS_KEY}" \
  238. -out "${CERT}"
  239. fi
  240. if [ ! -s "${CERT}" ]; then
  241. echo "Unable to generate certificate" 1>&2
  242. rm -f "${KEY}"
  243. exit 3
  244. fi