diff --git a/.gitignore b/.gitignore index 68f590c..ccc4242 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ # Local .env + + +etc/ \ No newline at end of file diff --git a/README.md b/README.md index 0fcf2f0..07101ff 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,11 @@ Create certificates for HTTPS ```bash -chmod u+x ./scripts/generate-certificates.sh -./scripts/generate-certificates.sh +./scripts/pontsun generate-cert +``` +You need to add the generated certificate `etc/certificates/docker.rootCA.crt` to your browser authorities and trust related websites. +On OS X, this was automatically added to your keychain if the command above worked correctly. No need to do anything else. ``` -You need to add the generated certificate `certificates/docker.rootCA.crt` to your browser authorities and trust related websites. Start Traefik and Portainer ```bash diff --git a/build/build.sh b/build/build.sh new file mode 100755 index 0000000..bd42e76 --- /dev/null +++ b/build/build.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd $DIR +docker build -t liip/pontsun-helper:latest helper diff --git a/build/helper/Dockerfile b/build/helper/Dockerfile new file mode 100644 index 0000000..bb45979 --- /dev/null +++ b/build/helper/Dockerfile @@ -0,0 +1,5 @@ +FROM debian:stable-slim + +RUN apt-get update + +RUN apt-get install -y openssl gnutls-bin \ No newline at end of file diff --git a/config/openssl.cnf b/config/openssl.cnf index 5302f87..543dde8 100644 --- a/config/openssl.cnf +++ b/config/openssl.cnf @@ -11,5 +11,3 @@ keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [ alt_names ] -DNS.1 = ${ENV::PROJECT_NAME}.${ENV::PROJECT_EXTENSION} -DNS.2 = *.${ENV::PROJECT_NAME}.${ENV::PROJECT_EXTENSION} diff --git a/containers/.env.example b/containers/.env.example index 3153c74..6c8d4e6 100644 --- a/containers/.env.example +++ b/containers/.env.example @@ -5,7 +5,10 @@ PROJECT_NAME=pontsun PROJECT_EXTENSION=test PROJECT_DOMAIN=pontsun.test -### Images tags +# could also be ~/.pontsun +PONTSUN_DIR_ETC=../etc + +### Images tags PORTAINER_TAG=1.19.2 TRAEFIK_TAG=1.7.2-alpine diff --git a/containers/docker-compose.yml b/containers/docker-compose.yml index 867477d..53a1239 100644 --- a/containers/docker-compose.yml +++ b/containers/docker-compose.yml @@ -22,7 +22,7 @@ services: - '80:80' - '443:443' volumes: - - ../certificates/:/certs/ + - ${PONTSUN_DIR_ETC:-../etc/}/certificates/:/certs/ - /var/run/docker.sock:/var/run/docker.sock labels: - 'traefik.enable=true' diff --git a/etc/.gitkeep b/etc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/env.sh b/scripts/env.sh new file mode 100644 index 0000000..eb6b348 --- /dev/null +++ b/scripts/env.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +export PONTSUN_DIR=${PONTSUN_DIR:-$DIR/../} +export PONTSUN_DIR_ETC=${PONTSUN_DIR_ETC:-$PONTSUN_DIR/etc/} + +# Load env file +set -a +# load env variables but only if not set already +test -f $PONTSUN_DIR/containers/.env && source <(grep -v '^\s*#' $PONTSUN_DIR/containers/.env | sed -E 's|^ *([^=]+)=(.*)$|: ${\1=\2}; export \1|g') + diff --git a/scripts/generate-certificates.sh b/scripts/generate-certificates.sh index d864843..7015b3f 100755 --- a/scripts/generate-certificates.sh +++ b/scripts/generate-certificates.sh @@ -1,25 +1,13 @@ -#!/bin/bash -set -e +#!/usr/bin/env bash -# Load env file -set -a -test -f $(dirname $0)/../containers/.env && source $(dirname $0)/../containers/.env -set +a -cd $(dirname $0)/../certificates +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -if [ -f $PROJECT_NAME.crt ]; then - echo "Certificate already exists." -else - subj="/C=CH/ST=FR/L=Fribourg/O=Liip/OU=Pontsun/CN=$PROJECT_NAME.$PROJECT_EXTENSION" +. $DIR/env.sh - openssl genrsa -out $PROJECT_NAME.rootCA.key 4096 - openssl req -x509 -new -nodes -key $PROJECT_NAME.rootCA.key -sha256 -days 1024 -out $PROJECT_NAME.rootCA.crt -subj "$subj" +mkdir -p $PONTSUN_DIR_ETC/certificates/ - openssl genrsa -out $PROJECT_NAME.key 4096 - openssl req -new -sha256 -subj "$subj" -key $PROJECT_NAME.key -out $PROJECT_NAME.csr -config ../config/openssl.cnf - openssl x509 -req -in $PROJECT_NAME.csr -CA $PROJECT_NAME.rootCA.crt -CAkey $PROJECT_NAME.rootCA.key -CAcreateserial -out $PROJECT_NAME.crt -days 365 -extensions v3_req -extfile ../config/openssl.cnf - - cat $PROJECT_NAME.crt $PROJECT_NAME.key > $PROJECT_NAME.pem - chmod 600 $PROJECT_NAME.key $PROJECT_NAME.pem -fi +docker run --rm -v $DIR/../:/generate/ -v $PONTSUN_DIR_ETC/certificates/:/certs/ -it docker.gitlab.liip.ch/druids/docker-toolbox/pontsun-helper:latest /generate/scripts/helper/docker-generate-certificates.sh $1 +if [[ "$OSTYPE" == "darwin"* ]]; then + $DIR/install-cert-macos.sh $PONTSUN_DIR_ETC/certificates/$PROJECT_NAME.rootCA.crt +fi \ No newline at end of file diff --git a/scripts/helper/docker-generate-certificates.sh b/scripts/helper/docker-generate-certificates.sh new file mode 100755 index 0000000..903c571 --- /dev/null +++ b/scripts/helper/docker-generate-certificates.sh @@ -0,0 +1,59 @@ +#!/bin/bash +set -e + +# Load env file +set -a +test -f $(dirname $0)/../../containers/.env && source $(dirname $0)/../../containers/.env +set +a + +# check if there are certs in the local directory +cd /certs/ +if [ -f $PROJECT_NAME.crt ] && [ -z $1 ]; then + echo "Certificate already exists in local certificates directory." +else + if [ -f $PROJECT_NAME.crt ]; then + # get existing alt names from the current cert, so that we can reuse them + EXISTING_ALT_NAMES=$(certtool -i < /certs/$PROJECT_NAME.crt | grep DNSname | cut -f 2 -d ":" | sed -e 's/^[[:space:]]*//') + ALT_NAMES=${EXISTING_ALT_NAMES} + else + ALT_NAMES=$PROJECT_NAME.$PROJECT_EXTENSION + ALT_NAMES=${ALT_NAMES}$'\n'*.$PROJECT_NAME.$PROJECT_EXTENSION + fi + # add additional altnames + if [[ ! -z $1 ]]; then + ALT_NAMES=${ALT_NAMES}$'\n'$1 + ALT_NAMES=${ALT_NAMES}$'\n'*.$1 + fi + + # sort them and make them uniq to avoid duplicates + ALT_NAMES=$(echo $"${ALT_NAMES}" | sort | uniq) + EXISTING_ALT_NAMES=$(echo $"${EXISTING_ALT_NAMES}" | sort | uniq) + + if [[ $ALT_NAMES == $EXISTING_ALT_NAMES ]]; then + echo "Certificate wouldn't change, don't generate a new one." + exit 0; + fi + + I=1 + #write the correct config lines + while read -r line; do + if [[ ! -z $line ]]; then + ALT_NAMES_CONFIG=$ALT_NAMES_CONFIG$'\n'"DNS.$I = $line" + ((I++)) + fi + done <<< "$ALT_NAMES" + + subj="/C=CH/ST=FR/L=Fribourg/O=Liip/CN=$PROJECT_NAME.$PROJECT_EXTENSION" + # don't regenerate rootCA, if it already exists + if [ ! -f $PROJECT_NAME.rootCA.key ]; then + openssl genrsa -out $PROJECT_NAME.rootCA.key 4096 + openssl req -x509 -new -nodes -key $PROJECT_NAME.rootCA.key -sha256 -days 1024 -out $PROJECT_NAME.rootCA.crt -subj "$subj" + fi + openssl genrsa -out $PROJECT_NAME.key 4096 + openssl req -new -sha256 -subj "$subj" -key $PROJECT_NAME.key -out $PROJECT_NAME.csr -config <(cat /generate/config/openssl.cnf <(printf "$ALT_NAMES_CONFIG")) + openssl x509 -req -in $PROJECT_NAME.csr -CA $PROJECT_NAME.rootCA.crt -CAkey $PROJECT_NAME.rootCA.key -CAcreateserial -out $PROJECT_NAME.crt -days 365 -extensions v3_req -extfile <(cat /generate/config/openssl.cnf <(printf "$ALT_NAMES_CONFIG")) + + cat $PROJECT_NAME.crt $PROJECT_NAME.key > $PROJECT_NAME.pem + chmod 600 $PROJECT_NAME.key $PROJECT_NAME.pem +fi + diff --git a/scripts/install-cert-macos.sh b/scripts/install-cert-macos.sh new file mode 100755 index 0000000..6d62009 --- /dev/null +++ b/scripts/install-cert-macos.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# base from https://gist.github.com/koop/84254d5214495e6fc49db3284c9b7772 +# Usage +# $ ./install-cert-macos.sh "/path/to/cert" + +CERT_PATH=$1 + + + +# First, grab the SHA-1 from the provided SSL cert. +CERT_SHA1=$(openssl x509 -in "$CERT_PATH" -sha1 -noout -fingerprint | cut -d "=" -f2 | sed "s/://g") + +# Next, grab the SHA-1s of any standard.dev certs in the keychain. +# Don't return an error code if nothing is found. +EXISTING_CERT_SHAS=$(security find-certificate -a -c "$PROJECT_NAME.$PROJECT_EXTENSION" -Z /Library/Keychains/System.keychain | grep "SHA-1") || true +echo "$EXISTING_CERT_SHAS" | grep -q "$CERT_SHA1" || { + echo "Installing $CERT_PATH into your Keychain" + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$CERT_PATH" +} \ No newline at end of file diff --git a/scripts/pontsun b/scripts/pontsun new file mode 100755 index 0000000..837356b --- /dev/null +++ b/scripts/pontsun @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +show_help() { + echo "Usage: pontsun [options] []" + echo + echo " -h Print this help." + echo + echo "Common commands:" + echo " generate-cert [host] Generates needed ssl certificates" +} + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +while getopts "hv" opt; do + case "$opt" in + h*) + show_help + exit 0 + ;; + esac +done + +shift $((OPTIND-1)) + +[ "${1:-}" = "--" ] && shift + +if [ -z $1 ]; then + show_help + exit 0 +fi + +case "$1" in + generate-cert) + $DIR/generate-certificates.sh $2 + ;; + *) + echo "No such command: $1" + show_help + ;; +esac + +