Last active
July 7, 2020 03:32
-
-
Save QNimbus/19a53ce305e43b12434ddcac740e7bfe to your computer and use it in GitHub Desktop.
Short script to generate Docker server and client certificates to enable TLS communication
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
## | |
## Title: create_docker_certs.sh | |
## Description: Short script to generate Docker server and client certificates to enable TLS communication | |
## Author: B. van wetten | |
## Created date: 25-05-2020 | |
## Updated date: 25-05-2020 | |
## Version: 0.0.1 | |
## GitHub Gist: https://gist.github.com/QNimbus/19a53ce305e43b12434ddcac740e7bfe | |
## | |
## Usage: TODO | |
# https://dwheeler.com/essays/filenames-in-shell.html#ifs | |
IFS=$'\n\t' | |
# Prevents environment variables from corrupting script | |
# unset HOST | |
# Shell utilities | |
declare -x SH=$(which sh); [[ $? != 0 ]] && echo "Command 'sh' not found" >&2 && exit 1 | |
declare -x CAT=$(which cat); [[ $? != 0 ]] && echo "Command 'cat' not found" >&2 && exit 1 | |
declare -x TR=$(which tr); [[ $? != 0 ]] && echo "Command 'tr' not found" >&2 && exit 1 | |
declare -x RM=$(which rm); [[ $? != 0 ]] && echo "Command 'rm' not found" >&2 && exit 1 | |
declare -x FOLD=$(which fold); [[ $? != 0 ]] && echo "Command 'fold' not found" >&2 && exit 1 | |
declare -x HEAD=$(which head); [[ $? != 0 ]] && echo "Command 'head' not found" >&2 && exit 1 | |
declare -x FIND=$(which find); [[ $? != 0 ]] && echo "Command 'find' not found" >&2 && exit 1 | |
declare -x CHMOD=$(which chmod); [[ $? != 0 ]] && echo "Command 'chmod' not found" >&2 && exit 1 | |
declare -x GETOPT=$(which getopt); [[ $? != 0 ]] && echo "Command 'getopt' not found" >&2 && exit 1 | |
declare -x DOCKER=$(which docker); [[ $? != 0 ]] && echo "Command 'docker' not found" >&2 && exit 1 | |
# Initialize variables | |
_PWD=$(pwd) | |
_UID=$(id -u) | |
_GID=$(id -g) | |
_ME=$(basename "${0}") | |
_CERT_PERMS="0444" | |
_KEY_PERMS="0400" | |
# Option strings | |
SHORT=hc: | |
LONG=help,common-name: | |
########################################################################## | |
# Init # | |
########################################################################## | |
# Get command line arguments | |
if [[ "${#}" -gt 0 ]] | |
then | |
getopt -T > /dev/null | |
if [ $? -eq 4 ]; then | |
# GNU enhanced getopt is available | |
_ARGS=$(${GETOPT} --name "$_ME" --long ${LONG} --options ${SHORT} -- "$@") | |
else | |
# Original getopt is available (no long option names, no whitespace, no sorting) | |
_ARGS=$(${GETOPT} ${SHORT} "$@") | |
fi | |
if [ $? -ne 0 ]; then | |
echo "$_ME: usage error (use -h for help)" >&2 | |
exit 2 | |
fi | |
fi | |
eval set -- "${_ARGS:-}" | |
############################################################################### | |
# Functions # | |
############################################################################### | |
# _print_usage() | |
# | |
# Usage: | |
# _print_usage | |
# | |
# Print the program usage information. | |
_print_usage() { | |
cat <<HEREDOC | |
____ ____ ____ ____ ___ ____ ___ ____ ____ _ _ ____ ____ ____ ____ ____ ___ ____ | |
| |__/ |___ |__| | |___ | \ | | | |_/ |___ |__/ | |___ |__/ | [__ | |
|___ | \ |___ | | | |___ ___ |__/ |__| |___ | \_ |___ | \ ___ |___ |___ | \ | ___] | |
Usage: | |
${_ME} -c commonname | |
${_ME} -h | |
Options: | |
-h, --help Show this screen | |
-c, --common-name Certificate common name | |
HEREDOC | |
exit ${1:-0} | |
} | |
# _openssl() | |
# | |
# Usage: | |
# _openssl variable value | |
# | |
# Runs the OpenSSL utility as a docker container | |
_openssl() { | |
$DOCKER run --rm -v "$_PWD:$_PWD" --user "${_UID}:${_GID}" --workdir="$_PWD" frapsoft/openssl "$@" | |
} | |
# _set_variable() | |
# | |
# Usage: | |
# _set_variable variable value | |
# | |
# Sets the variable to a value if not already set. Otherwise exits with an error message | |
_set_variable() | |
{ | |
local varname="$1" | |
shift | |
if [ -z "${!varname:-}" ]; then | |
# eval="${varname}=${@@Q}" | |
eval "$varname=\"$@\"" | |
else | |
echo "Error: $varname already set" | |
usage | |
fi | |
} | |
# _parse_commandline_arguments() | |
# | |
# Usage: | |
# _parse_commandline_arguments | |
# | |
# Parses and validates commandline arguments and populates appropriate variables. | |
_parse_commandline_arguments() | |
{ | |
while true; | |
do | |
case "${1:-}" in | |
-c|--common-name) | |
[[ -z "${2}" || "${2}" == *[[:space:]]* || "${2}" == -* ]] && { echo "$_ME: $1 needs a value" >&2; _print_usage 1; } | |
_set_variable CN "${2}" | |
shift 2 | |
;; | |
\?) echo "$_ME: Unknown option -$1" >&2; | |
exit 1 | |
;; | |
:) echo "$_ME: -$1 needs a value" >&2; | |
exit 1 | |
;; | |
*) shift | |
break | |
;; | |
esac | |
done | |
} | |
# _validate_parameters() | |
# | |
# Usage: | |
# _validate_parameters | |
# | |
# Performs several checks on the supplied command line arguments | |
_validate_parameters() { | |
# Check if common name is supplied | |
[[ -z "$CN" ]] && echo -e "Error: Forgot to specify a 'Common Name' attribute for the certificates\n" && _print_usage 1; | |
} | |
############################################################################### | |
# Main # | |
############################################################################### | |
# _main() | |
# | |
# Usage: | |
# _main [<options>] [<arguments>] | |
# | |
# Description: | |
# Entry point for the program, handling basic option parsing and dispatching. | |
_main() { | |
# Avoid complex option parsing when only one program option is expected. | |
if [[ "${@:-}" =~ -h|--help ]] | |
then | |
_print_usage | |
else | |
_parse_commandline_arguments "$@" | |
_validate_parameters | |
fi | |
PASSPHRASE=$(${CAT} /dev/urandom | ${TR} -dc 'a-zA-Z0-9' | ${FOLD} -w 32 | ${HEAD} -n 1) | |
# Extract certificate, key and certificate authority chain | |
_openssl genrsa -passout pass:"${PASSPHRASE}" -aes256 -out ca-key.pem 4096 | |
_openssl req -passin pass:"${PASSPHRASE}" -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem -subj "/C=NL/ST=Gelderland/L=Arnhem/O=Besquared/CN=${CN}" | |
_openssl genrsa -out server-key.pem 4096 | |
_openssl req -subj "/CN=${CN}" -sha256 -new -key server-key.pem -out server.csr | |
echo "subjectAltName = DNS:localhost,DNS:${CN},IP:127.0.0.1,IP:10.72.200.3" > extfile.cnf | |
echo "extendedKeyUsage = serverAuth" >> extfile.cnf | |
_openssl x509 -req -passin pass:"${PASSPHRASE}" -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf | |
_openssl genrsa -out key.pem 4096 | |
_openssl req -subj '/CN=client' -new -key key.pem -out client.csr | |
echo "extendedKeyUsage = clientAuth" > extfile-client.cnf | |
_openssl x509 -req -passin pass:"${PASSPHRASE}" -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf | |
# Cleanup | |
${RM} -rf client.csr server.csr extfile.cnf extfile-client.cnf | |
${CHMOD} -v 0400 ca-key.pem key.pem server-key.pem | |
${CHMOD} -v 0444 ca.pem server-cert.pem cert.pem | |
} | |
# Call `_main` after everything has been defined. | |
_main "$@" | |
exit 0; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment