This is a plugin for Nagios / Icinga to monitor the days left before a TLS certificate expires. An expired certificate isn't good and should never happen. Well, it happened to me and I got many E-Mails from people complaining about that.
There are two modes:
- Fetch a file via the network
- Read a local file
If you give an address and a port option 1 is choosen. If you set a file option 2 is choosen.
Fetch the script and place it in your PluginDir-Folder. Usually it's unter /usr/lib/nagios/plugins
The following applications and modules are needed:
- perl of course
- openssl
- Perl module "Crypt::OpenSSL::X509"
- Perl module "Date::Calc"
- Perl module "IPC::Run3"
If you are on a Debian/Ubuntu based machine you can install the needed perl modules via apt:
apt-get install libdate-calc-perl libcrypt-openssl-x509-perl libipc-run3-perl
Another way is to fetch it over CPAN. Your choice!
I don't have Nagios so I don't know how to configure it :-) I tried to developed the plugin according to the "Nagios Plugin Development Guidelines" so there shouldn't be any problem implementing this check in a nagios compatible environment.
Navigate on your Icinga 2 server to your config folder (Normally /etc/icinga2/conf.d
).
I placed the following piece of code in commands.cfg
:
object CheckCommand "tls_certificate_expiration" {
import "plugin-check-command"
command = [ PluginDir + "/check_tls_certificate_expiration" ]
arguments = {
"--address" = "$tls_address$"
"--port" = "$tls_port$"
"--hostname" = "$tls_hostname$"
"--common-name" = "$tls_common_name$"
"--file" = "$tls_file$"
"--warn" = "$tls_warn$"
"--crit" = "$tls_crit$"
"--openssl" = "$tls_openssl$"
"--starttls" = "$tls_protocol$"
}
vars.tls_address = "$address$"
}
To add the check to a host use this snippet in a host configuration file:
object Host "mineralwasser" {
[...]
}
object Service "tls_blog.veloc1ty.de" {
host_name = "mineralwasser"
display_name = "TLS expire blog.veloc1ty.de"
check_interval = 1d
check_command = "tls_certificate_expiration"
vars.tls_hostname = "blog.veloc1ty.de"
}
Of course you can change check_interval to the value you desire. Since the plugin calculates in whole days one check every day is enough.
If you want to add a service group for this check you can simply add the following snippet in groups.conf
:
object ServiceGroup "tls_certificate_expiration" {
display_name = "TLS certificate expiration"
assign where service.check_command == "tls_certificate_expiration"
}
If you want to add it to multiple hosts work with apply
!
That's it. Pretty simple. Reload or restart icinga2 and check the result in your browser.
The CheckCommand and the plugin accept various arguments:
CheckCommand Variable | Plugin Argument | Description |
---|---|---|
tls_address | --address | The address of the server |
tls_port | --port | The port to connect to. Default: 443 |
tls_hostname | --hostname | The hostname which should be sent as SNI |
tls_common_name | --common-name | The command name of the certificate |
tls_file | --file | Path to the file |
tls_warn | --warn | Amount of days left until certificate expires. Default: 21 |
tls_crit | --crit | Amount of days left until certificate expires. Default: 14 |
tls_openssl | --openssl | Path to the openssl binary. Default: /usr/bin/openssl |
tls_protocol | --starttls | One in "smtp", "pop3", "imap", "ftp" or "xmpp" |
Hint: Not every parameter has to be set.
If you specify tls_address the plugin does a network fetch and ignores file settings.
If you specify tls_file the plugin reads from file and ignores the network settings.
tls_warn,tls_crit, tls_common_name and tls_openssl can always be set.
Note: If you don't specify tls_common_name the common name check is skipped.
Note: The CheckCommand is always the same. The host "mineralwasser" is given.
object Service "tls-blog-veloc1ty-de" {
import "generic-service"
check_command = "tls_certificate_expiration"
host_name = "mineralwasser"
vars.tls_hostname = "blog.veloc1ty.de"
vars.tls_common_name = "blog.veloc1ty.de"
// Note: address is automatically set to the host's address
// Note: port is default 443
// Note: If you skip tls_common_name common name checking is disabled
}
object Service "tls-mail-veloc1ty-de" {
import "generic-service"
check_command = "tls_certificate_expiration"
host_name = "mineralwasser"
vars.tls_port = "993"
// Note: address is automatically set to the host's address
// Note: no SNI is needed, so we can skip "tls_hostname"
}
object Service "tls-veloc1ty-ca" {
import "generic-service"
check_command = "tls_certificate_expiration"
host_name = "mineralwasser"
vars.tls_file = "/path/to/veloc1tyCA.pem"
// Note: address is automatically set to the host's address
}
Special thanks to Jan from biocrafting.net for notifying me about the SNI issue!