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

Add support for certificates from Let's Encrypt. #13

Merged
merged 11 commits into from
Dec 13, 2024
Merged

Add support for certificates from Let's Encrypt. #13

merged 11 commits into from
Dec 13, 2024

Conversation

plietar
Copy link
Contributor

@plietar plietar commented Dec 6, 2024

This adds a new configuration option named acme and a new sub-command montagu renew-certificate. Using these will fetch a certificate from Let's Encrypt (or another ACME provider), inject it into the proxy container and finally reload nginx. The host machine needs to be configured to run the renew-certificate on a regular basis, using, for example, crontab or systemd timers.

The ACME protocol is handled by running certbot as its own short-lived container. Alternatives could have been a long-running container running a cron-like daemon, installing certbot inside the nginx container and using docker exec to run it, installing and running certbot directly on the host, using a Python implementation of the ACME protocol directly inside the montagu tool process.

The certbot container shares a volume with nginx to host the acme-challenge files on port 80. To allow nginx to start and serve these files before we have any certificate at all, the proxy generates a self-signed certificate on startup if none exist yet. This certificate would be replaced on the first renewal.

See vimc/montagu-proxy#87 for the proxy side of this, mapping the /.well-known/acme-challenge path to a directory on the file system.

While we support alternative ACME servers, in production we will probably stick to the default which uses Let's Encrypt. The configuration option makes it easier to trial the process using servers that aren't exposed publically, using a miniature ACME server such as pebble

In the future the ACME configuration block may be extended to support DNS challenges instead, allowing us to use this even on internal-only services. If and when this happens, we won't even need nginx to host acme-challenges and may be able to remove the need for the transient self-signed certificates.

Once we get more experience with this, we may also want to move some of this functionality into constellation, allowing it to be re-used in other projects.

This adds a new configuration option named `acme` and a new sub-command
`montagu renew-certificate`. Using these will fetch a certificate from
Let's Encrypt (or another ACME provider), inject it into the proxy
container and finally reload nginx. The host machine needs to be
configured to run the `renew-certificate` on a regular basis, using, for
example, crontab or systemd timers.

The ACME protocol is handled by running certbot as its own short-lived
container. Alternatives could have been a long-running container running
a cron-like daemon, installing certbot inside the nginx container and
using `docker exec` to run it, installing and running certbot directly
on the host, using a Python implementation of the ACME protocol directly
inside the montagu tool process.

The certbot container shares a volume with nginx to host the
acme-challenge files on port 80. To allow nginx to start and serve these
files before we have any certificate at all, the proxy generates a
self-signed certificate on startup if none exist yet. This certificate
would be replaced on the first renewal.

See vimc/montagu-proxy#87 for the proxy side of this, mapping the
`/.well-known/acme-challenge` path to a directory on the file system.

While we support alternative ACME servers, in production we will
probably stick to the default which uses Let's Encrypt. The
configuration option makes it easier to trial the process using servers
that aren't exposed publically, using a miniature ACME server such as
[pebble][pebble]

In the future the ACME configuration block may be extended to support
DNS challenges instead, allowing us to use this even on internal-only
services. If and when this happens, we won't even need nginx to host
acme-challenges and may be able to remove the need for the transient
self-signed certificates.

Once we get more experience with this, we may also want to move some of
this functionality into constellation, allowing it to be re-used in
other projects.

[pebble]: https://github.com/letsencrypt/pebble
@plietar plietar requested a review from richfitz December 6, 2024 18:45
DOCKER_MODE_SYMLINK = 0x8000000


def read_file(container, path, *, follow_links=False):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is similar to https://github.com/reside-ic/constellation/blob/master/constellation/docker_util.py#L184, but supports symbol links. I'll probably upstream that functionality at some point.

Copy link

codecov bot commented Dec 8, 2024

Codecov Report

Attention: Patch coverage is 87.35632% with 11 lines in your changes missing coverage. Please review.

Project coverage is 96.87%. Comparing base (f8fe27a) to head (0371e65).
Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
src/montagu_deploy/certbot.py 90.47% 1 Missing and 3 partials ⚠️
src/montagu_deploy/cli.py 75.00% 2 Missing and 2 partials ⚠️
src/montagu_deploy/config.py 80.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #13      +/-   ##
==========================================
- Coverage   99.36%   96.87%   -2.50%     
==========================================
  Files           4        5       +1     
  Lines         316      384      +68     
  Branches       36       51      +15     
==========================================
+ Hits          314      372      +58     
- Misses          0        5       +5     
- Partials        2        7       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@plietar plietar merged commit 662e6bf into main Dec 13, 2024
4 of 6 checks passed
@plietar plietar deleted the VIMC-7467 branch December 13, 2024 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants