From e6d9e17d1e8ba40145c44a47b068d5d78c988619 Mon Sep 17 00:00:00 2001 From: eskimo Date: Sun, 21 Jun 2026 21:08:30 -0400 Subject: [PATCH] v3.0.0: authenticate with a yk_ App key, not email/app_password The email+app_password -> /api/v1/auth/login bearer mint was retired with personal app passwords (dns commit 834c90e). Switch to sending a yeil App key (yk__) directly as the Bearer token, which the DNS API's principal auth accepts. Single credential 'dns_yeil_api_key'; removed the login round-trip. BREAKING: existing credential files must replace email/app_password with an api_key (an App with DNS record-write permission, minted in team Apps). README + version bumped. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 33 ++++++++++++++++------------- certbot_dns_yeil/dns_yeil.py | 40 ++++++++++++++---------------------- setup.py | 2 +- 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 037b005..3f32cbb 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,11 @@ yeil DNS Authenticator plugin for [Certbot](https://certbot.eff.org/). -Authenticates against `dns.yeil.app`'s public API with an email and an -app password, then adds/removes TXT records to satisfy ACME DNS-01 -challenges. Works for any yeil user with an owned DNS zone; the -certbot host just needs HTTPS reachability to `dns.yeil.app`. +Authenticates to `dns.yeil.app`'s public API with a yeil **App key** +(`yk_...`) sent as a Bearer token, then adds/removes TXT records to +satisfy ACME DNS-01 challenges. Works for any yeil team with an App that +has DNS record-write permission; the certbot host just needs HTTPS +reachability to `dns.yeil.app`. Wildcard certs require DNS-01, so this plugin (or another DNS authenticator) is needed for `*.example.com`. @@ -18,16 +19,20 @@ pip install git+https://git.eskimo.dev/Yeil/certbot-dns-yeil.git ## Configuration -Create an app password at `https://account.yeil.app/security` and -drop it into a credentials INI: +In your yeil team settings, open **Apps**, create an App, grant it DNS +**record-write** permission on the zone(s) you'll issue certs for, and +mint a key. Drop the key (`yk_...`) into a credentials INI: ```ini -dns_yeil_email = you@yourdomain.com -dns_yeil_app_password = abcd-efgh-ijkl-mnop +dns_yeil_api_key = yk_xxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyy ``` `chmod 600` it. +> Migrating from 2.x: the old `dns_yeil_email` / `dns_yeil_app_password` +> login was retired with personal app passwords. Replace those two lines +> with a single `dns_yeil_api_key`. + Optional override if you're testing against a non-production host: ```ini @@ -55,13 +60,13 @@ certbot certonly \ ## How it works -The plugin logs in once per run (`POST /api/v1/auth/login`) and caches -the returned Bearer token. For each requested name it asks the API -which zone the account owns that covers the FQDN -(`GET /api/v1/zones?suffix_of=`), creates a TXT at +The plugin sends the App key as a Bearer token on every request. For +each requested name it asks the API which of the App's zones covers the +FQDN (`GET /api/v1/zones?suffix_of=`), creates a TXT at `_acme-challenge.` (`POST /api/v1/zones/{id}/records`), waits for propagation, and on cleanup deletes the record by id (`DELETE /api/v1/zones/{id}/records/{recordId}`). -The token is a real yeil session; revoking the app password (or -hitting `/logout`) invalidates it cleanly. +Revoking the App key (or disabling the App) in your team settings cuts +off access cleanly. The key only carries the DNS permissions you granted +the App, so scope it to record-write on just the zones you need. diff --git a/certbot_dns_yeil/dns_yeil.py b/certbot_dns_yeil/dns_yeil.py index a1cfd80..6712038 100644 --- a/certbot_dns_yeil/dns_yeil.py +++ b/certbot_dns_yeil/dns_yeil.py @@ -1,9 +1,9 @@ """DNS-01 authenticator plugin for Certbot using the yeil public API. -Authenticates against dns.yeil.app/api/v1/auth/login with an -email + app password, caches the Bearer token for the run, then -adds/removes TXT records via the public records API. Any yeil user -with an app password and an owned DNS zone can use it. +Authenticates to dns.yeil.app with a yeil App key (yk_...) sent as a +Bearer token, then adds/removes TXT records via the public records API. +Create an App with DNS record-write permission on your zone(s) in your +yeil team settings (the Apps tab) and put its key in the credentials file. The certbot host only needs HTTPS reachability to dns.yeil.app; no NetBird or shared admin key. @@ -34,10 +34,6 @@ class Authenticator(dns_common.DNSAuthenticator): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.credentials = None - # Bearer token cached for the lifetime of this plugin instance. - # The login route mints a 30-day session; we only need it for - # the duration of one certbot run. - self._token = None # (domain, validation_name, validation) -> (zone_id, record_id) self._records = {} @@ -59,8 +55,10 @@ class Authenticator(dns_common.DNSAuthenticator): "credentials", "yeil API credentials INI file", { - "email": "yeil account email (e.g. you@yourdomain.com)", - "app_password": "yeil app password (create one in account.yeil.app/security)", + "api_key": ( + "yeil App key (yk_...) with DNS record-write permission on " + "your zone(s); create an App under Apps in your team settings" + ), }, ) @@ -85,9 +83,7 @@ class Authenticator(dns_common.DNSAuthenticator): req.add_header("Content-Type", "application/json") req.add_header("Content-Length", str(len(data))) if auth: - if not self._token: - self._login() - req.add_header("Authorization", f"Bearer {self._token}") + req.add_header("Authorization", f"Bearer {self._api_key()}") try: with urlopen(req, timeout=HTTP_TIMEOUT) as resp: @@ -114,20 +110,14 @@ class Authenticator(dns_common.DNSAuthenticator): f"yeil dns API error ({method} {path}, {e.code}): {msg}" ) - def _login(self): - email = self.credentials.conf("email") - password = self.credentials.conf("app_password") - result = self._request( - "POST", - "/api/v1/auth/login", - body={"email": email, "password": password}, - auth=False, - ) - if not isinstance(result, dict) or "token" not in result: + def _api_key(self): + key = self.credentials.conf("api_key") + if not key: raise errors.PluginError( - "yeil dns API login returned no token" + "yeil credentials file is missing 'api_key' " + "(a yk_... App key with DNS record-write permission)" ) - self._token = result["token"] + return key # ── Zone resolution ──────────────────────────────────────────────── diff --git a/setup.py b/setup.py index cbe3e37..f14ff8f 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="certbot-dns-yeil", - version="2.0.0", + version="3.0.0", description="yeil DNS Authenticator plugin for Certbot", url="https://git.eskimo.dev/Yeil/certbot-dns-yeil", author="yeil",