Metadata-Version: 2.4
Name: certbot-dns-nicmanager
Version: 1.0.1
Summary: nicmanager AnycastDNS Authenticator plugin for Certbot
Author: Jochen Pylypiw
License: Apache-2.0
Project-URL: Homepage, https://github.com/jp1337/certbot-dns-nicmanager
Project-URL: Repository, https://github.com/jp1337/certbot-dns-nicmanager
Project-URL: Issues, https://github.com/jp1337/certbot-dns-nicmanager/issues
Project-URL: Changelog, https://github.com/jp1337/certbot-dns-nicmanager/blob/main/CHANGELOG.md
Keywords: certbot,letsencrypt,acme,dns-01,nicmanager,dns
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Plugins
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Security
Classifier: Topic :: System :: Installation/Setup
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.txt
License-File: NOTICE
Requires-Dist: certbot>=2.0.0
Requires-Dist: requests>=2.20.0
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: requests-mock; extra == "test"
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: types-requests; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Dynamic: license-file

# certbot-dns-nicmanager

[![CI](https://github.com/jp1337/certbot-dns-nicmanager/actions/workflows/ci.yml/badge.svg)](https://github.com/jp1337/certbot-dns-nicmanager/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/certbot-dns-nicmanager.svg)](https://pypi.org/project/certbot-dns-nicmanager/)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE.txt)

> **Status:** stable (1.0). Running in production — wildcard issuance + automatic
> renewal against the live nicmanager AnycastDNS API.

A [Certbot](https://certbot.eff.org/) DNS authenticator plugin for
[nicmanager](https://www.nicmanager.com/) **AnycastDNS**. It automates the
`dns-01` ACME challenge by creating, and then removing, the
`_acme-challenge` TXT record through the
[nicmanager API](https://api.nicmanager.com/docs/v1/) — which makes it possible
to issue **wildcard certificates** for domains hosted on nicmanager.

There was no Certbot plugin for the nicmanager API, and the `lego`-based
multi-provider plugins do not yet support nicmanager's current API. This plugin
fills that gap with a small, dependency-light, well-tested implementation.

## Why DNS-01 (and not HTTP-01)?

`dns-01` is the only ACME challenge type that can issue **wildcard**
certificates, and it does not require any inbound HTTP reachability. It also
keeps your individual service hostnames out of the public
[Certificate Transparency](https://certificate.transparency.dev/) logs that a
per-host `http-01` certificate would expose.

## Installation

```bash
pip install certbot-dns-nicmanager
```

> Install the plugin into the **same** Python environment as Certbot. If you
> installed Certbot via `snap`, install the plugin with
> `snap install certbot-dns-nicmanager` once it is published there, or run
> Certbot from a `pip` environment that contains both packages.

Verify it is registered:

```bash
certbot plugins
# ... should list:  * dns-nicmanager
```

## Credentials

This plugin authenticates against the nicmanager API with HTTP Basic auth.
The strongly recommended setup is a dedicated **API-ACME account**, which
nicmanager restricts to managing only the `_acme-challenge.<zone>` TXT record:

| Module           | Rights                                  |
| ---------------- | --------------------------------------- |
| Webfrontend      | –                                       |
| Account settings | –                                       |
| Domains          | –                                       |
| Nameserver       | View, Manage (create, edit, delete)     |
| Domainsecurity   | –                                       |
| Other modules    | –                                       |

Because such an account can touch nothing but the challenge record, a leaked
credential cannot be used to hijack other records, transfer domains, or read
account data. **Disable two-factor authentication** on the account used for
automation — the API would otherwise require a rotating TOTP code that cannot be
provided unattended.

Create an INI file, e.g. `~/.secrets/certbot/nicmanager.ini`:

```ini
# nicmanager API credentials used by Certbot
dns_nicmanager_username = mylogin.acmeuser
# Quote the password if it contains '#' — an unquoted '#' starts an INI comment.
dns_nicmanager_password = "0123456789abcdef0123456789abcdef"

# Optional. Defaults to https://api.nicmanager.com/v1
# dns_nicmanager_endpoint = https://api.nicmanager.com/v1

# Optional. Skip zone detection and always use this zone.
# dns_nicmanager_zone = example.com
```

The `username` is `login.username` (or the account email). Zone detection works
without any read access, so `dns_nicmanager_zone` is only needed in unusual
multi-zone-suffix setups.

The `username` is either `login.username` or the account email address, as
configured in nicmanager.

Protect this file:

```bash
chmod 600 ~/.secrets/certbot/nicmanager.ini
```

## Usage

```bash
# A single hostname
certbot certonly \
  --authenticator dns-nicmanager \
  --dns-nicmanager-credentials ~/.secrets/certbot/nicmanager.ini \
  -d example.com

# A wildcard (and the apex)
certbot certonly \
  --authenticator dns-nicmanager \
  --dns-nicmanager-credentials ~/.secrets/certbot/nicmanager.ini \
  -d 'example.com' -d '*.example.com'
```

### Command-line arguments

| Argument                                | Description                                                                 | Default |
| --------------------------------------- | --------------------------------------------------------------------------- | ------- |
| `--dns-nicmanager-credentials`          | Path to the nicmanager credentials INI file. **(required)**                 | –       |
| `--dns-nicmanager-propagation-seconds`  | Seconds to wait for DNS propagation before the ACME server checks the record. | `60`    |

## How it works

1. Certbot asks the plugin to create `_acme-challenge.<domain>` with the
   validation token.
2. The plugin determines the owning AnycastDNS zone **without reading it** — a
   restricted API-ACME account cannot read zones. It tries
   `POST /v1/anycast/<candidate>/records` against each candidate zone
   (most-specific first); a `403`/`404` skips to the next candidate, the first
   `2xx` wins. An explicit `dns_nicmanager_zone` short-circuits this. A `401`
   (genuine auth failure) is surfaced immediately.
3. nicmanager returns the new record's numeric `id`, which the plugin
   remembers.
4. After validation, the plugin removes the record via
   `DELETE /v1/anycast/<zone>/records/<id>`.

TTL is fixed at the API minimum of **900 seconds**.

> **Heads-up:** the API blocks the IP after too many failed logins. Make sure
> the password is correct (and any `#` in it is quoted in the INI, see below)
> before running at scale.

## Troubleshooting

Common failures, decoded (full details in
[`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md)):

| Response | Meaning | Fix |
| --- | --- | --- |
| `401 Authentication error` | Wrong username form or password | Match the username to the account's auth method: **email** for "E-Mail + Passwort" accounts, `login.username` otherwise. Disable 2FA. |
| `403 API usage not allowed` | Auth OK — API access not enabled | Ask nicmanager support to enable API access for the account. |
| `401 Too many invalid attempts` / no response (`000`) | IP rate-limited / firewall-blocked after failed logins | Stop and wait. **Never** loop over credential variants — it locks the IP. |

Key gotchas: the username form depends on the account's **active authentication
method** (email vs `login.username`); **2FA must be off**; a `#` in the password
must be **quoted** in the INI; and the restricted API-ACME account **cannot read
zones** (this plugin resolves the zone by create-attempt instead).

## Development

```bash
git clone https://github.com/jp1337/certbot-dns-nicmanager
cd certbot-dns-nicmanager
python -m venv .venv && . .venv/bin/activate
pip install -e '.[test,dev]'

pytest          # run the test suite
ruff check .    # lint
mypy certbot_dns_nicmanager
```

For the design and the reasoning behind it, see
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) and the Architecture Decision
Records in [`docs/decisions/`](docs/decisions/) (DNS-01-only, zone resolution
without zone reads, and the basic-auth username / cleanup-by-id decisions).

## License

[Apache License 2.0](LICENSE.txt)

This is an independent, community-maintained plugin and is not affiliated with
or endorsed by InterNexum GmbH / nicmanager or the EFF / Certbot project.
