Wiki source code of Icinga 2
Last modified by Sebastian Marsching on 2022/04/03 22:58
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 | Next, we create the configuration file for OpenSSL as `/var/lib/icinga2/ca/crl/openssl.cnf`: | ||
21 | |||
22 | # OpenSSL configuration for CRL generation | ||
23 | # | ||
24 | #################################################################### | ||
25 | [ ca ] | ||
26 | default_ca = CA_default # The default ca section | ||
27 | |||
28 | #################################################################### | ||
29 | [ CA_default ] | ||
30 | database = /var/lib/icinga2/ca/crl/index.txt | ||
31 | crlnumber = /var/lib/icinga2/ca/crl/crlnumber.txt | ||
32 | certificate = /var/lib/icinga2/ca/ca.crt | ||
33 | private_key = /var/lib/icinga2/ca/ca.key | ||
34 | |||
35 | crl_extensions = crl_ext # name of the section containing the | ||
36 | # CRL extensions | ||
37 | default_crl_days = 365 # how long before next CRL | ||
38 | default_crl_hours = 0 | ||
39 | default_md = sha256 # use SHA256 for signing the CRL | ||
40 | unique_subject = no # do not enforce unique certificate | ||
41 | # subjects | ||
42 | |||
43 | #################################################################### | ||
44 | [ crl_ext ] | ||
45 | # CRL extensions. | ||
46 | |||
47 | Finally, we want two shell scripts. One for generating the CRL and one for revoking a certificate. | ||
48 | |||
![]() |
2.1 | 49 | `/var/lib/icinga2/ca/crl/gen-crl.sh`: |
50 | |||
![]() |
1.1 | 51 | ```bash |
52 | #!/bin/bash | ||
53 | |||
54 | # Find the path to this file (this script might be referenced through a | ||
55 | # symbolic link). | ||
56 | CURRENT_WORKING_DIRECTORY="`pwd`" | ||
57 | THIS_FILE="$0" | ||
58 | cd "`dirname "$THIS_FILE"`" | ||
59 | THIS_FILE="`basename "$THIS_FILE"`" | ||
60 | while [ -L "$THIS_FILE" ]; do | ||
61 | THIS_FILE="`readlink "$THIS_FILE"`" | ||
62 | cd "`dirname "$THIS_FILE"`" | ||
63 | THIS_FILE="`basename "$THIS_FILE"`" | ||
64 | done | ||
65 | THIS_FILE="`pwd -P `/$THIS_FILE" | ||
66 | cd "$CURRENT_WORKING_DIRECTORY" | ||
67 | BASE_DIR="`dirname "$THIS_FILE"`" | ||
68 | |||
69 | openssl ca -config "$BASE_DIR/openssl.cnf" -gencrl -out "$BASE_DIR/crl.pem" | ||
70 | ``` | ||
71 | |||
![]() |
2.1 | 72 | `/var/lib/icinga2/ca/crl/revoke.sh`: |
73 | |||
![]() |
1.1 | 74 | ```bash |
75 | #!/bin/bash | ||
76 | |||
77 | # Find the path to this file (this script might be referenced through a | ||
78 | # symbolic link). | ||
79 | CURRENT_WORKING_DIRECTORY="`pwd`" | ||
80 | THIS_FILE="$0" | ||
81 | cd "`dirname "$THIS_FILE"`" | ||
82 | THIS_FILE="`basename "$THIS_FILE"`" | ||
83 | while [ -L "$THIS_FILE" ]; do | ||
84 | THIS_FILE="`readlink "$THIS_FILE"`" | ||
85 | cd "`dirname "$THIS_FILE"`" | ||
86 | THIS_FILE="`basename "$THIS_FILE"`" | ||
87 | done | ||
88 | THIS_FILE="`pwd -P `/$THIS_FILE" | ||
89 | cd "$CURRENT_WORKING_DIRECTORY" | ||
90 | BASE_DIR="`dirname "$THIS_FILE"`" | ||
91 | |||
92 | for cert in "$@"; do | ||
93 | openssl ca -config "$BASE_DIR/openssl.cnf" -revoke "$cert" | ||
94 | done | ||
95 | ``` | ||
96 | |||
97 | Do not forget to make the shell scripts executable: | ||
98 | |||
99 | ```bash | ||
100 | chmod a+x /var/lib/icinga2/ca/crl/gen-crl.sh | ||
101 | chmod a+x /var/lib/icinga2/ca/crl/revoke.sh | ||
102 | ``` | ||
103 | |||
104 | You might also want to change the owner of these files, though this step is entirely optional: | ||
105 | |||
106 | ```bash | ||
107 | chown -R nagios:nagios /var/lib/icinga2/ca/crl | ||
108 | ``` | ||
109 | |||
110 | Now in order to revoke a certificate, you call `revoke.sh` with the certificate file as the parameter. For example: | ||
111 | |||
112 | ```bash | ||
113 | /var/lib/icinga2/ca/crl/revoke.sh /var/lib/icinga2/ca/host.example.com.crt | ||
114 | ``` | ||
115 | |||
116 | After revoking a certificate, you have to regenerate the CRL in order to include the revoked certificate in the CRL: | ||
117 | |||
118 | ```bash | ||
119 | /var/lib/icinga2/ca/crl/gen-crl.sh | ||
120 | ``` | ||
121 | |||
122 | 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/). | ||
123 | |||
124 | 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. | ||
125 | |||
126 | 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`. | ||
127 | |||
128 | /** | ||
129 | * The API listener is used for distributed monitoring setups. | ||
130 | */ | ||
131 | |||
132 | object ApiListener "api" { | ||
133 | cert_path = SysconfDir + "/icinga2/pki/" + NodeName + ".crt" | ||
134 | key_path = SysconfDir + "/icinga2/pki/" + NodeName + ".key" | ||
135 | ca_path = SysconfDir + "/icinga2/pki/ca.crt" | ||
136 | crl_path = SysconfDir + "/icinga2/pki/crl.pem" | ||
137 | |||
138 | ticket_salt = TicketSalt | ||
139 | } | ||
140 | |||
141 | # Building a Python 3 compatble Debian package for Pynag | ||
142 | |||
143 | 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. | ||
144 | |||
145 | ```bash | ||
146 | PYNAG_VERSION=0.9.1 | ||
147 | PYNAG_GIT_COMMIT=bcdbd435dd48f9bf791b5d41307da93683cb17b3 | ||
148 | |||
149 | # We need python-stdeb and python3-stdeb in order to build the Debian packages. | ||
150 | # For some reason apt-get does not automatically install dh-python, python-all, | ||
151 | # and python3-all, even though they are needed (and recommended) for | ||
152 | # python-stdeb to work correctly. | ||
153 | sudo apt-get -y install dh-python python-all python3-all python-stdeb and python3-stdeb | ||
154 | |||
155 | curl -L -o pynag-$PYNAG_VERSION.tar.gz https://github.com/netmarkjp/pynag/archive/$PYNAG_GIT_COMMIT.tar.gz | ||
156 | |||
157 | # We have to specify DEB_BUILD_OPTIONS=nocheck because the tests have some | ||
158 | # additional dependencies that we do not want to install. | ||
159 | # We do not build the package for Python 2 because for Python 2, we can use the | ||
160 | # original version shipped with Ubuntu. | ||
161 | DEB_BUILD_OPTIONS=nocheck py2dsc-deb --with-python2=false --with-python3=true pynag-$PYNAG_VERSION.tar.gz | ||
162 | ``` |