wip: letsencrypt

This commit is contained in:
Yann Autissier 2022-11-02 12:42:27 +00:00
parent 04df1bd919
commit 5d4d2de910
4 changed files with 116 additions and 37 deletions

View File

@ -53,7 +53,7 @@ Install myos on a server and manage server config with ansible.
* DEBUG
Show executed commands
Show executed commands.
```shell
$ make up DEBUG=true
@ -61,7 +61,7 @@ $ make up DEBUG=true
* DRYRUN
Do nothing, show commands instead of executing it
Do nothing, show commands instead of executing it.
```shell
$ make up DRYRUN=true
@ -69,7 +69,7 @@ $ make up DRYRUN=true
* VERBOSE
Show called functions
Show called functions.
```shell
$ make up VERBOSE=true
@ -81,6 +81,67 @@ $ make up VERBOSE=true
$ make print-VARIABLE
```
#### Setup
* SETUP_LETSENCRYPT
Generate ${DOMAIN} certificate files with letsencrypt.
By default, myos generates invalid ${DOMAIN} certificate files with openssl.
You can use letsencrypt instead, to generate valid wildcard certificate files.
To achieve this, you must add following DNS entries to domain ${DOMAIN} to prove you own it:
```
_acme-challenge.${DOMAIN} IN CNAME ${DOMAIN}.acme.${DOMAIN}.
acme.${DOMAIN}. IN NS certbot.${DOMAIN}.
certbot.${DOMAIN}. IN A ${DOCKER_HOST_INET4}
```
In this config, DOCKER_HOST_INET4 should be the external IP address of the server running certbot.
Port 53 of this IP address must be reachable from internet and point to this server.
If you want a simple DNS configuration to host all your services on the same server, you can setup following DNS config:
```
@ IN A ${DOCKER_HOST_INET4}
*.${DOMAIN}. IN CNAME ${DOMAIN}.
_acme-challenge.${DOMAIN} IN CNAME ${DOMAIN}.acme.${DOMAIN}.
acme.${DOMAIN}. IN NS ${DOMAIN}.
```
This will point domain ${DOMAIN} to the IP address ${DOCKER_HOST_INET4} of this server, and point all subdomains *.{DOMAIN} to the ip address pointed by ${DOMAIN}.
At this point, you should be able to generate a valid certificate for *.${DOMAIN} using certbot [dns standalone](https://github.com/siilike/certbot-dns-standalone) plugin.
This task is done automatically when creating the node stack if SETUP_LETSENCRYPT variable is not empty.
If you already launched myos node stack before, the ${DOMAIN} certificates has been automatically generated by openssl and you should remove them before trying to generate them with letsencrypt.
```
$ make node-down
$ docker volume rm node_myos
```
You can then test the letsencrypt certificate generation using DEBUG mode that force to use the letsencrypt staging server.
```
$ make node SETUP_LETSENCRYPT=true DEBUG=true
```
If letsencrypt certificate generation fails, you can retry the generation of a staging certificate.
```
$ make node-certbot-staging
```
Once the certificate generation is working, you can ask for a valid certificate.
```
$ make node-down
$ docker volume rm node_myos
$ make node SETUP_LETSENCRYPT=true
```
### Debug
* Show docker compose yaml config

View File

@ -41,7 +41,6 @@ CONFIG_REPOSITORY_URI ?= $(shell printf '$(CONFIG_REPOSITORY_URL)\n' |
CONFIG_REPOSITORY_URL ?= $(call pop,$(APP_UPSTREAM_REPOSITORY))/$(notdir $(CONFIG))
CONTEXT ?= ENV $(shell awk 'BEGIN {FS="="}; $$1 !~ /^(\#|$$)/ {print $$1}' .env.dist 2>/dev/null)
CONTEXT_DEBUG ?= MAKEFILE_LIST DOCKER_ENV_ARGS ENV_ARGS APPS GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME MAKE_DIR MAKE_SUBDIRS MAKE_CMD_ARGS MAKE_ENV_ARGS UID USER
CERTBOT ?=
DEBUG ?=
DOCKER ?= $(shell type -p docker)
DOMAIN ?= localhost

View File

@ -1,9 +1,9 @@
ENV_VARS += IPFS_DAEMON_ARGS IPFS_PROFILE IPFS_VERSION
IPFS_PROFILE ?= $(if $(filter-out amd64 x86_64,$(MACHINE)),lowpower,server)
IPFS_VERSION ?= 0.15.0
IPFS_VERSION ?= 0.16.0
.PHONY: bootstrap-stack-ipfs
bootstrap-stack-ipfs: ~/.ipfs
bootstrap-stack-ipfs: ~/.ipfs setup-sysctl
~/.ipfs:
mkdir -p ~/.ipfs

View File

@ -1,10 +1,11 @@
CMDS += node-exec stack-node-exec node-exec:% node-exec@% node-run node-run:% node-run@%
node ?= node/node
ENV_VARS += DOCKER_HOST_IFACE DOCKER_HOST_INET4 DOCKER_INTERNAL_DOCKER_HOST
SETUP_LETSENCRYPT ?=
# target bootstrap-stack-node: Fire node-certbot node-ssl-certs
.PHONY: bootstrap-stack-node
bootstrap-stack-node: docker-network-create-$(DOCKER_NETWORK_PUBLIC) $(if $(CERTBOT),node-certbot) node-ssl-certs
bootstrap-stack-node: docker-network-create-$(DOCKER_NETWORK_PUBLIC) $(if $(SETUP_LETSENCRYPT),node-certbot$(if $(DEBUG),-staging)) node-ssl-certs
# target node: Fire stack-node-up
.PHONY: node
@ -14,32 +15,44 @@ node: stack-node-up
.PHONY: node-%
node-%: stack-node-%;
# target node-ssl-certs: Create invalid ${DOMAIN}/privkey.pem and ${DOMAIN}/cert.pem certificate files
# target node-ssl-certs: Create invalid ${DOMAIN} certificate files with openssl
.PHONY: node-ssl-certs
node-ssl-certs:
docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/certs alpine \
[ -f /certs/live/$(DOMAIN)/cert.pem -a -f /certs/live/$(DOMAIN)/privkey.pem ] \
|| $(RUN) docker run --rm -e DOMAIN=$(DOMAIN) --mount source=$(NODE_DOCKER_VOLUME),target=/certs alpine sh -c "\
apk --no-cache add openssl \
&& mkdir -p /certs/live/${DOMAIN} \
&& { [ -f /certs/live/${DOMAIN}/privkey.pem ] || openssl genrsa -out /certs/live/${DOMAIN}/privkey.pem 2048; } \
&& openssl req -key /certs/live/${DOMAIN}/privkey.pem -out /certs/live/${DOMAIN}/cert.pem \
-addext extendedKeyUsage=serverAuth \
-addext subjectAltName=DNS:${DOMAIN} \
-subj \"/C=/ST=/L=/O=/CN=${DOMAIN}\" \
-x509 -days 365"
[ -f /certs/live/$(DOMAIN)/fullchain.pem -a -f /certs/live/$(DOMAIN)/privkey.pem ] \
|| $(RUN) docker run --rm \
-e DOMAIN=$(DOMAIN) \
--mount source=$(NODE_DOCKER_VOLUME),target=/certs \
alpine sh -c "\
apk --no-cache add openssl \
&& mkdir -p /certs/live/${DOMAIN} \
&& { [ -f /certs/live/${DOMAIN}/privkey.pem ] || openssl genrsa -out /certs/live/${DOMAIN}/privkey.pem 2048; } \
&& openssl req -key /certs/live/${DOMAIN}/privkey.pem -out /certs/live/${DOMAIN}/cert.pem \
-addext extendedKeyUsage=serverAuth \
-addext subjectAltName=DNS:${DOMAIN},DNS:*.${DOMAIN} \
-subj \"/C=/ST=/L=/O=/CN=${DOMAIN}\" \
-x509 -days 365 \
&& rm -f /certs/live/${DOMAIN}/fullchain.pem \
&& ln -s cert.pem /certs/live/${DOMAIN}/fullchain.pem \
"
# target node-certbot: Create letsencrypt ${DOMAIN}/privkey.pem and ${DOMAIN}/cert.pem files
# target node-certbot: Create ${DOMAIN} certificate files with letsencrypt
.PHONY: node-certbot
node-certbot: node-docker-build-certbot
docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/certs alpine [ -f /certs/live/$(DOMAIN)/cert.pem -a -f /certs/live/$(DOMAIN)/privkey.pem ] \
|| $(RUN) docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/etc/letsencrypt/ --mount source=$(NODE_DOCKER_VOLUME),target=/var/log/letsencrypt/ -e DOMAIN=$(DOMAIN) --network host node/certbot \
--non-interactive --agree-tos --email hostmaster@${DOMAIN} certonly \
--preferred-challenges dns --authenticator dns-standalone \
--dns-standalone-address=0.0.0.0 \
--dns-standalone-port=53 \
-d ${DOMAIN} \
-d *.${DOMAIN}
docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/certs alpine \
[ -f /certs/live/$(DOMAIN)/cert.pem -a -f /certs/live/$(DOMAIN)/privkey.pem ] \
|| $(RUN) docker run --rm \
--mount source=$(NODE_DOCKER_VOLUME),target=/etc/letsencrypt/ \
--mount source=$(NODE_DOCKER_VOLUME),target=/var/log/letsencrypt/ \
-e DOMAIN=$(DOMAIN) \
--network host \
node/certbot \
--non-interactive --agree-tos --email hostmaster@${DOMAIN} certonly \
--preferred-challenges dns --authenticator dns-standalone \
--dns-standalone-address=0.0.0.0 \
--dns-standalone-port=53 \
-d ${DOMAIN} \
-d *.${DOMAIN}
# target node-certbot-certificates: List letsencrypt certificates
.PHONY: node-certbot-certificates
@ -51,18 +64,24 @@ node-certbot-certificates: node-docker-build-certbot
node-certbot-renew: node-docker-build-certbot
docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/etc/letsencrypt/ --network host node/certbot renew
# target node-certbot-staging: Create staging letsencrypt ${DOMAIN}/privkey.pem and ${DOMAIN}/cert.pem files
# target node-certbot-staging: Create staging ${DOMAIN} certificate files with letsencrypt
.PHONY: node-certbot-staging
node-certbot-staging: node-docker-build-certbot
docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/certs alpine [ -f /certs/live/$(DOMAIN)/cert.pem -a -f /certs/live/$(DOMAIN)/privkey.pem ] \
|| $(RUN) docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/etc/letsencrypt/ --mount source=$(NODE_DOCKER_VOLUME),target=/var/log/letsencrypt/ -e DOMAIN=$(DOMAIN) --network host node/certbot \
--non-interactive --agree-tos --email hostmaster@${DOMAIN} certonly \
--preferred-challenges dns --authenticator dns-standalone \
--dns-standalone-address=0.0.0.0 \
--dns-standalone-port=53 \
--staging \
-d ${DOMAIN} \
-d *.${DOMAIN}
docker run --rm --mount source=$(NODE_DOCKER_VOLUME),target=/certs alpine \
[ -f /certs/live/$(DOMAIN)/cert.pem -a -f /certs/live/$(DOMAIN)/privkey.pem ] \
|| $(RUN) docker run --rm \
--mount source=$(NODE_DOCKER_VOLUME),target=/etc/letsencrypt/ \
--mount source=$(NODE_DOCKER_VOLUME),target=/var/log/letsencrypt/ \
-e DOMAIN=$(DOMAIN) \
--network host \
node/certbot \
--non-interactive --agree-tos --email hostmaster@${DOMAIN} certonly \
--preferred-challenges dns --authenticator dns-standalone \
--dns-standalone-address=0.0.0.0 \
--dns-standalone-port=53 \
--staging \
-d ${DOMAIN} \
-d *.${DOMAIN}
# target node-docker-build-%: Build % docker
.PHONY: node-docker-build-%