Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge master → dev #703

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 51 additions & 26 deletions app/letsencrypt_service_data.tmpl
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
{{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }}
{{ $scopedContainersString := "" }}

{{ range $hosts, $containers := groupBy $ "Env.LETSENCRYPT_HOST" }}
{{ if trim $hosts }}
{{ range $container := $containers }}
{{ $cid := printf "%.12s" $container.ID }}
{{ if $CurrentContainer.Env.NETWORK_SCOPE }}
{{ range $containerNetwork := $container.Networks }}
{{ if eq $CurrentContainer.Env.NETWORK_SCOPE $containerNetwork.Name }}
{{ $scopedContainersString = (printf "%s %s" $scopedContainersString $cid) }}
{{ end }}
{{ end }}
{{ else }}
{{ $scopedContainersString = (printf "%s %s" $scopedContainersString $cid) }}
{{ end }}
{{ end }}
{{ end }}
{{ end }}

{{ $scopedContainersSlice := split (trim $scopedContainersString) " " }}

LETSENCRYPT_CONTAINERS=(
{{ range $hosts, $containers := groupBy $ "Env.LETSENCRYPT_HOST" }}
{{ if trim $hosts }}
{{ range $container := $containers }}
{{ if parseBool (coalesce $container.Env.LETSENCRYPT_SINGLE_DOMAIN_CERTS "false") }}
{{ range $host := split $hosts "," }}
{{ $host := trim $host }}
'{{ printf "%.12s" $container.ID }}_{{ sha1 $host }}'
{{ $cid := printf "%.12s" $container.ID }}
{{ if intersect $scopedContainersSlice (split $cid " ") }}
{{ if parseBool (coalesce $container.Env.LETSENCRYPT_SINGLE_DOMAIN_CERTS "false") }}
{{ range $host := split $hosts "," }}
'{{ printf "%s_%s" $cid (sha1 (trim $host)) }}'
{{ end }}
{{ else }}
'{{ $cid }}'
{{ end }}
{{ else }}
'{{ printf "%.12s" $container.ID }}'
{{ end }}
{{ end }}
{{ end }}
Expand All @@ -19,27 +43,28 @@ LETSENCRYPT_CONTAINERS=(
{{ $hosts := trimSuffix "," $hosts }}
{{ range $container := $containers }}
{{ $cid := printf "%.12s" $container.ID }}
{{ if parseBool (coalesce $container.Env.LETSENCRYPT_SINGLE_DOMAIN_CERTS "false") }}
{{ range $host := split $hosts "," }}
{{ $host := trim $host }}
{{ $host := trimSuffix "." $host }}
{{ $hostHash := sha1 $host }}
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_HOST=('{{ $host }}')
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_EMAIL="{{ $container.Env.LETSENCRYPT_EMAIL }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_KEYSIZE="{{ $container.Env.LETSENCRYPT_KEYSIZE }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_TEST="{{ $container.Env.LETSENCRYPT_TEST }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_ACCOUNT_ALIAS="{{ $container.Env.LETSENCRYPT_ACCOUNT_ALIAS }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_RESTART_CONTAINER="{{ $container.Env.LETSENCRYPT_RESTART_CONTAINER }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_MIN_VALIDITY="{{ $container.Env.LETSENCRYPT_MIN_VALIDITY }}"
{{ if intersect $scopedContainersSlice (split $cid " ") }}
{{ if parseBool (coalesce $container.Env.LETSENCRYPT_SINGLE_DOMAIN_CERTS "false") }}
{{ range $host := split $hosts "," }}
{{ $host := trim $host }}
{{ $host := trimSuffix "." $host }}
{{ $hostHash := sha1 $host }}
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_HOST=('{{ $host }}')
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_EMAIL="{{ $container.Env.LETSENCRYPT_EMAIL }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_KEYSIZE="{{ $container.Env.LETSENCRYPT_KEYSIZE }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_TEST="{{ $container.Env.LETSENCRYPT_TEST }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_ACCOUNT_ALIAS="{{ $container.Env.LETSENCRYPT_ACCOUNT_ALIAS }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_RESTART_CONTAINER="{{ $container.Env.LETSENCRYPT_RESTART_CONTAINER }}"
LETSENCRYPT_{{ $cid }}_{{ $hostHash }}_MIN_VALIDITY="{{ $container.Env.LETSENCRYPT_MIN_VALIDITY }}"
{{ end }}
{{ else }}
LETSENCRYPT_{{ $cid }}_HOST=( {{ range $host := split $hosts "," }}{{ $host := trim $host }}{{ $host := trimSuffix "." $host }}'{{ $host }}' {{ end }}) LETSENCRYPT_{{ $cid }}_EMAIL="{{ $container.Env.LETSENCRYPT_EMAIL }}"
LETSENCRYPT_{{ $cid }}_KEYSIZE="{{ $container.Env.LETSENCRYPT_KEYSIZE }}"
LETSENCRYPT_{{ $cid }}_TEST="{{ $container.Env.LETSENCRYPT_TEST }}"
LETSENCRYPT_{{ $cid }}_ACCOUNT_ALIAS="{{ $container.Env.LETSENCRYPT_ACCOUNT_ALIAS }}"
LETSENCRYPT_{{ $cid }}_RESTART_CONTAINER="{{ $container.Env.LETSENCRYPT_RESTART_CONTAINER }}"
LETSENCRYPT_{{ $cid }}_MIN_VALIDITY="{{ $container.Env.LETSENCRYPT_MIN_VALIDITY }}"
{{ end }}
{{ else }}
LETSENCRYPT_{{ $cid }}_HOST=( {{ range $host := split $hosts "," }}{{ $host := trim $host }}{{ $host := trimSuffix "." $host }}'{{ $host }}' {{ end }})
LETSENCRYPT_{{ $cid }}_EMAIL="{{ $container.Env.LETSENCRYPT_EMAIL }}"
LETSENCRYPT_{{ $cid }}_KEYSIZE="{{ $container.Env.LETSENCRYPT_KEYSIZE }}"
LETSENCRYPT_{{ $cid }}_TEST="{{ $container.Env.LETSENCRYPT_TEST }}"
LETSENCRYPT_{{ $cid }}_ACCOUNT_ALIAS="{{ $container.Env.LETSENCRYPT_ACCOUNT_ALIAS }}"
LETSENCRYPT_{{ $cid }}_RESTART_CONTAINER="{{ $container.Env.LETSENCRYPT_RESTART_CONTAINER }}"
LETSENCRYPT_{{ $cid }}_MIN_VALIDITY="{{ $container.Env.LETSENCRYPT_MIN_VALIDITY }}"
{{ end }}
{{ end }}
{{ end }}
17 changes: 17 additions & 0 deletions docs/Container-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,20 @@ You can also create test certificates per container (see [Test certificates](./L
* `REUSE_PRIVATE_KEYS` - Set it to `true` to make `simp_le` reuse previously generated private key for each certificate instead of creating a new one on certificate renewal. Recommended if you intend to use [HPKP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning) (please not however that HPKP has been deprecated by Google's Chrome and that its use is therefore not recommended).

* `DHPARAM_BITS` - Change the size of the Diffie-Hellman key generated by the container from the default value of 2048 bits. For example `--env DHPARAM_BITS=1024` to support some older clients like Java 6 and 7.

* `NETWORK_SCOPE` – The network name, that the container requesting a certificate MUST be connected to, in order to be discovered. You may find this option useful, when the host machine has multiple public IP addresses and you want to run separate nginx-proxy containers that will handle separate services with a proper networking isolation.

If you set this environment variable, you MUST connect the nginx-proxy container to the same network. For example:

```bash
$ docker run --detach \
--name nginx-proxy-letsencrypt \
--volumes-from nginx-proxy \
--volume /path/to/certs:/etc/nginx/certs:rw \
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
--network domains_group_a
--env "NETWORK_SCOPE=domains_group_a" \
jrcs/letsencrypt-nginx-proxy-companion
```

The created companion will discover only the containers, that are also connected to the `domains_group_a` network.
1 change: 1 addition & 0 deletions test/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ imageTests+=(
permissions_default
permissions_custom
symlinks
networks_segregation
'
)
11 changes: 11 additions & 0 deletions test/tests/networks_segregation/expected-std-out.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Started letsencrypt container for test networks_segregation
Started test web server for le1.wtf in net boulder_bluenet
Started test web server for le2.wtf in net le_test_other_net1
Started test web server for le3.wtf in net le_test_other_net2
le1.wtf is in boulder_bluenet, cert should be generated
Symlink to le1.wtf certificate has been generated.
The link is pointing to the file ./le1.wtf/fullchain.pem
le2.wtf is not in boulder_bluenet, cert should not be generated
Domain le2.wtf was not included in the service_data.
le3.wtf is not in boulder_bluenet, cert should not be generated
Domain le3.wtf was not included in the service_data.
71 changes: 71 additions & 0 deletions test/tests/networks_segregation/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/bin/bash

## Test for single domain certificates.

if [[ -z $TRAVIS ]]; then
le_container_name="$(basename ${0%/*})_$(date "+%Y-%m-%d_%H.%M.%S")"
else
le_container_name="$(basename ${0%/*})"
fi
desired_network="boulder_bluenet"
run_le_container ${1:?} "$le_container_name" "--env NETWORK_SCOPE=$desired_network"

# Create the $domains array from comma separated domains in TEST_DOMAINS.
IFS=',' read -r -a domains <<< "$TEST_DOMAINS"

# Cleanup function with EXIT trap
function cleanup {
# Remove any remaining Nginx container(s) silently.
for domain in "${domains[@]}"; do
docker rm --force "$domain" > /dev/null 2>&1
done
# Cleanup the files created by this run of the test to avoid foiling following test(s).
docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*'
# Stop the LE container
docker stop "$le_container_name" > /dev/null
# Drop temp network
docker network rm "le_test_other_net1" > /dev/null
docker network rm "le_test_other_net2" > /dev/null
}
trap cleanup EXIT

docker network create "le_test_other_net1" > /dev/null
docker network create "le_test_other_net2" > /dev/null

networks_map=("$desired_network" le_test_other_net1 le_test_other_net2)

# Run a separate nginx container for each domain in the $domains array.
# Start all the containers in a row so that docker-gen debounce timers fire only once.
i=0
for domain in "${domains[@]}"; do
docker run --rm -d \
--name "$domain" \
-e "VIRTUAL_HOST=${domain}" \
-e "LETSENCRYPT_HOST=${domain}" \
--network "${networks_map[i]}" \
nginx:alpine > /dev/null && echo "Started test web server for $domain in net ${networks_map[${i}]}"

i=$(( $i + 1 ))
done

i=0
for domain in "${domains[@]}"; do
if [ "${networks_map[i]}" != "$desired_network" ]; then
echo "$domain is not in $desired_network, cert should not be generated";

service_data="$(docker exec "$le_container_name" cat /app/letsencrypt_service_data)"
if grep -q "$domain" <<< "$service_data"; then
echo "Domain $domain is on data list, but MUST not!"
else
echo "Domain $domain was not included in the service_data."
fi
else
echo "$domain is in $desired_network, cert should be generated";

# Wait for a symlink at /etc/nginx/certs/$domain.crt
wait_for_symlink "$domain" "$le_container_name"
fi
# Stop the Nginx container silently.
docker stop "$domain" > /dev/null
i=$(( $i + 1 ))
done