Adding README.md

This commit is contained in:
László Károlyi 2024-04-13 16:10:55 +02:00
parent 98a49b788a
commit 4ca913ac3a
Signed by: karolyi
GPG Key ID: 2DCAF25E55735BFE
3 changed files with 88 additions and 27 deletions

87
README.md Normal file
View File

@ -0,0 +1,87 @@
# daneupdate
Python-based TLSA records updater hooking into certbot internals. It replaces the `certbot renew` command, managing renewals and proper certificate rollovers.
The earliest supported Python version is 3.9 now.
## About
This tool was born out of my need to rotate TLSA records for hostnames that serve TLS encrypted traffic. The idea came in light of the [jabber.ru MitM attack](https://notes.valdikss.org.ru/jabber.ru-mitm/). There are a couple other TLSA record managers out there (e.g. [letsdns](https://letsdns.org/), shuque's [generator](https://www.huque.com/bin/gen_tlsa), or letoams's [hash-slinger](https://github.com/letoams/hash-slinger)) but none of those served my needs properly, that is to handle rollovers with external daemons using the certificates, without having to hack around significantly. As mentioned in the [related certbot issue](https://github.com/certbot/certbot/issues/230#issuecomment-2047124291), this tool manages the rollover the following way, when a certificate renewal is due:
- Daneupdate (hooking into certbot) gets a newly signed key and certificate, puts it into the upcoming directory
- Immediately places a TLSA record next to the original one
- Waits for 24 hours (customizable) to pass for DNS caches to expire, then moves the certificate from the upcoming directory and set it as live (by symlinking to the latest version, also done by hooking into certbot internals)
- After another 24 hrs (also configurable), it is assumed that the respective daemons have reloaded and are using the new certificate
- At which point, the 'old' TLSA record can be cleared.
All of this happens upon repeated execution of `daneupdate renew`, for which cron is the ideal candidate.
At its current state, daneupdate uses the DNS update (with TSIG) method to delete/set TLSA records. It can be expanded in the future, but this fits my current needs. Feel free to open a PR if you have made code changes to fit your scenario.
## Installation
### FreeBSD
Just clone this repo and execute `scripts/install-freebsd.sh`. It will install daneupdate into a virtualenv and also use the FreeBSD ports patch to make certbot see the custom certificate directory paths.
### Linux
Using python and a virtualenv is the easiest way:
- Clone the repo (`master` branch should suffice), cd into its directory
- `python -m venv venv`
- `. venv/bin/activate`
- `python -m pip install -U pip wheel setuptools`
- `python -m pip install -e .`
- You can then symlink `venv/bin/daneupdate` (the full path of it) into `/usr/bin` or whatever path you prefer, as to be able to execute it without its full installation path.
Maybe an installer script for Linux would be nice, PRs for that are also welcome. I use FreeBSD as a server platform, and thus I use `install-freebsd.sh`, that does the job.
## Usage
### Configuration
After having the tool installed, make a copy of the [sample configuration](https://gitea.ksol.io/karolyi/daneupdate/src/branch/master/config.sample.yaml) file to a directory that will persist between installations — assuming you're using docker or some kinda [automated FreeBSD jail redeployment](https://gitea.ksol.io/karolyi/ansible-freebsd-jailhost-tools) like I do). This directory — and the configuration files within — is best be restricted to be read by root (or the process you use to renew certificates).
After having copied the sample configuration, use your infrastructure properties to set up proper values in the copied file.
### Certificate maintenance
You still have to use `certbot` for getting your initial certificates. This tool only manages the renewal of them.
For all supported commands, use `daneupdate -h` or `daneupdate -c <path-to-your-config-yaml> <command> -h` for help on the respective subcommands below.
If you have a certificate installed, you can use `daneupdate` to adopt the hostname associated with it:
#### Listing adoptable certificates
`daneupdate -c <path-to-your-config-yaml> list-adoptables` will list hostnames with certificates that can be adopted by daneupdate.
#### Adopting a certificate
`daneupdate -c <path-to-your-config-yaml> adopt hostname [hostname ...]` will adopt one or more hostnames from the aforementioned list. It will put its configuration file at the path you've configured in your `config.yaml`.
When having adopted a certificate, you can look into the runtime configuration and make changes to fit your needs. The structure of the file is explained at the commented version at the start of the runtime configuration.
Upon adoption, daneupdate will set up the initial TLSA records. You can skip that with specifying `-s` or `--skip-tlsa-update`. Then, you can use `update-tlsa` to add/update the respective records later on.
#### Renewing
`daneupdate -c <path-to-your-config-yaml> renew [hostname ...]`
This command will renew all the adopted certificates and set up TLSA records for them, when necessary. The necessity of a renewal is checked by using certbot internals (`should_update()`).
You can specify one or more hostnames, in which case only those will be processed for renewal.
This is the command you want to put into cron, replacing `certbot renew` with it.
#### Manually updating TLSA records
daneupdate has an `update-tlsa` command that will only run the TLSA updates on an adopted certificate, or all of them.
## Errors, bugs
This tool is not foolproof, so bugs might occur. Also, it is not responsible for a code exception due to misconfiguration. Having a proper infrastructure set up with the right configuration values and TCP access to your DNS server is your job.
That said, if you find something that you think is a bug that is not a result of a misconfiguration, feel free to open an issue, or submit a PR with a fix is even better.
## Donations
I have the following platforms, should you want to drop me a couple bucks :)
[![Liberapay](raw/branch/master/assets/liberapay.svg)](https://liberapay.com/karolyi/donate)
Buy me a coffee (or more): [https://www.buymeacoffee.com/karolyi](https://www.buymeacoffee.com/karolyi)
Paypal: [https://paypal.me/masterkarolyi](https://paypal.me/masterkarolyi)
I also used to have a Github: [https://github.com/sponsors/karolyi](https://github.com/sponsors/karolyi)
Patreon: [https://www.patreon.com/karolyi](https://www.patreon.com/karolyi)

1
assets/liberapay.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="83" height="30"><rect id="back" fill="#f6c915" x="1" y=".5" width="82" height="29" rx="4"/><svg viewBox="0 0 80 80" height="16" width="16" x="7" y="7"><g transform="translate(-78.37-208.06)" fill="#1a171b"><path d="m104.28 271.1c-3.571 0-6.373-.466-8.41-1.396-2.037-.93-3.495-2.199-4.375-3.809-.88-1.609-1.308-3.457-1.282-5.544.025-2.086.313-4.311.868-6.675l9.579-40.05 11.69-1.81-10.484 43.44c-.202.905-.314 1.735-.339 2.489-.026.754.113 1.421.415 1.999.302.579.817 1.044 1.546 1.395.729.353 1.747.579 3.055.679l-2.263 9.278"/><path d="m146.52 246.14c0 3.671-.604 7.03-1.811 10.07-1.207 3.043-2.879 5.669-5.01 7.881-2.138 2.213-4.702 3.935-7.693 5.167-2.992 1.231-6.248 1.848-9.767 1.848-1.71 0-3.42-.151-5.129-.453l-3.394 13.651h-11.162l12.52-52.19c2.01-.603 4.311-1.143 6.901-1.622 2.589-.477 5.393-.716 8.41-.716 2.815 0 5.242.428 7.278 1.282 2.037.855 3.708 2.024 5.02 3.507 1.307 1.484 2.274 3.219 2.904 5.205.627 1.987.942 4.11.942 6.373m-27.378 15.461c.854.202 1.91.302 3.167.302 1.961 0 3.746-.364 5.355-1.094 1.609-.728 2.979-1.747 4.111-3.055 1.131-1.307 2.01-2.877 2.64-4.714.628-1.835.943-3.858.943-6.071 0-2.161-.479-3.998-1.433-5.506-.956-1.508-2.615-2.263-4.978-2.263-1.61 0-3.118.151-4.525.453l-5.28 21.948"/></g></svg><text fill="#1a171b" text-anchor="middle" font-family="Helvetica Neue,Helvetica,Arial,sans-serif" font-weight="700" font-size="14" x="50" y="20">Donate</text></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,27 +0,0 @@
from copy import deepcopy
from certbot._internal.cli import prepare_and_parse_args
from certbot._internal.display.obj import set_display
from certbot._internal.main import make_displayer
from certbot._internal.plugins.disco import PluginsRegistry
# from certbot._internal.plugins.selection import choose_configurator_plugins
from certbot._internal.renewal import reconstitute, should_renew
from certbot._internal.storage import (
lineagename_for_filename, renewal_conf_files)
plugins = PluginsRegistry.find_all()
config = prepare_and_parse_args(plugins=plugins, args=['--test-cert'])
# config = prepare_and_parse_args(plugins, [])
with make_displayer(config=config) as displayer:
set_display(display=displayer)
# installer, authenticator = choose_configurator_plugins(
# config=config, plugins=plugins, verb='renew')
conf_files = renewal_conf_files(config=config)
lineage_config = deepcopy(x=config)
renewal_file = conf_files[0]
# lineagename = lineagename_for_filename(config_filename=renewal_file)
renewal_candidate = reconstitute(
config=lineage_config, full_path=renewal_file)
if renewal_candidate:
x = should_renew(config=lineage_config, lineage=renewal_candidate)
breakpoint()