Wiki source code of Icinga 2
Version 1.2 by Sebastian Marsching on 2022/04/03 14:08
Hide last authors
| author | version | line-number | content |
|---|---|---|---|
| |
1.1 | 1 | {{toc/}} |
| 2 | |||
| 3 | # Using a Certificate Revocation List (CRL) with Icinga 2 | ||
| 4 | |||
| 5 | **Before you start**: There is a [bug](https://github.com/Icinga/icinga2/issues/5040) in Icinga 2 (at least up to version 2.6.2) that prevents a CRL from being loaded, so you have to ensure that you use a newer version or patch the bug yourself. | ||
| 6 | |||
| 7 | Icinga 2 makes managing the CA easy by using the `icinga2 pki` commands. However, it does not provide any commands for generating a CRL. This means that the regular `openssl` tool needs to be used for that. The functions for generating a CRL are part of the `ca` module, so one first has to create a CA configuration for OpenSSL. For the rest of this tutorial, we assume that the certificates for Icinga 2 are stored in the default location (`/var/lib/icinga2/ca`). | ||
| 8 | |||
| 9 | First, we create the directory `/var/lib/icinga2/ca/crl` and a number of files needed in this directory: | ||
| 10 | |||
| 11 | ```bash | ||
| 12 | mkdir /var/lib/icinga2/ca/crl | ||
| 13 | cd /var/lib/icinga2/ca/crl | ||
| 14 | touch index.txt | ||
| 15 | echo "unique_subject = no" >index.txt.attr | ||
| 16 | echo "0000" >crlnumber.txt | ||
| 17 | touch crl.pem | ||
| 18 | |||
| 19 | ``` | ||
| 20 | |||
| 21 | Next, we create the configuration file for OpenSSL as `/var/lib/icinga2/ca/crl/openssl.cnf`: | ||
| 22 | |||
| 23 | # OpenSSL configuration for CRL generation | ||
| 24 | # | ||
| 25 | #################################################################### | ||
| 26 | [ ca ] | ||
| 27 | default_ca = CA_default # The default ca section | ||
| 28 | |||
| 29 | #################################################################### | ||
| 30 | [ CA_default ] | ||
| 31 | database = /var/lib/icinga2/ca/crl/index.txt | ||
| 32 | crlnumber = /var/lib/icinga2/ca/crl/crlnumber.txt | ||
| 33 | certificate = /var/lib/icinga2/ca/ca.crt | ||
| 34 | private_key = /var/lib/icinga2/ca/ca.key | ||
| 35 | |||
| 36 | crl_extensions = crl_ext # name of the section containing the | ||
| 37 | # CRL extensions | ||
| 38 | default_crl_days = 365 # how long before next CRL | ||
| 39 | default_crl_hours = 0 | ||
| 40 | default_md = sha256 # use SHA256 for signing the CRL | ||
| 41 | unique_subject = no # do not enforce unique certificate | ||
| 42 | # subjects | ||
| 43 | |||
| 44 | #################################################################### | ||
| 45 | [ crl_ext ] | ||
| 46 | # CRL extensions. | ||
| 47 | |||
| 48 | Finally, we want two shell scripts. One for generating the CRL and one for revoking a certificate. | ||
| 49 | |||
| 50 | ```bash | ||
| 51 | #!/bin/bash | ||
| 52 | |||
| 53 | # Find the path to this file (this script might be referenced through a | ||
| 54 | # symbolic link). | ||
| 55 | CURRENT_WORKING_DIRECTORY="`pwd`" | ||
| 56 | THIS_FILE="$0" | ||
| 57 | cd "`dirname "$THIS_FILE"`" | ||
| 58 | THIS_FILE="`basename "$THIS_FILE"`" | ||
| 59 | while [ -L "$THIS_FILE" ]; do | ||
| 60 | THIS_FILE="`readlink "$THIS_FILE"`" | ||
| 61 | cd "`dirname "$THIS_FILE"`" | ||
| 62 | THIS_FILE="`basename "$THIS_FILE"`" | ||
| 63 | done | ||
| 64 | THIS_FILE="`pwd -P `/$THIS_FILE" | ||
| 65 | cd "$CURRENT_WORKING_DIRECTORY" | ||
| 66 | BASE_DIR="`dirname "$THIS_FILE"`" | ||
| 67 | |||
| 68 | openssl ca -config "$BASE_DIR/openssl.cnf" -gencrl -out "$BASE_DIR/crl.pem" | ||
| 69 | ``` | ||
| 70 | |||
| 71 | ```bash | ||
| 72 | #!/bin/bash | ||
| 73 | |||
| 74 | # Find the path to this file (this script might be referenced through a | ||
| 75 | # symbolic link). | ||
| 76 | CURRENT_WORKING_DIRECTORY="`pwd`" | ||
| 77 | THIS_FILE="$0" | ||
| 78 | cd "`dirname "$THIS_FILE"`" | ||
| 79 | THIS_FILE="`basename "$THIS_FILE"`" | ||
| 80 | while [ -L "$THIS_FILE" ]; do | ||
| 81 | THIS_FILE="`readlink "$THIS_FILE"`" | ||
| 82 | cd "`dirname "$THIS_FILE"`" | ||
| 83 | THIS_FILE="`basename "$THIS_FILE"`" | ||
| 84 | done | ||
| 85 | THIS_FILE="`pwd -P `/$THIS_FILE" | ||
| 86 | cd "$CURRENT_WORKING_DIRECTORY" | ||
| 87 | BASE_DIR="`dirname "$THIS_FILE"`" | ||
| 88 | |||
| 89 | for cert in "$@"; do | ||
| 90 | openssl ca -config "$BASE_DIR/openssl.cnf" -revoke "$cert" | ||
| 91 | done | ||
| 92 | ``` | ||
| 93 | |||
| 94 | Do not forget to make the shell scripts executable: | ||
| 95 | |||
| 96 | ```bash | ||
| 97 | chmod a+x /var/lib/icinga2/ca/crl/gen-crl.sh | ||
| 98 | chmod a+x /var/lib/icinga2/ca/crl/revoke.sh | ||
| 99 | ``` | ||
| 100 | |||
| 101 | You might also want to change the owner of these files, though this step is entirely optional: | ||
| 102 | |||
| 103 | ```bash | ||
| 104 | chown -R nagios:nagios /var/lib/icinga2/ca/crl | ||
| 105 | ``` | ||
| 106 | |||
| 107 | Now in order to revoke a certificate, you call `revoke.sh` with the certificate file as the parameter. For example: | ||
| 108 | |||
| 109 | ```bash | ||
| 110 | /var/lib/icinga2/ca/crl/revoke.sh /var/lib/icinga2/ca/host.example.com.crt | ||
| 111 | ``` | ||
| 112 | |||
| 113 | After revoking a certificate, you have to regenerate the CRL in order to include the revoked certificate in the CRL: | ||
| 114 | |||
| 115 | ```bash | ||
| 116 | /var/lib/icinga2/ca/crl/gen-crl.sh | ||
| 117 | ``` | ||
| 118 | |||
| 119 | In order to actually use the CRL, you have to distribute it to the Icinga 2 nodes. How to do this is outside of the scope of this tutorial. One might simply use [scp](http://man.openbsd.org/scp) or one could use a configuration management tool like [SaltStack](https://saltstack.com/). | ||
| 120 | |||
| 121 | One thing to consider when distributing the CRL is its validity period: When using a CRL, Icinga 2 will start to reject **all** certificates (even the ones which have not expired yet and have not been revoked either) when the CRL has expired. This means that a new CRL has to be distributed before the old one expires. Choosing a longer validity period (by changing the `crldays` and `crlhours` options in the OpenSSL configuration) might help so that you can distribute the CRL less often. For example, the certificiates generated by Icinga 2 are valid for 5475 days (approximately 15 years). However, in contrast to certificates, there is no way to revoke a CRL. This means that if an attacker got hold of a CRL (which is not unlikely because a CRL is generally considered public information) and found a way to inject that CRL in the distribution process, he might be able to make a node use an old version of the CRL, thus accepting certificates that have been revoked in the meantime. When using a secure channel (like SSH) for distributing the CRL, you might not be worried too much about this scenario. | ||
| 122 | |||
| 123 | In order to make Icinga 2 use the CRL, it has to be registered with the API listener. The following configuration (typically stored in `/etc/icinga2/features-available/api.conf`) assumes that the CRL is stored in `/etc/icinga2/pki/crl.pem`. | ||
| 124 | |||
| 125 | /** | ||
| 126 | * The API listener is used for distributed monitoring setups. | ||
| 127 | */ | ||
| 128 | |||
| 129 | object ApiListener "api" { | ||
| 130 | cert_path = SysconfDir + "/icinga2/pki/" + NodeName + ".crt" | ||
| 131 | key_path = SysconfDir + "/icinga2/pki/" + NodeName + ".key" | ||
| 132 | ca_path = SysconfDir + "/icinga2/pki/ca.crt" | ||
| 133 | crl_path = SysconfDir + "/icinga2/pki/crl.pem" | ||
| 134 | |||
| 135 | ticket_salt = TicketSalt | ||
| 136 | } | ||
| 137 | |||
| 138 | # Building a Python 3 compatble Debian package for Pynag | ||
| 139 | |||
| 140 | Ubuntu 18.04 includes the `python-pynag` package, but only for Python 2. There is no `python3-pynag` package, because the upstream version of Pynag is not compatible with Python 3. Luckily, there is a [fork](https://github.com/netmarkjp/) that is compatible with Python 3. The following shell script can be used to build a Debian package of this fork. This package should be compatible with Ubuntu as well. | ||
| 141 | |||
| 142 | ```bash | ||
| 143 | PYNAG_VERSION=0.9.1 | ||
| 144 | PYNAG_GIT_COMMIT=bcdbd435dd48f9bf791b5d41307da93683cb17b3 | ||
| 145 | |||
| 146 | # We need python-stdeb and python3-stdeb in order to build the Debian packages. | ||
| 147 | # For some reason apt-get does not automatically install dh-python, python-all, | ||
| 148 | # and python3-all, even though they are needed (and recommended) for | ||
| 149 | # python-stdeb to work correctly. | ||
| 150 | sudo apt-get -y install dh-python python-all python3-all python-stdeb and python3-stdeb | ||
| 151 | |||
| 152 | curl -L -o pynag-$PYNAG_VERSION.tar.gz https://github.com/netmarkjp/pynag/archive/$PYNAG_GIT_COMMIT.tar.gz | ||
| 153 | |||
| 154 | # We have to specify DEB_BUILD_OPTIONS=nocheck because the tests have some | ||
| 155 | # additional dependencies that we do not want to install. | ||
| 156 | # We do not build the package for Python 2 because for Python 2, we can use the | ||
| 157 | # original version shipped with Ubuntu. | ||
| 158 | DEB_BUILD_OPTIONS=nocheck py2dsc-deb --with-python2=false --with-python3=true pynag-$PYNAG_VERSION.tar.gz | ||
| 159 | ``` |