Skip to content

Instantly share code, notes, and snippets.

@QNimbus
Last active July 7, 2020 03:32
Show Gist options
  • Save QNimbus/19a53ce305e43b12434ddcac740e7bfe to your computer and use it in GitHub Desktop.
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
#!/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