#acme #async #certsd

bin+lib certsd

CertsD - automated, asynchronous LE certificate issuer

8 releases

0.6.9 May 15, 2023
0.6.8 May 14, 2023
0.6.1 Apr 24, 2023

#339 in Asynchronous

Download history 1/week @ 2023-11-04 10/week @ 2023-11-11 1/week @ 2023-11-18 26/week @ 2023-11-25 16/week @ 2023-12-02 8/week @ 2023-12-16 16/week @ 2023-12-23 8/week @ 2023-12-30 4/week @ 2024-01-06 3/week @ 2024-01-13 40/week @ 2024-01-27 29/week @ 2024-02-10 116/week @ 2024-02-17

185 downloads per month

MIT license

40KB
821 lines

CertsD

CertsD-open - open-source, automated, asynchronous LE certificate issuer

Author:

Daniel (@dmilith) Dettlaff

Features:

  • Generates separate certificates for the root domain and its wildcard version.

  • Uses RON formatted configuration.

  • Supports multiple CloudFlare accounts and multiple domains/ zones at once.

  • Automatic management of DNS TXT records via the CloudFlare API.

  • Notifies Slack using a Webhook after a successful renewal.

  • Asynchronous by default.

Requirements read from the configuration file:

  • CloudFlare API Token (with "Edit zone DNS" permission).

  • CloudFlare Zone ID

  • A domain

Step by step how it works

  • CertsD reads the input configuration from one of the existing paths.

  • The ACME registration process starts in the current working directory.

  • Attempt to reuse all non-existent key files (account.key + example.com/domain.key + wild_example.com/domain.key) or generates them automatically.

  • Validate the expiration date of both certs (example.com/chained.pem and wild_example.com/chained.pem). By default, ACME provides certificates valid for 90 days. Based on that CertsD will only renew certificates that have less than 60 days of validity time left.

  • ACME process creates the DNS challenge.

  • A DNS TXT record for a given domain (with the value of the challenge) is created using CF API.

  • Await confirmation of the order from the ACME response.

  • A DNS TXT record for a given domain is deleted using CF API.

  • After order confirmation, the (example.com/chained.pem + wild_example.com/chained.pem) are fetched from ACME.

A few notes about ACME service:

  • CertsD stability relies on the stability of ACME services. Don't panic. Be patient.

  • From time to time the ACME API responds with a random "invalid" status just because. Don't panic. Be patient.

  • If you won't remove one of (account.key+example.com/domain.key+wild_example.com/domain.key`) too often, the ACME is likely to renew your certs faster without any issues (ACME cert caching mechanism).

  • If you want to use ACME Staging for testing, set the acme_staging: true in your configuration.

Software requirements:

  • Rust >= 1.68.2
  • OpenSSL >= 1.1.1t

Additional build requirements:

  • Clang >= 6.x
  • Make >= 3.x
  • Cmake >= 3.16
  • Perl >= 5.x
  • Patchelf > 0.17
  • POSIX-compliant base-system (tested on systems: FreeBSD/ HardenedBSD/ Darwin and Linux)

Production Configuration:

NOTE: I hold the configuration under /Services/Certsd/service.conf, all keys and generated certificates under /Services/Certsd.

(
    acme_staging: false,
    accounts: [
        (
            cloudflare_api_token: "cloudflare-api-token",
            cloudflare_zone_id: "cloudflare-zone-id",
            domain: "myexample.com",
            contacts: ["domains@example.com"],
        ),

        //
    ],

    notifications: [
        Slack(webhook: "https://hooks.slack.com/services/111111111/33333333333/44444444444444444"),
        Telegram(
            chat_id: "@Public_Channel",
            token: "1111111111111111111111111111111"
        ),
        //
    ]
)

Production cron entry example:

# run certsd every 10 days, 30 minutes before midnight:
30 23 */10 * * "/Software/Certsd/exports/certsd >> /var/log/renew-example.com.log"

Example Nginx proxy configuration (to serve generated chained.pem to remote hosts):

server {
   listen       80;
   server_name  my.example.com;
   autoindex off;

   location ~ .*/chained.pem {
       root   /etc/certsd/certs;
   }

   location / {
       deny  all;
   }
}

Dependencies

~16–32MB
~494K SLoC