create_server_certificate.sh 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #!/bin/bash
  2. set -u
  3. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  4. if [[ "$#" -eq 0 ]]; then
  5. cat <<-EOF
  6. To generate a server certificate, provide the domain name as a parameter:
  7. $(basename $0) www.my-domain.tdl
  8. $(basename $0) www.my-domain.tdl alternate.domain.tld
  9. You can also create certificates for wildcard domains:
  10. $(basename $0) '*.my-domain.tdl'
  11. EOF
  12. exit 0
  13. else
  14. DOMAIN="$1"
  15. ALTERNATE_DOMAINS="DNS:$( echo "$@" | sed 's/ /,DNS:/g')"
  16. fi
  17. ###############################################################################
  18. # Create a nginx container (which conveniently provides the `openssl` command)
  19. ###############################################################################
  20. CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.27.5)
  21. # Configure openssl
  22. docker exec $CONTAINER bash -c '
  23. mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null
  24. echo 1000 > /ca/serial
  25. touch /ca/index.txt
  26. cat > /ca/openssl.cnf <<-"OESCRIPT"
  27. [ ca ]
  28. # `man ca`
  29. default_ca = CA_default
  30. [ CA_default ]
  31. # Directory and file locations.
  32. dir = /ca
  33. certs = $dir/certs
  34. crl_dir = $dir/crl
  35. new_certs_dir = $dir/newcerts
  36. database = $dir/index.txt
  37. serial = $dir/serial
  38. RANDFILE = $dir/private/.rand
  39. # The root key and root certificate.
  40. private_key = /work/ca-root.key
  41. certificate = /work/ca-root.crt
  42. # SHA-1 is deprecated, so use SHA-2 instead.
  43. default_md = sha256
  44. name_opt = ca_default
  45. cert_opt = ca_default
  46. default_days = 10000
  47. preserve = no
  48. policy = policy_loose
  49. [ policy_loose ]
  50. countryName = optional
  51. stateOrProvinceName = optional
  52. localityName = optional
  53. organizationName = optional
  54. organizationalUnitName = optional
  55. commonName = supplied
  56. emailAddress = optional
  57. [ req ]
  58. # Options for the `req` tool (`man req`).
  59. default_bits = 2048
  60. distinguished_name = req_distinguished_name
  61. string_mask = utf8only
  62. # SHA-1 is deprecated, so use SHA-2 instead.
  63. default_md = sha256
  64. # Extension to add when the -x509 option is used.
  65. x509_extensions = v3_ca
  66. [ req_distinguished_name ]
  67. # See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
  68. countryName = Country Name (2 letter code)
  69. stateOrProvinceName = State or Province Name
  70. localityName = Locality Name
  71. 0.organizationName = Organization Name
  72. organizationalUnitName = Organizational Unit Name
  73. commonName = Common Name
  74. emailAddress = Email Address
  75. [ v3_ca ]
  76. # Extensions for a typical CA (`man x509v3_config`).
  77. subjectKeyIdentifier = hash
  78. authorityKeyIdentifier = keyid:always,issuer
  79. basicConstraints = critical, CA:true
  80. keyUsage = critical, digitalSignature, cRLSign, keyCertSign
  81. [ server_cert ]
  82. # Extensions for server certificates (`man x509v3_config`).
  83. basicConstraints = CA:FALSE
  84. nsCertType = server
  85. nsComment = server certificate generated for test purpose (nginx-proxy test suite)
  86. subjectKeyIdentifier = hash
  87. authorityKeyIdentifier = keyid,issuer:always
  88. keyUsage = critical, digitalSignature, keyEncipherment
  89. extendedKeyUsage = serverAuth
  90. [ san_env ]
  91. subjectAltName=${ENV::SAN}
  92. OESCRIPT
  93. '
  94. # shortcut for calling `openssl` inside the container
  95. function openssl {
  96. docker exec $CONTAINER openssl "$@"
  97. }
  98. function exitfail {
  99. echo
  100. echo ERROR: "$@"
  101. docker rm -f $CONTAINER
  102. exit 1
  103. }
  104. ###############################################################################
  105. # Setup Certificate authority
  106. ###############################################################################
  107. if ! [[ -f "$DIR/ca-root.key" ]]; then
  108. echo
  109. echo "> Create a Certificate Authority root key: $DIR/ca-root.key"
  110. openssl genrsa -out ca-root.key 2048
  111. [[ $? -eq 0 ]] || exitfail failed to generate CA root key
  112. fi
  113. # Create a CA root certificate
  114. if ! [[ -f "$DIR/ca-root.crt" ]]; then
  115. echo
  116. echo "> Create a CA root certificate: $DIR/ca-root.crt"
  117. openssl req -config /ca/openssl.cnf \
  118. -key ca-root.key \
  119. -new -x509 -days 3650 -subj "/O=nginx-proxy test suite/CN=www.nginx-proxy.tld" -extensions v3_ca \
  120. -out ca-root.crt
  121. [[ $? -eq 0 ]] || exitfail failed to generate CA root certificate
  122. # Verify certificate
  123. openssl x509 -noout -text -in ca-root.crt
  124. fi
  125. ###############################################################################
  126. # create server key and certificate signed by the certificate authority
  127. ###############################################################################
  128. echo
  129. echo "> Create a host key: $DIR/$DOMAIN.key"
  130. openssl genrsa -out "$DOMAIN.key" 2048
  131. echo
  132. echo "> Create a host certificate signing request"
  133. SAN="$ALTERNATE_DOMAINS" openssl req -config /ca/openssl.cnf \
  134. -key "$DOMAIN.key" \
  135. -new -out "/ca/$DOMAIN.csr" -days 1000 -extensions san_env -subj "/CN=$DOMAIN"
  136. [[ $? -eq 0 ]] || exitfail failed to generate server certificate signing request
  137. echo
  138. echo "> Create server certificate: $DIR/$DOMAIN.crt"
  139. SAN="$ALTERNATE_DOMAINS" openssl ca -config /ca/openssl.cnf -batch \
  140. -extensions server_cert \
  141. -extensions san_env \
  142. -in "/ca/$DOMAIN.csr" \
  143. -out "$DOMAIN.crt"
  144. [[ $? -eq 0 ]] || exitfail failed to generate server certificate
  145. # Verify host certificate
  146. #openssl x509 -noout -text -in "$DOMAIN.crt"
  147. docker rm -f $CONTAINER >/dev/null