Certgrinder
The certgrinder
client is responsible for generating a keypair and a CSR, which it uses to contact the Certgrinder server certgrinderd
over SSH to get a signed certificate. The following section explains how to install and configure it to get certificates from the Certgrinder server.
Installation
This section explains the steps to install a Certgrinder client. Repeat these steps on each server in need of certificates!
Install certgrinder
You can install certgrinder from pip with pip install certgrinder
. This will install the latest certgrinder
release. It will pull in the dependencies it needs automatically.
You can also checkout the Github repo and install the deps from requirements.txt by hand if you prefer. If you want to install with pip directly from Git the following may help:
pip install "git+https://github.com/tykling/certgrinder/#egg=certgrinder&subdirectory=client"
Create Certgrinder User
Since certgrinder
is designed to be run under a separate system user one should be created. The user needs sudo access if (and only if) it is to be able to reload/restart services after renewing certificates. Sometimes it is also necessary to add some system users to the certgrinder group so they can read certificates. More on that later.
The user also needs to run ssh-keygen
and the SSH key needs to be added to the authorized_keys
file on the Certgrinder server. Make sure to test the SSH access works (hint: check firewalls, v4 vs v6 etc).
Configuration
Configuration of certgrinder
can be done using command-line options, or a configuration file, or a combination of the two.
The certgrinder
configuration file is in YAML format. An example config named certgrinder.conf.dist
can be found in the distribution. use --config-file
or -f
to specify the config file location.
Each config item can be specified either in the YAML config file as a key: value
pair, or on the commandline as --key value
- the latter overriding the former if both are present. For example, if the configfile has log-level: INFO
and the command-line has --log-level: DEBUG
then the effective log-level would be DEBUG
.
This is an alphabetical list of the configurable options:
- alternate-chain
Instruct certgrinder to request the alternate chain for signing.
For production this means using the short chain with 1 intermediate signed by
ISRG Root X1
instead of using the default long chain with 2 intermediates signed byDST Root CA X3
.For staging it means using
Fake LE Root X2
(1 intermediate) instead of the usualFake LE Root X1
(2 intermediates).Default:
False
- certgrinderd
The command to run as
certgrinderd
. Usually this will be something likessh certgrinderd@certgrinder.example.com -T
, possibly also with a--config-file
forcertgrinderd
if needed.Default:
None
- cert-renew-threshold-days
A certificate will be renewed when it has less than this many days of lifetime left.
Default:
30
- domain-list
Comma-separated lists of domains for the certificates. Can be specified multiple times on the command-line,
--domain-list example.com,www.example.com --domain-list example.net
means two certificates, the first with two names, the second with one name.Default:
None
- invalid-ca-cn-list
List of CommonName of certificate issuers to consider invalid. This is not a regular CA certificate validity check, it is used to detect certificates issued by LetsEncrypt staging servers as invalid.
Default:
["Fake LE Intermediate X1", "Fake LE Intermediate X2"]
- log-level
Sets the verbosity level for console and syslog logging. One of DEBUG, INFO, WARNING, ERROR, CRITICAL.
Default:
INFO
- key-type-list
List of key types to enable. Supported choices are rsa and ecdsa. Files for each keytype will be suffixed with .rsa.ext and ecdsa.ext, respectively.
Default:
["rsa", "ecdsa"]
- name-server
Set this to a DNS server IP (v4 or v6, no hostnames) to use that DNS server instead of the system resolver.
Default:
None
- ocsp-renew-threshold-percent
The amount of time in percent between
produced_at
andnext_update
that must have passed before an OCSP response is considered too old. As of January 2021 LetsEncrypt has 7 days betweenproduced_at
andnext_update
in OCSP responses, so the default of 50% means OCSP responses will be renewed after 3.5 days (half of the validity period) has passed.As of January 2021 LetsEncrypt produces new OCSP responses after half of the validity period has passed, so any setting lower than that will be pointless. Setting this lower than 50 will just result in Certgrinder fetching the same OCSP response over and over.
Set to 0 to always renew OCSP responses regardless of their age.
Default:
50
- path
The directory used for keys, CSRs and certificates. Must exist and be writable by the user running Certgrinder.
Default:
None
- periodic-sleep-minutes
Certgrinder will pick a random number of minutes between 0 and this number and sleep for that long before doing periodic actions. Set to 0 to disable sleeping.
Default:
60
- pid-dir
The directory to place the certgrinderd PID file in.
Default:
/tmp
- post-renew-hooks
A list of commands which
certgrinder
must run after renewing one or more certificates or OCSP responses. Use this to reload/restart services which need to be poked after the certificate changes. Can be specified multiple times on the command-line. Remember to include sudo or whatever if needed. Wrap complex commands in a small shell script to avoid quoting issues.Default:
None
- post-renew-hooks-dir
A path to a hooks.d style directory containing files to be executed after renewing one or more certificates or OCSP responses. Each executable file in this path will be run in the order returned by
os.listdir()
. Setpost-renew-hooks-dir-runner
if something likesudo
is needed to elevate privileges before running the hooks.Default:
None
- post-renew-hooks-dir-runner
When this is set it will be executed in place of each executable in
post-renew-hooks-dir
with the executable as argument.Example: If
post-renew-hooks-dir
contains two executable fileshook1
andhook2
andpost-renew-hooks-dir-runner
is set to/usr/local/bin/sudo
then certgrinder will execute/usr/local/bin/sudo /path/to/hooks/dir/hook1
and then/usr/local/bin/sudo /path/to/hooks/dir/hook2
instead of executing the two hooks directly.Default:
None
- staging
Enable staging mode. Adds
--staging
to thecertgrinderd
command, and considers certificates issued by LE staging servers as valid.Default:
False
- syslog-facility
Set this and syslog-socket to enable logging to syslog. Must be a value supported by
logging.handlers.SysLogHandler
likeLOG_USER
orLOG_LOCAL0
.Default:
None
- syslog-socket
Set this and syslog-facility to enable logging to syslog.
Default:
None
- tlsa-port
Set this to the port (like
443
) when usingshow tlsa
orcheck tlsa
subcommands.Default:
None
- tlsa-protocol
Set this to the protocol (like
tcp
) when usingshow tlsa
orcheck tlsa
subcommands.Default:
None
- tlsa-type-list
Set this to enable a TLSA type (can be specified multiple times). The TLSA type must be specified as three integers, one of:
310
,311
or312
. Default: is all three pubkey types.Default:
["310", "311", "312"]
ACME Challenges
Finally you need to choose which challenge type to use for this certgrinder
client. If DNS-01
you need to create one or more CNAME
record pointing somewhere. If HTTP-01
you need to create an HTTP redirect. See the section on challenges for more info.
Testing
At this point you should be ready to test! Start by checking with SSH manually to see that the SSH key is installed properly on the Certgrinder server, and firewalls are open. Certgrinder has a --staging
switch which makes certgrinderd
use the LetsEncrypt staging environment. Use this until everything works! certgrinder
outputs some info on what happens, and can output more with -d / --debug
, but sometimes you need to check syslog on the Certgrinder server.
Crontab job
I run Certgrinder daily, although by default it only attempts certificate renewal when less than 30 days validity remains, and OCSP response renewal when half the validity period has passed.
When everything above works it is time to automate it by adding it to crontab. The following line works for me (the periodic
command sleeps a random number of minutes before doing its thing, so all the clients don’t contact the Certgrinder server at once):
0 2 * * * certgrinder /usr/home/certgrinder/virtualenv/bin/certgrinder -c /usr/home/certgrinder/certgrinder.conf periodic
Client Commands
All the functionality in Certgrinder can be accessed by using commands
and subcommands
. The following commands
are available:
check commands
All the subcommands for the check
commands return exit code 1 if a problem is found and 0 if everything is fine.
check certificate command
The check certificate
subcommand loops over the configured domainsets and checks the validity of the certificate for each. If a problem is found certgrinder
will exit with exit code 1, if all is well the exit code will be 0.
check connection command
The check connection
subcommand simply checks that the connection to the certgrinderd
server works as expected. It calls the ping
command on the certgrinderd
server and expects to see the string pong
on stdout. If the expected string is found the exit code will be 0, if a problem is found the exit code will be 1.
check ocsp command
The check ocsp
subcommand loops over the configured domainsets and checks for the existance of an OCSP response for each. If an OCSP response for a certificate is missing or too old certgrinder
will exit with exit code 1, if all is well the exit code will be 0.
An OCSP response is considered too old when more than ocsp-renew-threshold-percent
percent of the time between producedAt
and nextUpdate
has passed. As of January 2021 LetsEncrypt has 7 days (one week) between producedAt
and nextUpdate
which means OCSP responses will be renewed after 3.5 days with the default ocsp-renew-threshold-percent
setting of 50
.
check tlsa command
The check tlsa
subcommand is like the show tlsa
subcommand but it goes one step further and actually checks in the DNS
if the records could be found, and prints some output accordingly. The following example shows two runs of check tlsa
mode. The first run finds no TLSA records and outputs what needs to be added:
[certgrinder@znc ~]$ ./virtualenv/bin/certgrinder -f certgrinder.conf check tlsa 443 tcp
2018-02-16 08:59:39 +0000 INFO: Processing domains: znc.tyknet.dk
2018-02-16 08:59:39 +0000 INFO: Looking up TLSA records for _443._tcp.znc.tyknet.dk
2018-02-16 08:59:39 +0000 WARNING: No TLSA records for name _443._tcp.znc.tyknet.dk of type 3 1 0 was found in DNS. This record needs to be added:
2018-02-16 08:59:39 +0000 WARNING: _443._tcp.znc.tyknet.dk 3 1 0 30820222300d06092a864886f70d01010105000382020f003082020a0282020100bb852c1035ee7ce08d69a13f5cca95374dc872b2028e65ee34600478076c9185e79ff373d3acfc4aa29f152b9abcb515e449417ce7768f7f91915ff2d6e75d732e863021240ce4b24475220306e6ffd3f963dc4a8eafb4077f635d8a0d655b5921df2bcb2e6e610aa8db1d79b6da14d1fc7d842c1e5d4cbfa6697617aa9d2251be1a386fd7c14eccef21151c35d336ebba8f97d3160b35775c57079d2594b1d2a9d593bc408ccf2a01b171f4a3e65005b07df7efd77bac3d5f430b0aab5f161b7d7ebc40b600064ec3a4c59d64a1ec1f27c234a08a473aa0fcdf6008492161af6a1d9179a432622776e675f4d3dafb3d1d00b3189c4cdcd6de250721f012fc5f34426d06cb4b045b04ba2bd7ac2fcedce429dfde3dffcbb8b2df50cade99458c954de157b88751c26b79413d6eef5e26ab008e7aa7c69be3d6163f80f5d565b87f9030b54a23cf4c704e509cc84e618a446c75684893d65bd5fd38ef6b839d316b5616b06bbafbb7c2aa6f3db217b4df6e5f02b85d8685be14a9d480ee56c1b4454a88fc01a4532a55e926929fea70822088054f5ddf957e8c5ca2c3808c8a09b70c7eeda4883aaf6f1092033beeb0ff5621a8b8ddf3455f1d30d2398fe786038a39e0825bb6bac9865500de33eff67e3984a73b7592bde5897681b52da06c93447a0efa4d1fb52bc151811776ef501ca818c68fd1d4fe3d73c5e5526b4bf47f0203010001
2018-02-16 08:59:39 +0000 WARNING: No TLSA records for name _443._tcp.znc.tyknet.dk of type 3 1 1 was found in DNS. This record needs to be added:
2018-02-16 08:59:39 +0000 WARNING: _443._tcp.znc.tyknet.dk 3 1 1 5b95cb6ea387570f1f3dc4508794ca13a17a665733bab5f76b1e330f2fa13361
2018-02-16 08:59:39 +0000 WARNING: No TLSA records for name _443._tcp.znc.tyknet.dk of type 3 1 2 was found in DNS. This record needs to be added:
2018-02-16 08:59:39 +0000 WARNING: _443._tcp.znc.tyknet.dk 3 1 2 24d49f3c974129b9c28b5e6213892a404d8e9777c5a2e977333b88442d4e16ac0bc732001ec783df795c194704149bd18bbca21087111b33fa79e84dab05e760
2018-02-16 08:59:39 +0000 INFO: Done processing domains: znc.tyknet.dk
[certgrinder@znc ~]$
The second run is after adding the suggested records to DNS
:
[certgrinder@znc ~]$ ./virtualenv/bin/certgrinder -f certgrinder.conf check tlsa 443 tcp
2018-02-16 09:16:27 +0000 INFO: Processing domains: znc.tyknet.dk
2018-02-16 09:16:27 +0000 INFO: Looking up TLSA records for _443._tcp.znc.tyknet.dk
2018-02-16 09:16:27 +0000 INFO: TLSA record for name _443._tcp.znc.tyknet.dk type 3 1 0 found in DNS matches the local key, good.
2018-02-16 09:16:27 +0000 INFO: TLSA record for name _443._tcp.znc.tyknet.dk type 3 1 1 found in DNS matches the local key, good.
2018-02-16 09:16:27 +0000 INFO: TLSA record for name _443._tcp.znc.tyknet.dk type 3 1 2 found in DNS matches the local key, good.
2018-02-16 09:16:27 +0000 INFO: Done processing domains: znc.tyknet.dk
[certgrinder@znc ~]$
All TLSA
records for this public key can now be found in the DNS
.
NOTE: As there might be additional records for the same name which do not belong to this server/key (for example in a loadbalanced or anycast setup), no attempts are made to warn about wrong/old/superfluous TLSA
records. This might be added in a future version as a switch to tell Certgrinder that the local public key is the only one in existence for this service.
get commands
The get
subcommands do all the real work.
get certificate command
The get certificate
subcommand loops over the configured domainsets and gets a new certificate for each, regardless of the current status of existing certificates. Use with care, only for troubleshooting. Do not use from cron. Use the periodic command instead.
get ocsp command
The get ocsp
subcommand loops over the configured domainsets and gets a new OCSP response for each, regardless of the current status of existing OCSP responses. Do not use from cron. Use the periodic command instead.
help command
The help
command is just a shortcut for -h
which shows commandline usage and help.
periodic command
The periodic
command sleeps for a random number of minutes between 0 and the config setting periodic-sleep-minutes
before doing anything. Set this setting to 0 to disable sleeping.
After sleeping the certificates and OCSP responses are checked and renewed as needed. This command is meant to be run daily from cron or similar.
show commands
The show
subcommands show information but never change anything.
show certificate command
The show certificate
subcommand loops over configured domainsets and outputs information about each certificate (if any).
show configuration command
The show configuration
subcommand just dumps the active configuration as a pretty printed JSON object and exits. Useful for testing or debugging configuration issues.
show ocsp command
The show ocsp
subcommand loops over the configured domainsets and shows info about each OCSP response.
show paths command
The show paths
subcommand loops over the configured domainsets and outputs the paths used for keys, certificates and OCSP responses.
show spki command
The show spki
subcommand outputs pin-sha256 spki pins for the public keys. The HPKP
standard https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning defined the pin-sha256
format for public key pins. While the HPKP
standard didn’t get much traction the pinning format is used in various places now, so certgrinder
can generate them.
The operation is pretty simple:
[certgrinder@znc ~]$ ./virtualenv/bin/certgrinder -f certgrinder.conf show spki
2018-02-16 09:28:37 +0000 INFO: Processing domains: znc.tyknet.dk
2018-02-16 09:28:37 +0000 INFO: pin-sha256="W5XLbqOHVw8fPcRQh5TKE6F6ZlczurX3ax4zDy+hM2E="
2018-02-16 09:28:37 +0000 INFO: Done processing domains: znc.tyknet.dk
[certgrinder@znc ~]$
show tlsa command
The show tlsa
subcommand loops over the configured domainsets and generates TLSA
records for the public keys. The result is printed to the terminal in a format suitable for putting in the DNS
. It looks something like this:
[certgrinder@znc ~]$ ./virtualenv/bin/certgrinder -f certgrinder.conf show tlsa 443 tcp
2018-02-16 08:42:18 +0000 INFO: Processing domains: znc.tyknet.dk
2018-02-16 08:42:18 +0000 INFO: TLSA records for _443._tcp.znc.tyknet.dk:
2018-02-16 08:42:18 +0000 INFO: _443._tcp.znc.tyknet.dk 3 1 0 30820222300d06092a864886f70d01010105000382020f003082020a0282020100bb852c1035ee7ce08d69a13f5cca95374dc872b2028e65ee34600478076c9185e79ff373d3acfc4aa29f152b9abcb515e449417ce7768f7f91915ff2d6e75d732e863021240ce4b24475220306e6ffd3f963dc4a8eafb4077f635d8a0d655b5921df2bcb2e6e610aa8db1d79b6da14d1fc7d842c1e5d4cbfa6697617aa9d2251be1a386fd7c14eccef21151c35d336ebba8f97d3160b35775c57079d2594b1d2a9d593bc408ccf2a01b171f4a3e65005b07df7efd77bac3d5f430b0aab5f161b7d7ebc40b600064ec3a4c59d64a1ec1f27c234a08a473aa0fcdf6008492161af6a1d9179a432622776e675f4d3dafb3d1d00b3189c4cdcd6de250721f012fc5f34426d06cb4b045b04ba2bd7ac2fcedce429dfde3dffcbb8b2df50cade99458c954de157b88751c26b79413d6eef5e26ab008e7aa7c69be3d6163f80f5d565b87f9030b54a23cf4c704e509cc84e618a446c75684893d65bd5fd38ef6b839d316b5616b06bbafbb7c2aa6f3db217b4df6e5f02b85d8685be14a9d480ee56c1b4454a88fc01a4532a55e926929fea70822088054f5ddf957e8c5ca2c3808c8a09b70c7eeda4883aaf6f1092033beeb0ff5621a8b8ddf3455f1d30d2398fe786038a39e0825bb6bac9865500de33eff67e3984a73b7592bde5897681b52da06c93447a0efa4d1fb52bc151811776ef501ca818c68fd1d4fe3d73c5e5526b4bf47f0203010001
2018-02-16 08:42:18 +0000 INFO: _443._tcp.znc.tyknet.dk 3 1 1 5b95cb6ea387570f1f3dc4508794ca13a17a665733bab5f76b1e330f2fa13361
2018-02-16 08:42:18 +0000 INFO: _443._tcp.znc.tyknet.dk 3 1 2 24d49f3c974129b9c28b5e6213892a404d8e9777c5a2e977333b88442d4e16ac0bc732001ec783df795c194704149bd18bbca21087111b33fa79e84dab05e760
[certgrinder@znc ~]$
Shown above is the show tlsa
subcommand in action. The value supplied should be the port and protocol of the service, in the example above it is a HTTPS
service, so the TLSA
record is the service hostname prefixed with _443._tcp.
version command
The version
command is just a shortcut for -v
which shows the Certgrinder version and exits.
Command Line Usage
Certgrinder version 0.18.0-dev. See the manpage or ReadTheDocs for more info.
usage: certgrinder [-h] [-a] [--certgrinderd CERTGRINDERD]
[--cert-renew-threshold-days CERT-RENEW-THRESHOLD-DAYS]
[-c CONFIG-FILE] [-d] [-D DOMAIN-LIST]
[--invalid-ca-cn-list INVALID-CA-CN-LIST]
[-l {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [-k {rsa,ecdsa}]
[-n NAME-SERVER] [--now] [-o OCSP-RENEW-THRESHOLD-PERCENT]
[--path PATH]
[--periodic-sleep-minutes PERIODIC-SLEEP-MINUTES]
[-p PID-DIR] [--post-renew-hooks POST-RENEW-HOOKS]
[--post-renew-hooks-dir POST-RENEW-HOOKS-DIR]
[--post-renew-hooks-dir-runner POST-RENEW-HOOKS-DIR-RUNNER]
[-q] [-s] [--syslog-facility SYSLOG-FACILITY]
[--syslog-socket SYSLOG-SOCKET] [--tlsa-port TLSA-PORT]
[--tlsa-protocol TLSA-PROTOCOL]
[--tlsa-type-list {310,311,312}] [-v]
{check,get,help,periodic,show,version} ...
Positional Arguments
- command
Possible choices: check, get, help, periodic, show, version
Command (required)
Named Arguments
- -a, --alternate-chain
Use alternate chain. For production this means using the short chain with 1 intermediate signed by ‘ISRG Root X1’ instead of using the long chain with 2 intermediates signed by ‘DST Root CA X3’. For staging it means using ‘Fake LE Root X2’ (1 intermediate) instead of the usual ‘Fake LE Root X1’ (2 intermediates).
- --certgrinderd
The command to reach the certgrinderd server, will get the input (CSR or cert chain) on stdin. Usually something like ‘ssh certgrinderd@server -T’
- --cert-renew-threshold-days
A certificate is renewed when it has less than this many days of lifetime left. Default: 30
- -c, --config-file
The path to the certgrinder.yml config file to use
- -d, --debug
Debug mode. Equal to setting –log-level=DEBUG.
- -D, --domain-list
Comma separated list of domains for a certificate. Can be specified multiple times.
- --invalid-ca-cn-list
The CommonName of an issuer (CA intermediate) to consider invalid. Can be specified multiple times.
- -l, --log-level
Possible choices: DEBUG, INFO, WARNING, ERROR, CRITICAL
Logging level. One of DEBUG, INFO, WARNING, ERROR, CRITICAL. Defaults to INFO.
- -k, --key-type-list
Possible choices: rsa, ecdsa
The keytypes to enable. Valid values are ‘rsa’ and ‘ecdsa’. Can be specified multiple times. Defaults to both rsa and ecdsa.
- -n, --name-server
Tell certgrinder to use this DNS server IP to lookup TLSA records. Only relevant with -c / –checktlsa. Only v4/v6 IPs, no hostnames.
- --now
Run periodic command without delay. Equal to setting –periodic-sleep-minutes 0.
- -o, --ocsp-renew-threshold-percent
Possible choices: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100
An integer between 0 and 100 specifying the amount of time in percent between
produced_at
andnext_update
which must have passed before an OCSP response is considered too old. Defaults to 50.- --path
Tell certgrinder to use the specified directory for keys, CSRs and certificates. The directory must exist and be writeable by the user running certgrinder.
- --periodic-sleep-minutes
Tell certgrinder to sleep for a random number of minutes between 0 and this number before doing anything when the periodic command is used. Set to 0 to disable sleeping.
- -p, --pid-dir
The directory to store the PID file in
- --post-renew-hooks
The list of commands to run after one or more certificates are renewed. Most such commands will need root access to run, remember to prefix the command with ‘sudo’ as needed. Can be specified multiple times. Default: None
- --post-renew-hooks-dir
Path to a folder containing executables to run after one or more certificates or OCSP responses are renewed. These will execute under the regular certgrinder user uid, so make sure to use sudo/doas in scripts or suid executables as needed. Default: None
- --post-renew-hooks-dir-runner
Path to an executable like sudo to be used to run each of the executables in the post renew hooks dir. Default: None
- -q, --quiet
Quiet mode. No output at all if there is nothing to do, and no errors are encountered. Equal to setting –log-level=WARNING.
- -s, --staging
Staging mode. Sets –acme-server-url https://acme-staging-v02.api.letsencrypt.org/directory and –invalid-ca-cn-list empty. Use this while playing around to avoid hitting rate limits!
- --syslog-facility
The syslog facility to use. Set this and syslog-socket to enable logging to syslog.
- --syslog-socket
The syslog socket to connect to. Set this and syslog-facility to enable logging to syslog.
- --tlsa-port
The service port number (like 443) for TLSA operations.
- --tlsa-protocol
The service protocol (like tcp) for TLSA operations.
- --tlsa-type-list
Possible choices: 310, 311, 312
Enables a TLSA type for TLSA operations. Can be specified multiple times.
- -v, --version
Show version and exit.
Sub-commands:
check
Use the “check” command to check certificates, OCSP responses and TLSA records. Returns exit code 0 if all is well, and 1 if something needs attention.
certgrinder check [-h] {certificate,connection,ocsp,tlsa} ...
Positional Arguments
- subcommand
Possible choices: certificate, connection, ocsp, tlsa
Specify what to check using one of the available check sub-commands.
Sub-commands:
certificate
Tell certgrinder to check certificate validity for all configured domainsets. Returns exit code 1 if any problem is found, exit code 0 if all is well.
certgrinder check certificate [-h]
connection
Tell certgrinder to check the connection to the certgrinderd server by calling the certgrinderd ‘ping’ command which should return the string ‘pong’ if all is well.
certgrinder check connection [-h]
ocsp
Tell certgrinder to check the OCSP response validity for certificates for all configured domainsets. Returns exit code 1 if any problem is found, exit code 0 if all is well.
certgrinder check ocsp [-h]
tlsa
Tell certgrinder to lookup TLSA records for the given port and protocol in the DNS and compare with what we have locally, for example: ‘certgrinder check tlsa 853 tcp’
certgrinder check tlsa [-h] tlsa-port tlsa-protocol
- tlsa-port
The port of the service, for example 443
- tlsa-protocol
The protocol of the service, for example tcp
get
Use the “get” command to get certificates and OCSP responses
certgrinder get [-h] {certificate,ocsp} ...
Positional Arguments
- subcommand
Possible choices: certificate, ocsp
Specify what to get using one of the available get sub-commands
Sub-commands:
certificate
Tell certgrinder to get new certificate(s), regardless of their current state. Rarely needed, use ‘periodic’ command instead.
certgrinder get certificate [-h]
ocsp
Tell certgrinder to get OCSP responses for the configured domainset(s). Rarely needed, use ‘periodic’ command instead.
certgrinder get ocsp [-h]
help
The “help” command just outputs the usage help
certgrinder help [-h]
periodic
The “periodic” command checks certificates and renews them as needed. Meant to be run from cron or similar daily.
certgrinder periodic [-h]
show
Use the “show” command to show certificates, TLSA records, SPKI pins or configuration.
certgrinder show [-h] {certificate,configuration,paths,ocsp,spki,tlsa} ...
Positional Arguments
- subcommand
Possible choices: certificate, configuration, paths, ocsp, spki, tlsa
Specify what to show using one of the available show sub-commands
Sub-commands:
certificate
Tell certgrinder to output information about certificates.
certgrinder show certificate [-h]
configuration
Tell certgrinder to output the current configuration
certgrinder show configuration [-h]
paths
Tell certgrinder to output the paths used
certgrinder show paths [-h]
ocsp
Tell certgrinder to output information about OCSP responses.
certgrinder show ocsp [-h]
spki
Tell certgrinder to generate and print the pin-sha256 spki pins for the public keys it manages.
certgrinder show spki [-h]
tlsa
Use the ‘show tlsa’ sub-command to tell certgrinder to generate and print TLSA records for the given service, for example: ‘certgrinder show tlsa 443 tcp’
certgrinder show tlsa [-h] tlsa-port tlsa-protocol
- tlsa-port
The port of the service, for example 443
- tlsa-protocol
The protocol of the service, for example tcp
version
The “version” command just outputs the version of Certgrinder
certgrinder version [-h]
Class Methods
- class certgrinder.Certgrinder
The Certgrinder client class.
- __init__() None
Define the default config.
- check_certificate(certificate: Optional[cryptography.x509.base.Certificate] = None, public_key: Optional[Union[cryptography.hazmat.backends.openssl.rsa._RSAPublicKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey]] = None) bool
Check certificate validity and returns True or False.
This method is called by self.grind() once per domainset when the “check certificate” subcommand is invoked. It reads the certificate from self.certificate_path if there is no certificate arg
- Parameters
certificate – The certificate to be checked
public_key – The keypair the certificate is based on
- Returns
True if everything is OK, False otherwise
- static check_certificate_expiry(certificate: cryptography.x509.base.Certificate, threshold_days: int) bool
Check the remaining validity of the certificate.
- Parameters
certificate – The certificate to check
threshold_days – The lowest number of remaining days of validity that is considered valid
- Returns
True if remaining certificate lifetime is >= threshold_days, False if not
- static check_certificate_issuer(certificate: cryptography.x509.base.Certificate, invalid_ca_cn_list: List[str]) bool
Check the issuer of the certificate.
- Parameters
certificate – The certificate to check
invalid_ca_cn_list – The list of CA CommonName strings to consider invalid
- Returns
True if the certificate issuer CN is not in invalid_ca_cn_list
- static check_certificate_public_key(certificate: cryptography.x509.base.Certificate, public_key: Union[cryptography.hazmat.backends.openssl.rsa._RSAPublicKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey]) bool
Make sure certificate has the specified public key.
- Parameters
certificate – The certificate to check
public_key – The public key
- Returns
True if the public key matches, False if not
- static check_certificate_san_names(certificate: cryptography.x509.base.Certificate, san_names: List[str]) bool
Make sure the certificate has the provided list of names as SAN.
- Parameters
certificate – The certificate to check
san_names – A list of the names to expect
- Returns
True if all san_names were found in the cert, and no others.
- static check_certificate_subject(certificate: cryptography.x509.base.Certificate, subject: str) bool
Make sure the certificate has the specified subject.
- Parameters
certificate – The certificate to check
subject – The subject to expect
- Returns
True if the subject matches the cert, False if not
- classmethod check_certificate_validity(certificate: cryptography.x509.base.Certificate, invalid_ca_cn_list: List[str], threshold_days: int, san_names: List[str], public_key: Optional[Union[cryptography.hazmat.backends.openssl.rsa._RSAPublicKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey]] = None, subject: str = '') bool
Perform a few sanity checks of the certificate.
Check that the issuer is valid
Check that the certificate expiry is not exceeded
Check that the public key is correct
Check that the subject is correct
Check that the SubjectAltName data is correct
- Parameters
certificate – The certificate to check
invalid_ca_cn_list – A list of CA CommonNames to consider invalid
threshold_days – The minimum number of remaining days lifetime to considered valid.
san_names – A list of domain names to expect in SubjectAltName of the certificate.
keypair – The keypair the certificate is for.
- Returns
False if a problem is found, True if all is well.
- check_connection(stdout: Optional[bytes] = None) bool
The
check connection
subcommand method.- Parameters
stdout – The certgrinderd response to use instead of calling certgrinderd (optional)
- Returns
None
- check_ocsp() bool
The
check ocsp
subcommand method, called for each domainset byself.grind()
.- Returns
True if the OCSP response was found and is not too old, False otherwise
- check_tlsa() None
The ‘check tlsa’ subcommand method, called for each domainset by
self.grind()
.Loops over the configured TLSA types and calls
self.verify_tlsa_record()
which does the heavy lifting.- Returns
None
- configure(userconfig: Dict[str, Union[str, int, bool, List[str]]]) None
Merge and check configuration and configure logging.
Merge the supplied userconfig dict with the default config, checks for missing required settings, and configures logging and syslog.
- Parameters
userconfig – dict of the config to be merged with the default config
- Returns
None
- static generate_csr(keypair: Union[cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey], domains: List[str]) cryptography.hazmat.backends.openssl.x509._CertificateSigningRequest
Generate and return a new CSR based on the public key and list of domains.
Only set CN since everything else is removed by LetsEncrypt in the certificate anyway. Add all domains in subjectAltName, including the one put into CN.
- Parameters
keypair – The keypair to base the CSR on
domains – A list of domains to put in the CSR. First in the list will be cert CN.
- Returns
The CSR object
- static generate_private_key(keytype: str) Union[cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey, cryptography.hazmat.backends.openssl.ec._EllipticCurvePrivateKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey]
Generate and returns a private key.
- Parameters
keytype – “rsa” for RSA key, “ecdsa” for ECDSA and “ed25519” for ed25519
- Returns
The keypair object
- Raises
ValueError – For unsupported keytypes
- static generate_spki(derkey: bytes) str
Generate and return a pin-sha256 spki hpkp style pin for the provided public key.
- OpenSSL equivalent command is:
openssl x509 -in example.com.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl base64
- Parameters
derkey – The bytes representing the public key in DER format
- Returns
A string of the SPKI pin
- static generate_tlsa_record(derkey: bytes, tlsatype: str) str
Generate and return the data part of a TLSA record of the requested type.
TLSA record is generated from the DER formatted public key supplied. Returns an uppercase hex string.
- Parameters
derkey – The bytes representing the public key in DER format
tlsatype – The TLSA type (like “310”)
- Returns
String of the TLSA data
- Raises
ValueError – If an unknown TLSA type is passed
- get_certgrinderd_command(subcommand: List[str]) List[str]
Return the certgrinderd command to run.
Adds
--log-level
with the currentself.conf["log-level"]
. Also adds –acme-server-url if configured, and –preferred-chain.- Parameters
subcommand – The certgrinderd subcommand to run as a list, like [“get”, “ocsp”]
- Returns
A list of the elements which make up the
certgrinderd
command
- get_certificate(csr: Optional[cryptography.hazmat.backends.openssl.x509._CertificateSigningRequest] = None, stdout: Optional[bytes] = None) bool
Get a new certificate for self.domainset.
This methods gets a new certificate regardless of the status of any existing certificate. It is called by
self.periodic()
as needed. It can also be called by theget certificate
subcommand.- Parameters
csr – The CSR to use instead of generating one
stdout – The stdout bytes to use instead of calling self.run_certgrinderd(csr)
- Returns
False something goes wrong, True if all is well
- static get_der_pubkey(keypair: Union[cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey]) bytes
Return the DER formatted publickey.
- Parameters
keypair – The keypair which contains the public key
- Returns
The bytes representing the DER formatted public key
- get_filename(hostname: str) str
Calculate the hostname string to be used for filenames.
Files are named after the ascii idna representation of the first hostname in the list (which is also the CN in the subject of the CSR and certificate).
Max filename length on some platforms is 255 bytes, but a hostname could be up to 253 bytes (RFC 1035 section 2.3.4), and we need some room for the usage and keytype and extension, so we only use the last 230 bytes of the ascii idna representation of the hostname for the filename, leaving 25 bytes for metadata.
- Parameters
domainset – The list of hostnames
- Returns
The string to use in filenames
- get_ocsp(certificate: Optional[cryptography.x509.base.Certificate] = None, issuers: List[cryptography.x509.base.Certificate] = [], stdout: Optional[bytes] = None) bool
The
get ocsp
subcommand method, called for each domainset byself.grind()
.- Parameters
certificate – The certificate to get OCSP response for (optional)
issuers – The list of issuer(s) of the certificate to get OCSP response for (optional)
stdout – The mock OCSP response to return instead of calling certgrinderd (optional, used for unit tests)
- Returns
None
- grind(args: argparse.Namespace) None
Loop over enabled keytypes and domainsets in
self.conf["domain-list"]
and call args.method for each.
- load_certificates(path: str) List[cryptography.x509.base.Certificate]
Reads PEM certificate data from the path, parses the certificate(s), and returns them in a list.
- Parameters
path – The path to read the PEM certificate(s) from
- Returns
A list of cryptography.x509.Certificate objects
- load_domainset(domainset: List[str], keytype: str) None
Prepare paths and create/load private key.
- Parameters
domainset – The list of hostnames to load
keytype – The keytype to use, “rsa” or “ecdsa”.
- Returns
None
- static load_keypair(path: str) Union[cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey]
Load keypair bytes from disk, load key and return the object.
Fixes keypair permissions to 640 if they are not 640.
- Parameters
path – The path to load the keypair from
- Returns
The keypair object
- static load_ocsp_response(path: str) cryptography.hazmat.backends.openssl.ocsp._OCSPResponse
Reads OCSP response in DER format from the path and returns the object.
- Parameters
path – The path to read the OCSP response from
- Returns
The OCSP response object
- static lookup_tlsa_record(domain: str, port: int, protocol: str, tlsatype: Optional[str] = None, nameserver: str = '') Optional[List[str]]
Lookup TLSA records in DNS for the configured domain, port, and protocol.
Loop over any responses and look for the requested tlsatype. Return a list of results, optionally limited to the specified tlsatype, or None. Use system resolver unless nameserver is specified.
- Parameters
domain – The service domain name (like
mail.example.com
)port – The service port (like
443
)protocol – The service protocol (like
tcp
)tlsatype – The TLSA type (like
312
)nameserver – The DNS server IP to use instead of system resolver (optional)
- Returns
A list of records or None
- classmethod output_spki(derkey: bytes) None
Get and print the spki pin for the supplied DER public key.
- Parameters
derkey – The bytes representation of the DER formatted public key
- Returns
None
- classmethod output_tlsa_record(derkey: bytes, domain: str, port: int, protocol: str, tlsatype: str, warning: bool = False) None
Output the TLSA record for the given DER key, domain, port, protocol and tlsatype.
Call
self.generate_tlsa()
and output the result formatted as a DNS record- Parameters
derkey – The bytes representation the public key in DER format
domain – The service domain name (like
mail.example.com
)port – The service port (like
443
)protocol – The service protocol (like
tcp
)tlsatype – The TLSA type (like
312
)warning – Set True to output at level
WARNING
(defaultINFO
)
- Returns
None
- static parse_certgrinderd_ocsp_output(certgrinderd_stdout: bytes) Optional[cryptography.hazmat.backends.openssl.ocsp._OCSPResponse]
Parse a DER encoded binary OCSP response as returned by Certgrinderd.
- Parameters
certgrinderd_output – The bytes representing the OCSP response in DER format
- Returns
cryptography.hazmat.backends.openssl.ocsp._OCSPResponse
- static parse_certificate(certificate_bytes: bytes) Optional[cryptography.x509.base.Certificate]
Parse a bunch of bytes representing a PEM certificate and return.
- Parameters
certificate_bytes – The PEM certificate
- Returns
The parsed cryptography.x509.Certificate object or None
- parse_certificate_chain(certificate_chain: bytes, csr: cryptography.hazmat.backends.openssl.x509._CertificateSigningRequest) Optional[List[cryptography.x509.base.Certificate]]
Split a PEM chain into a list of certificates.
- Parameters
certificate_chain – The bytes representing the PEM formatted certificate chain
csr – The CSR this certificate was issued from
- Returns
A list of certificates with the leaf certificate first, or None if an error happens
- periodic() bool
The periodic method performs periodic maintenance tasks.
This method is called by the ‘periodic’ command, from cron or similar. It starts out by sleeping for a random period and then checks certificates and renews as needed.
- run_certgrinderd(stdin: bytes, command: List[str], certgrinderd_stdout: Optional[bytes] = None, certgrinderd_stderr: Optional[bytes] = None) Optional[bytes]
Run the configured
self.conf["certgrinderd"]
command.The stdin argument will be passed to stdin of the command. A CSR is needed for the “get certificate” certgrinderd command, and a certificate chain is needed for the “get ocsp” command.
- Parameters
stdin – bytes representing CSR or cert chain to pass to the certgrinderd command
command – The certgrinderd command and subcommand to call
certgrinderd_stdout – Mocked certgrinderd stdout to use instead of calling the command
certgrinderd_stderr – Mocked certgrinderd stderr to use instead of calling the command
- Returns
The bytes representing the stdout from the subprocess call
- static run_post_renew_hook(hook: List[str]) bool
Run a specific post renew hook.
- Parameters
hook – A list of string components of the command and arguments
Returns: True if exit code was 0, False otherwise.
- run_post_renew_hooks() bool
Loops over configured post_renew_hooks and executables in post_renew_hooks_dir and runs them.
- Returns
None
- static save_certificate(certificate: cryptography.x509.base.Certificate, path: str, issuers: List[cryptography.x509.base.Certificate] = []) None
Save the PEM certificate to the path, optionally with an issuer chain.
- Parameters
certificate – The certificate to save
path – The path to save the certificate in
issuer – The list of issuer certificates to write after the certificate (if any)
- Returns
None
- classmethod save_concat_certkey(keypair: Union[cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey], certificate: cryptography.x509.base.Certificate, issuers: List[cryptography.x509.base.Certificate], path: str) None
Create a single file with the private key, the cert and the issuer(s), in that order.
- Parameters
keypair – The keypair to save in the concat file
certificate – The certificate to save in the concat file
issuers – The list of issuer(s) to save in the concat file
path – The path to save the concat file in
- Returns
None
- static save_csr(csr: cryptography.hazmat.backends.openssl.x509._CertificateSigningRequest, path: str) None
Save the PEM version of the CSR to the path.
chmods the file 644 after writing.
- Parameters
csr – The CSR to be saved
path – The path to save the CSR to
- Returns
None
- static save_keypair(keypair: Union[cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey], path: str) None
Save keypair to disk.
- Parameters
keypair – The keypair to save
path – The path to save the keypair in
- Returns
None
- Raises
ValueError – For unsupported keytypes
- static save_ocsp_response(ocsp_response: cryptography.hazmat.backends.openssl.ocsp._OCSPResponse, path: str) None
Save the OCSP response to disk in DER format.
- Parameters
ocsp_response – The OCSP response to save
path – The path to save in
- Returns
None
- show_certificate() None
The
show certificate
subcommand method, called for each domainset byself.grind()
.- Returns
None
- show_ocsp() None
The
show ocsp
subcommand method, called for each domainset byself.grind()
.- Returns
None
- show_paths() None
The
show paths
subcommand method, called for each domainset byself.grind()
.- Returns
None
- show_spki() None
The
show spki
subcommand method, called for each domainset byself.grind()
.Call
self.output_spki()
with the DER formatted public key and output the result.- Returns
None
- show_tlsa() None
The ‘show tlsa’ subcommand method, called for each domainset by
self.grind()
.- Returns
None
- static split_pem_chain(pem_chain_bytes: bytes) List[bytes]
Split a PEM chain into a list of bytes of the individual PEM certificates.
- Parameters
pem_chain_bytes – The bytes representing the PEM chain
- Returns
A list of 0 or more bytes chunks representing each certificate
- classmethod verify_tlsa_record(derkey: bytes, domain: str, port: int, protocol: str, tlsatype: str, nameserver: str = '') bool
Check the TLSA records for the port/protocol/domain and DER key in the DNS.
Output the info needed to fix things when missing records are found.
- Parameters
derkey – The bytes representation the public key in DER format
domain – The service domain name (like
mail.example.com
)port – The service port (like
443
)protocol – The service protocol (like
tcp
)tlsatype – The TLSA type (like
312
)nameserver – The DNS server IP to use instead of system resolver (optional)
- Returns
True if all is well, False if one or more problems are found