Skip to content

Commit

Permalink
Merge pull request #590 from buchdag/acmev2
Browse files Browse the repository at this point in the history
Switch to ACME v2
  • Loading branch information
buchdag authored Oct 16, 2019
2 parents c5b3715 + 2d41861 commit bcaefd1
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 59 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

It handles the automated creation, renewal and use of Let's Encrypt certificates for proxyed Docker containers.

Please note that [letsencrypt-nginx-proxy-companion does not work with ACME v2 endpoints yet](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion/issues/319).
Please note that **letsencrypt-nginx-proxy-companion** no longer supports ACME v1 endpoints. The last tagged version that supports ACME v1 is [v1.11](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion/releases/tag/v1.11.2).

### Features:
* Automated creation/renewal of Let's Encrypt (or other ACME CAs) certificates using [**simp_le**](https://github.com/zenhack/simp_le).
Expand Down
9 changes: 5 additions & 4 deletions app/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,11 @@ function check_default_cert_key {
source /app/functions.sh

if [[ "$*" == "/bin/bash /app/start.sh" ]]; then
acmev2_re='https://acme-.*v02\.api\.letsencrypt\.org/directory'
if [[ "${ACME_CA_URI:-}" =~ $acmev2_re ]]; then
echo "Error: ACME v2 API is not yet supported by simp_le."
echo "See https://github.com/zenhack/simp_le/issues/101"
acmev1_r='acme-(v01\|staging)\.api\.letsencrypt\.org'
if [[ "${ACME_CA_URI:-}" =~ $acmev1_r ]]; then
echo "Error: the ACME v1 API is no longer supported by simp_le."
echo "See https://github.com/zenhack/simp_le/pull/119"
echo "Please use one of Let's Encrypt ACME v2 endpoints instead."
exit 1
fi
check_docker_socket
Expand Down
4 changes: 3 additions & 1 deletion app/functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ function set_ownership_and_permissions {
return 1
fi

[[ "$(lc $DEBUG)" == true ]] && echo "Debug: checking $path ownership and permissions."

# Find the user numeric ID if the FILES_UID environment variable isn't numeric.
if [[ "$user" =~ ^[0-9]+$ ]]; then
user_num="$user"
Expand Down Expand Up @@ -329,7 +331,7 @@ function set_ownership_and_permissions {
fi
# If the path is a file, check and modify permissions if required.
elif [[ -f "$path" ]]; then
# Use different permissions for private files (private keys and ACME account keys) ...
# Use different permissions for private files (private keys and ACME account files) ...
if [[ "$path" =~ ^.*(default\.key|key\.pem|\.json)$ ]]; then
if [[ "$(stat -c %a "$path")" != "$f_perms" ]]; then
[[ "$(lc $DEBUG)" == true ]] && echo "Debug: setting $path permissions to $f_perms."
Expand Down
79 changes: 48 additions & 31 deletions app/letsencrypt_service
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
source /app/functions.sh

seconds_to_wait=3600
ACME_CA_URI="${ACME_CA_URI:-https://acme-v01.api.letsencrypt.org/directory}"
ACME_CA_URI="${ACME_CA_URI:-https://acme-v02.api.letsencrypt.org/directory}"
DEFAULT_KEY_SIZE=4096
REUSE_ACCOUNT_KEYS="$(lc ${REUSE_ACCOUNT_KEYS:-true})"
REUSE_PRIVATE_KEYS="$(lc ${REUSE_PRIVATE_KEYS:-false})"
Expand Down Expand Up @@ -158,7 +158,7 @@ function update_certs {
fi

test_certificate_varname="LETSENCRYPT_${cid}_TEST"
le_staging_uri="https://acme-staging.api.letsencrypt.org/directory"
le_staging_uri="https://acme-staging-v02.api.letsencrypt.org/directory"
if [[ $(lc "${!test_certificate_varname:-}") == true ]] || \
[[ "$ACME_CA_URI" == "$le_staging_uri" ]]; then
# Use staging Let's Encrypt ACME end point
Expand Down Expand Up @@ -215,27 +215,39 @@ function update_certs {
add_location_configuration "$domain" || reload_nginx
done

# The ACME account key full path is derived from the endpoint URI
# + the account alias (set to 'default' if no alias is provided)
account_key_dir="../accounts/${acme_ca_uri#*://}"
account_key_full_path="${account_key_dir}/${account_alias}.json"
if [[ -e "./account_key.json" ]] && [[ ! -e "./account_reg.json" ]]; then
# If there is an account key present without account registration, this is
# a leftover from the ACME v1 version of simp_le. Remove this account key.
rm -f ./account_key.json
[[ "$(lc $DEBUG)" == true ]] \
&& echo "Debug: removed ACME v1 account key $certificate_dir/account_key.json"
fi

# The ACME account key and registration full path are derived from the
# endpoint URI + the account alias (set to 'default' if no alias is provided)
account_dir="../accounts/${acme_ca_uri#*://}"
if [[ $REUSE_ACCOUNT_KEYS == true ]]; then
if [[ -f "$account_key_full_path" ]]; then
# If there is no symlink to the account key, create it
if [[ ! -L ./account_key.json ]]; then
ln -sf "$account_key_full_path" ./account_key.json \
&& set_ownership_and_permissions ./account_key.json
# If the symlink target the wrong account key, replace it
elif [[ "$(readlink -f ./account_key.json)" != "$account_key_full_path" ]]; then
ln -sf "$account_key_full_path" ./account_key.json \
&& set_ownership_and_permissions ./account_key.json
for type in "key" "reg"; do
file_full_path="${account_dir}/${account_alias}_${type}.json"
simp_le_file="./account_${type}.json"
if [[ -f "$file_full_path" ]]; then
# If there is no symlink to the account file, create it
if [[ ! -L "$simp_le_file" ]]; then
ln -sf "$file_full_path" "$simp_le_file" \
&& set_ownership_and_permissions "$simp_le_file"
# If the symlink target the wrong account file, replace it
elif [[ "$(readlink -f "$simp_le_file")" != "$file_full_path" ]]; then
ln -sf "$file_full_path" "$simp_le_file" \
&& set_ownership_and_permissions "$simp_le_file"
fi
fi
fi
done
fi

echo "Creating/renewal $base_domain certificates... (${hosts_array_expanded[*]})"
/usr/bin/simp_le \
-f account_key.json -f key.pem -f chain.pem -f fullchain.pem -f cert.pem \
-f account_key.json -f account_reg.json \
-f key.pem -f chain.pem -f fullchain.pem -f cert.pem \
$params_d_str \
--cert_key_size=$cert_keysize \
--server=$acme_ca_uri \
Expand All @@ -244,13 +256,17 @@ function update_certs {
simp_le_return=$?

if [[ $REUSE_ACCOUNT_KEYS == true ]]; then
# If the account key to be reused does not exist yet, copy it
# from the CWD and replace the file in CWD with a symlink
if [[ ! -f "$account_key_full_path" && -f ./account_key.json ]]; then
mkdir -p "$account_key_dir"
cp ./account_key.json "$account_key_full_path"
ln -sf "$account_key_full_path" ./account_key.json
fi
mkdir -p "$account_dir"
for type in "key" "reg"; do
file_full_path="${account_dir}/${account_alias}_${type}.json"
simp_le_file="./account_${type}.json"
# If the account file to be reused does not exist yet, copy it
# from the CWD and replace the file in CWD with a symlink
if [[ ! -f "$file_full_path" && -f "$simp_le_file" ]]; then
cp "$simp_le_file" "$file_full_path"
ln -sf "$file_full_path" "$simp_le_file"
fi
done
fi

popd || return
Expand All @@ -262,20 +278,21 @@ function update_certs {
else
create_links "$base_domain" "$domain" && should_reload_nginx='true' && should_restart_container='true'
fi
touch "${certificate_dir}/.companion"
set_ownership_and_permissions "${certificate_dir}/.companion"
done
# Make private key root readable only
for file in cert.pem key.pem chain.pem fullchain.pem account_key.json; do
touch "${certificate_dir}/.companion"
# Set ownership and permissions of the files inside $certificate_dir
for file in .companion cert.pem key.pem chain.pem fullchain.pem account_key.json account_reg.json; do
set_ownership_and_permissions "${certificate_dir}/${file}"
done
# Make the account key and its parent folders (up to
# /etc/nginx/certs/accounts included) root readable only
account_key_perm_path="/etc/nginx/certs/accounts/${acme_ca_uri#*://}/${account_alias}.json"
# Set ownership and permissions of the ACME account key and its parent
# folders (up to /etc/nginx/certs/accounts included)
account_key_perm_path="/etc/nginx/certs/accounts/${acme_ca_uri#*://}/${account_alias}_key.json"
until [[ "$account_key_perm_path" == /etc/nginx/certs ]]; do
set_ownership_and_permissions "$account_key_perm_path"
account_key_perm_path="$(dirname "$account_key_perm_path")"
done
# Set ownership and permissions of the ACME account registration
set_ownership_and_permissions "/etc/nginx/certs/accounts/${acme_ca_uri#*://}/${account_alias}_reg.json"
# Queue nginx reload if a certificate was issued or renewed
[[ $simp_le_return -eq 0 ]] && should_reload_nginx='true' && should_restart_container='true'
fi
Expand Down
2 changes: 1 addition & 1 deletion install_simp_le.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ apk add --update python3 git gcc musl-dev libffi-dev python3-dev openssl-dev
[[ -e /usr/bin/python ]] || ln -sf /usr/bin/python3 /usr/bin/python

# Get Let's Encrypt simp_le client source
branch="0.14.0"
branch="0.16.0"
mkdir -p /src
git -C /src clone --depth=1 --branch $branch https://github.com/zenhack/simp_le.git

Expand Down
4 changes: 2 additions & 2 deletions test/setup/setup-boulder.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

set -e

acme_endpoint='http://boulder:4000/directory'
acme_endpoint='http://boulder:4001/directory'

setup_boulder() {
export GOPATH=${TRAVIS_BUILD_DIR}/go
[[ ! -d $GOPATH/src/github.com/letsencrypt/boulder ]] \
&& git clone https://github.com/letsencrypt/boulder \
$GOPATH/src/github.com/letsencrypt/boulder
pushd $GOPATH/src/github.com/letsencrypt/boulder
git checkout release-2019-06-17
git checkout release-2019-10-07
if [[ "$(uname)" == 'Darwin' ]]; then
# Set Standard Ports
sed -i '' 's/ 5002/ 80/g' test/config/va.json
Expand Down
21 changes: 12 additions & 9 deletions test/tests/permissions_custom/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ wait_for_symlink "${domains[0]}" "$le_container_name"
# Array of folder paths to test
folders=( \
[0]="/etc/nginx/certs/accounts" \
[1]="/etc/nginx/certs/accounts/boulder:4000" \
[2]="/etc/nginx/certs/accounts/boulder:4000/directory" \
[1]="/etc/nginx/certs/accounts/boulder:4001" \
[2]="/etc/nginx/certs/accounts/boulder:4001/directory" \
[3]="/etc/nginx/certs/${domains[0]}" \
)

Expand All @@ -62,6 +62,7 @@ symlinks=( \
[2]="/etc/nginx/certs/${domains[0]}.chain.pem" \
[3]="/etc/nginx/certs/${domains[0]}.dhparam.pem" \
[4]="/etc/nginx/certs/${domains[0]}/account_key.json" \
[5]="/etc/nginx/certs/${domains[0]}/account_reg.json" \
)

# Test symlinks paths
Expand All @@ -75,8 +76,9 @@ symlinks=( \
# Array of private file paths to test
private_files=( \
[0]="/etc/nginx/certs/default.key" \
[1]="/etc/nginx/certs/accounts/boulder:4000/directory/default.json" \
[2]="/etc/nginx/certs/${domains[0]}/key.pem" \
[1]="/etc/nginx/certs/accounts/boulder:4001/directory/default_key.json" \
[2]="/etc/nginx/certs/accounts/boulder:4001/directory/default_reg.json" \
[3]="/etc/nginx/certs/${domains[0]}/key.pem" \
)

# Test private file paths
Expand All @@ -89,11 +91,12 @@ done

# Array of public files paths to test
public_files=( \
[0]="/etc/nginx/certs/${domains[0]}/cert.pem" \
[1]="/etc/nginx/certs/${domains[0]}/chain.pem" \
[2]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \
[3]="/etc/nginx/certs/default.crt" \
[4]="/etc/nginx/certs/dhparam.pem" \
[0]="/etc/nginx/certs/${domains[0]}/.companion" \
[1]="/etc/nginx/certs/${domains[0]}/cert.pem" \
[2]="/etc/nginx/certs/${domains[0]}/chain.pem" \
[3]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \
[4]="/etc/nginx/certs/default.crt" \
[5]="/etc/nginx/certs/dhparam.pem" \
)

# Test public file paths
Expand Down
21 changes: 12 additions & 9 deletions test/tests/permissions_default/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ wait_for_symlink "${domains[0]}" "$le_container_name"
# Array of folder paths to test
folders=( \
[0]="/etc/nginx/certs/accounts" \
[1]="/etc/nginx/certs/accounts/boulder:4000" \
[2]="/etc/nginx/certs/accounts/boulder:4000/directory" \
[1]="/etc/nginx/certs/accounts/boulder:4001" \
[2]="/etc/nginx/certs/accounts/boulder:4001/directory" \
[3]="/etc/nginx/certs/${domains[0]}" \
)

Expand All @@ -56,6 +56,7 @@ symlinks=( \
[2]="/etc/nginx/certs/${domains[0]}.chain.pem" \
[3]="/etc/nginx/certs/${domains[0]}.dhparam.pem" \
[4]="/etc/nginx/certs/${domains[0]}/account_key.json" \
[5]="/etc/nginx/certs/${domains[0]}/account_reg.json" \
)

# Test symlinks paths
Expand All @@ -69,8 +70,9 @@ symlinks=( \
# Array of private file paths to test
private_files=( \
[0]="/etc/nginx/certs/default.key" \
[1]="/etc/nginx/certs/accounts/boulder:4000/directory/default.json" \
[2]="/etc/nginx/certs/${domains[0]}/key.pem" \
[1]="/etc/nginx/certs/accounts/boulder:4001/directory/default_key.json" \
[2]="/etc/nginx/certs/accounts/boulder:4001/directory/default_reg.json" \
[3]="/etc/nginx/certs/${domains[0]}/key.pem" \
)

# Test private file paths
Expand All @@ -83,11 +85,12 @@ done

# Array of public files paths to test
public_files=( \
[0]="/etc/nginx/certs/${domains[0]}/cert.pem" \
[1]="/etc/nginx/certs/${domains[0]}/chain.pem" \
[2]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \
[3]="/etc/nginx/certs/default.crt" \
[4]="/etc/nginx/certs/dhparam.pem" \
[0]="/etc/nginx/certs/${domains[0]}/.companion" \
[1]="/etc/nginx/certs/${domains[0]}/cert.pem" \
[2]="/etc/nginx/certs/${domains[0]}/chain.pem" \
[3]="/etc/nginx/certs/${domains[0]}/fullchain.pem" \
[4]="/etc/nginx/certs/default.crt" \
[5]="/etc/nginx/certs/dhparam.pem" \
)

# Test public file paths
Expand Down
2 changes: 1 addition & 1 deletion test/tests/test-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function run_le_container {
$cli_args \
--env "DHPARAM_BITS=256" \
--env "DEBUG=true" \
--env "ACME_CA_URI=http://boulder:4000/directory" \
--env "ACME_CA_URI=http://boulder:4001/directory" \
--label com.github.jrcs.letsencrypt_nginx_proxy_companion.test_suite \
--network boulder_bluenet \
"$image" > /dev/null && echo "Started letsencrypt container for test ${name%%_2*}"
Expand Down

0 comments on commit bcaefd1

Please sign in to comment.