Skip to content

CertIntel DNS-01 plugin for Certbot

certbot-dns-certintel publishes and removes DNS-01 TXT challenge values through CertIntel. Certbot handles certificate orders, keys, files and renewal. This plugin does not install certificates or enroll a CertIntel agent.

Requires Linux/Unix, Python 3.10+, and Certbot 2.9 through 5.x. Tested with Certbot 5.8.0. Use Linux or WSL for Certbot; native Windows is not supported.

Download: use verified downloads, selecting certbot.

Install

Install Python with its venv support using your OS package manager. The commands below assume a root shell for the system paths under /opt, /etc and /var. For a non-root installation, use writable paths and the same account for renewal.

First complete the Linux/Unix verifier procedure in verified downloads. Use the wheel from the verified output directory, not a direct URL. For source release 0.1.1 the filename is shown below; use the exact verified filename for a later release.

python3 -m venv /opt/certintel-certbot
/opt/certintel-certbot/bin/python -m pip install \\
  ./verified/certbot/certbot_dns_certintel-0.1.1-py3-none-any.whl
/opt/certintel-certbot/bin/certbot plugins

Pip installs compatible dependencies too. Those dependencies are a separate supply-chain input; use your organization's approved index/constraints for reproducible installs. Pip does not verify the wheel's release attestation: the verifier must succeed first.

Confirm that dns-certintel appears. Always use this environment's certbot binary for issuance and renewal. A pip-installed plugin is not visible to a separate Certbot snap or system installation; no snap plugin is supplied.

Create the delegation and CNAME

In CertIntel, create a delegated DNS-01 record and save its UUID, update secret and full CNAME target. At your DNS provider, add the permanent CNAME:

_acme-challenge.example.com.  CNAME  YOUR-LABEL.dns01.certin.tel.

Use the exact target supplied by CertIntel. Wait until the CNAME resolves publicly. An apex/wildcard pair (example.com and *.example.com) shares one delegation. Other certificate names such as www.example.com require their own mapping and corresponding challenge CNAME. The CNAME target is not the certificate name.

Configure credentials

This Certbot plugin currently uses a JSON mapping file. It does not provide a Posh-ACME-style vault integration. Create a private directory:

install -d -m 700 /etc/certintel

Using a text editor, create /etc/certintel/delegations.json with your actual values. Do not leave the example UUID, label or secret unchanged:

{
  "apiBase": "https://api.certin.tel/api/v1",
  "delegations": {
    "example.com": {
      "delegationId": "11111111-1111-1111-1111-111111111111",
      "cnameTarget": "YOUR-LABEL.dns01.certin.tel",
      "apiKey": "YOUR-DELEGATION-UPDATE-SECRET"
    }
  }
}

Then restrict access:

chmod 600 /etc/certintel/delegations.json

The apiBase must include /api/v1; use a different HTTPS endpoint if needed. apiKey can also be a CertIntel DNS API key explicitly granted access to that delegation. Add sibling entries under delegations for multiple names, each with its own UUID, CNAME target and key. An entry can override apiBase for a different endpoint. Mapping keys exclude *. and _acme-challenge. and match certificate names exactly.

The renewal account needs read access to this file and write access to its directory for .certintel-locks. Keep the absolute file path stable for renewal.

Test against the staging CA

This example isolates staging state from production:

/opt/certintel-certbot/bin/certbot certonly \
  --authenticator dns-certintel \
  --dns-certintel-credentials /etc/certintel/delegations.json \
  --dns-certintel-propagation-seconds 60 \
  --config-dir /etc/letsencrypt-certintel-staging \
  --work-dir /var/lib/letsencrypt-certintel-staging \
  --logs-dir /var/log/letsencrypt-certintel-staging \
  --staging --agree-tos --email [email protected] \
  --cert-name example.com-staging \
  -d example.com -d '*.example.com'

Replace the domain and email. Quote wildcard names to prevent shell expansion. The default propagation wait is 60 seconds; increase it if DNS caching requires more time. Confirm successful issuance and removal of both TXT challenge values. Staging certificates are not publicly trusted.

Issue a production certificate

After staging succeeds, issue using Certbot's normal production directories:

/opt/certintel-certbot/bin/certbot certonly \
  --authenticator dns-certintel \
  --dns-certintel-credentials /etc/certintel/delegations.json \
  --dns-certintel-propagation-seconds 60 \
  --agree-tos --email [email protected] \
  --cert-name example.com \
  -d example.com -d '*.example.com'

With these default paths, the certificate chain is /etc/letsencrypt/live/example.com/fullchain.pem and the private key is /etc/letsencrypt/live/example.com/privkey.pem. certonly obtains and stores them without configuring a web server. Certificate deployment is a separate task.

Renewal

Certbot records the authenticator, credentials path and propagation delay for renewal. Test that saved configuration:

/opt/certintel-certbot/bin/certbot renew --cert-name example.com --dry-run

The dry run uses the staging CA. Keep the plugin installed and credentials readable under the account that will run unattended. A CA may reuse valid authorizations, so a renewal does not always publish a new TXT challenge.

For a pip/venv installation, configure a scheduler to invoke the exact binary. For example, a root-owned /etc/cron.d/certintel-certbot file can contain:

17 3,15 * * * root /opt/certintel-certbot/bin/certbot renew --quiet

Use your existing timer instead if it already invokes this environment; avoid duplicate schedulers. Credential rotation requires updating the mapping file and verifying renew --dry-run. Avoid overlapping tests and renewals against the same delegation.

Troubleshooting

Symptom Check
dns-certintel is missing Run plugins with the same /opt/certintel-certbot/bin/certbot used for issuance; install the wheel with that environment's Python.
No exact delegation mapping Add the exact certificate name without a wildcard prefix; parent mappings do not cover subdomains.
API 401/403 Check the update secret or granted DNS API key, delegation status and API endpoint.
API 404 or CNAME mismatch Check delegation UUID, endpoint and full CNAME target.
DNS validation fails Check the permanent CNAME and public TXT propagation; increase the propagation wait.
Invalid certificate identifier Remove underscores from the certificate hostname; keep the required underscore in _acme-challenge.
Delegation already has two TXT values Check for another issuer or stale values; do not clear another active challenge.
Cleanup warning Inspect the delegation after issuance; cleanup failures can leave values behind.

Use one issuing client/host per delegation. The plugin preserves other TXT values and deletes only its own, but CertIntel's API replaces the entire TXT set and permits at most two values. Local file locks cannot serialize another host, the dedicated CertIntel agent, or dashboard edits. Do not run them concurrently against the same delegation.

After a crash or cleanup failure, first confirm that no issuance is active, then remove stale values in CertIntel before retrying. API errors omit response bodies and secrets; Certbot logs are normally in /var/log/letsencrypt.

See also the official Certbot user guide.

Optional CertIntel reporting

The DNS plugin does not report check-ins or issued certificates. The separate PowerShell 7 reporting wrappers can add those reports. Pass the venv binary with -CertbotPath for both issuance and renewal, and use -Authenticator dns-certintel -CredentialsPath when creating the certificate. DNS credentials and the write-scoped reporting key are separate. If you adopt the renewal wrapper, schedule it in place of the bare Certbot command above so the same lineages are not run by two schedulers.