Skip to content

Commit

Permalink
Better certificate generation
Browse files Browse the repository at this point in the history
  • Loading branch information
chregu committed Aug 20, 2019
1 parent be5b605 commit 02ddea4
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 29 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
*.pem
*.srl

# Local
# Local .env configuration
.env

# Here are the local configurations like certificates and more later
etc/
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,35 @@

## Installation

### .env file

Copy and adjust `containers/.env.example` to `containers/.env`

```
cp containers/.env.example containers/.env
```

### Generate SSL certificate

Create certificates for HTTPS
```bash
chmod u+x ./scripts/generate-certificates.sh
./scripts/generate-certificates.sh
./scripts/generate-certicates.sh
```
You need to add the generated certificate `certificates/docker.rootCA.crt` to your browser authorities and trust related websites.
You need to add the generated certificate `etc/certificates/pontsun.rootCA.crt` to your browser authorities and trust related websites.

If you have [step-cli](https://smallstep.com/docs/cli/) or are on OS X, this should happen automatically.

### Setup local DNS

See

- [Docker installation for Mac](docs/docker-installation-for-mac.md)
- [Docker installation for Ubuntu](docs/docker-installation-for-ubuntu.md)

for now.

### Start pontsun with traefik and portainer

Start Traefik and Portainer
```bash
cd containers
docker-compose up -d
Expand Down
7 changes: 7 additions & 0 deletions build/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cd $DIR
docker build -t liip/pontsun-helper:latest helper
5 changes: 5 additions & 0 deletions build/helper/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM alpine:3.10

RUN set -ex; \
# Install Bash and OpenSSL
apk add --no-cache bash openssl
2 changes: 0 additions & 2 deletions config/openssl.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -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}
4 changes: 3 additions & 1 deletion containers/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
### Project settings

COMPOSE_PROJECT_NAME=traefik
PROJECT_NAME=pontsun
PROJECT_EXTENSION=test
Expand All @@ -12,6 +11,9 @@ PONTSUN_HTTPS_PORT=443
# name of the docker network used for pontsun
PONTSUN_NETWORK=pontsun

# Where to store local config files, could also be ~/.pontsun
PONTSUN_DIR_ETC=../etc

### Images tags
PORTAINER_TAG=1.19.2
TRAEFIK_TAG=1.7.2-alpine
2 changes: 1 addition & 1 deletion containers/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ services:
- '${PONTSUN_HTTP_PORT}:80'
- '${PONTSUN_HTTPS_PORT}:443'
volumes:
- ../certificates/:/certs/
- ${PONTSUN_DIR_ETC:-../etc/}/certificates/:/certs/
- /var/run/docker.sock:/var/run/docker.sock
labels:
- 'traefik.enable=true'
Expand Down
Empty file added etc/.gitkeep
Empty file.
39 changes: 19 additions & 20 deletions scripts/generate-certificates.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
#!/bin/bash
#!/usr/bin/env bash
set -e

# Load env file
set -a
test -f $(dirname $0)/../containers/.env && source $(dirname $0)/../containers/.env
set +a
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cd $(dirname $0)/../certificates
. $DIR/helper/env.sh

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"
mkdir -p $PONTSUN_DIR_ETC/certificates/

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"

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 $PONTSUN_DIR/:/generate/ -v $PONTSUN_DIR_ETC/certificates/:/certs/ -it liip/pontsun-helper:latest /generate/scripts/helper/docker-generate-certificates.sh $1
CERT_PATH=$PONTSUN_DIR_ETC/certificates/$PROJECT_NAME.rootCA.crt
# disable set -e, since which will return an exit code, when step is not installed
set +e
# check if step is installed and use that. https://smallstep.com/docs/cli/
STEP=$(which step)
set -e
if [[ ! -z $STEP ]]; then
if ! $STEP certificate verify $CERT_PATH 2> /dev/null; then
echo "Installing $CERT_PATH into your system truststore"
$STEP certificate install -all $CERT_PATH
fi
elif [[ "$OSTYPE" == "darwin"* ]]; then # use direct OS X methods, if step isn't installed
$PONTSUN_DIR/scripts/helper/install-cert-macos.sh $CERT_PATH
fi
59 changes: 59 additions & 0 deletions scripts/helper/docker-generate-certificates.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env 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

24 changes: 24 additions & 0 deletions scripts/helper/env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

PONTSUN_DIR_REL=${PONTSUN_DIR:-$DIR/../../}
PONTSUN_DIR="$( cd ${PONTSUN_DIR_REL} && pwd )"
PONTSUN_DIR_ETC=${PONTSUN_DIR_ETC:-$PONTSUN_DIR/etc/}

# Load env file
set -a
# load env variables but only if not set already

if [[ ! -f $PONTSUN_DIR/containers/.env ]]; then
RED='\033[0;31m'
NC='\033[0m' # No Color

printf "${RED}${PONTSUN_DIR}/containers/.env does not exist!${NC}\nPlease copy it with:\n"
printf "cp ${PONTSUN_DIR}/containers/.env.example ${PONTSUN_DIR}/containers/.env\n"
printf "and adjust it.\n"
exit 1
fi
test -f $PONTSUN_DIR/containers/.env && source <(grep -v '^\s*#' $PONTSUN_DIR/containers/.env | sed -E 's|^ *([^=]+)=(.*)$|: ${\1=\2}; export \1|g')

19 changes: 19 additions & 0 deletions scripts/helper/install-cert-macos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh
set -e

# 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"
}

0 comments on commit 02ddea4

Please sign in to comment.