feat: add NRPE probes

This commit is contained in:
Stéphane Lesimple 2021-12-30 15:22:50 +00:00 committed by Stéphane Lesimple
parent e71aa7b975
commit bbdf5a36b8
22 changed files with 714 additions and 0 deletions

View file

@ -53,6 +53,8 @@ chmod 0755 "$basedir"/docker/entrypoint.sh \
"$basedir"/tests/functional/proxy/remote-daemon \ "$basedir"/tests/functional/proxy/remote-daemon \
"$basedir"/tests/functional/fake_ttyrec.sh "$basedir"/tests/functional/fake_ttyrec.sh
find "$basedir"/contrib/nrpe/probes -type f -print0 | xargs -r0 chmod 0755
find "$basedir"/tests/unit -type f -name "*.pl" -print0 | xargs -r0 chmod 0755 find "$basedir"/tests/unit -type f -name "*.pl" -print0 | xargs -r0 chmod 0755
while IFS= read -r -d '' plugin while IFS= read -r -d '' plugin

15
contrib/nrpe/README.md Normal file
View file

@ -0,0 +1,15 @@
NRPE Probes
===========
A few NRPE probes are available in the ``probes/`` subdirectory.
Some of these probes might need to have elevated rights, an example of sudoers file is included.
You might want to also use the nice ``check_logfiles`` probe, courtesy of
Consol Labs (https://labs.consol.de/nagios/check_logfiles/index.html), to ensure
that the cron scripts behave correctly and that no error is happening during the backup process,
the encrypt & rsync process, the HA synchronization daemon, etc.
The configuration of the ``check_logfiles`` probe can be found in ``etc/nagios/plugins.d``.
The bastion-side NRPE daemon configuration for these probes can be found in the ``etc/nagios/nrpe.d``.

View file

@ -0,0 +1 @@
command[check_bastion_healthcheck]=/usr/bin/sudo -u healthcheck /opt/bastion/contrib/nrpe/probes/bastion-healthcheck --host 127.0.0.1 --port 22 --account healthcheck --keyfile /home/healthcheck/.ssh/id_healthcheck

View file

@ -0,0 +1 @@
command[check_bastion_http_proxy]=/opt/bastion/contrib/nrpe/probes/bastion-http-proxy --host 127.0.0.1 --port 8443 --disabled-ok

View file

@ -0,0 +1 @@
command[check_bastion_locked]=/opt/bastion/contrib/nrpe/probes/bastion-locked

View file

@ -0,0 +1 @@
command[check_bastion_root_connected_too_long]=/opt/bastion/contrib/nrpe/probes/bastion-root-connected-too-long --warn-after-minutes 60 --crit-after-minutes 180

View file

@ -0,0 +1 @@
command[check_bastion_sync_daemon]=/usr/lib/nagios/plugins/check_dummy 0 'osh-sync-watcher is not intended to run on slave bastions'

View file

@ -0,0 +1 @@
command[check_bastion_version]=/opt/bastion/contrib/nrpe/probes/bastion-version

View file

@ -0,0 +1 @@
command[check_log_bastion_backup]=/usr/bin/sudo -u root /usr/lib/nagios/check_logfiles -f /etc/nagios/plugins.d/ovh/check_logfiles.cfg --searches=bastion_backup

View file

@ -0,0 +1 @@
command[check_log_bastion_encrypt_rsync]=/usr/bin/sudo -u root /usr/lib/nagios/check_logfiles -f /etc/nagios/plugins.d/ovh/check_logfiles.cfg --searches=bastion_encrypt_rsync

View file

@ -0,0 +1 @@
command[check_log_bastion_guest_key_cleanup]=/usr/bin/sudo -u root /usr/lib/nagios/check_logfiles -f /etc/nagios/plugins.d/ovh/check_logfiles.cfg --searches=bastion_guest_key_cleanup

View file

@ -0,0 +1 @@
command[check_log_bastion_misc]=/usr/bin/sudo -u root /usr/lib/nagios/check_logfiles -f /etc/nagios/plugins.d/ovh/check_logfiles.cfg --searches=bastion_misc

View file

@ -0,0 +1 @@
command[check_log_bastion_orphaned_homedir]=/usr/bin/sudo -u root /usr/lib/nagios/check_logfiles -f /etc/nagios/plugins.d/ovh/check_logfiles.cfg --searches=bastion_orphaned_homedir

View file

@ -0,0 +1 @@
command[check_log_bastion_piv_grace]=/usr/bin/sudo -u root /usr/lib/nagios/check_logfiles -f /etc/nagios/plugins.d/ovh/check_logfiles.cfg --searches=bastion_piv_grace

View file

@ -0,0 +1 @@
command[check_log_bastion_secondaries_sync]=/usr/bin/sudo -u root /usr/lib/nagios/check_logfiles -f /etc/nagios/plugins.d/ovh/check_logfiles.cfg --searches=bastion_secondaries_sync

View file

@ -0,0 +1,56 @@
# where the state information will be saved.
$seekfilesdir = '/var/cache/nagios';
# where protocols with found patterns will be stored.
$protocolsdir = $seekfilesdir;
@searches = (
{
tag => 'bastion_backup',
logfile => '/var/log/bastion/bastion-scripts.log',
criticalpatterns => ["will not be encrypted", "ERROR:"],
okpatterns => ["Done, got 0 error"],
options => 'allyoucaneat, sticky=86400, syslogclient=osh-backup-acl-keys.sh',
},
{
tag => 'bastion_encrypt_rsync',
logfile => '/var/log/bastion/bastion-scripts.log',
criticalpatterns => ["ERROR:"],
okpatterns => ["Done, got 0 error"],
options => 'allyoucaneat, sticky=86400, syslogclient=osh-encrypt-rsync.pl',
},
{
tag => 'bastion_orphaned_homedir',
logfile => '/var/log/bastion/bastion-scripts.log',
criticalpatterns => ["ERROR:"],
okpatterns => ["Done, got 0 error"],
options => 'allyoucaneat, sticky=900, syslogclient=osh-orphaned-homedir.sh',
},
{
tag => 'bastion_piv_grace',
logfile => '/var/log/bastion/bastion-scripts.log',
criticalpatterns => ["ERROR:"],
okpatterns => ["Done, got 0 error"],
options => 'allyoucaneat, sticky=900, syslogclient=osh-piv-grace-reaper.pl',
},
{
tag => 'bastion_guest_key_cleanup',
logfile => '/var/log/bastion/bastion-scripts.log',
criticalpatterns => ["ERROR:"],
okpatterns => ["Done, got 0 error"],
options => 'allyoucaneat, sticky=900, syslogclient=osh-cleanup-guest-key-access.pl',
},
{
tag => 'bastion_misc',
logfile => '/var/log/bastion/bastion-scripts.log',
criticalpatterns => ["osh-lingering-sessions-reaper.sh.*ERROR:", "osh-rotate-ttyrec.sh.*ERROR:"],
options => 'allyoucaneat, sticky=900',
},
{
tag => 'bastion_secondaries_sync',
logfile => '/var/log/bastion/bastion-scripts.log',
criticalpatterns => ["ERROR:"],
okpatterns => ["All secondaries have been synchronized successfully"],
options => 'allyoucaneat, sticky=900, syslogclient=osh-sync-watcher.sh, criticalthreshold=6',
},
);

View file

@ -0,0 +1,107 @@
#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
#
# DESC: Check that the bastion code works (healtheck)
use strict;
use warnings;
use File::Basename;
use Getopt::Long;
my $PROBE_NAME = basename($0);
my $debug;
## no critic (Subroutines::RequireArgUnpacking)
## no critic (Subroutines::RequireFinalReturn)
sub _out {
my ($criticity, $msg) = @_;
printf "%s %4s - %s\n", $PROBE_NAME, $criticity, $msg;
}
sub _dbg { _out('dbg', $_[0]) if $debug; }
sub _info { _out('info', $_[0]); }
sub _warn { _out('WARN', $_[0]); }
sub _err { _out('ERR!', $_[0]); }
sub success { my $msg = shift; _info($msg) if $msg; _info("status=OK"); exit(0); }
sub warning { my $msg = shift; _warn($msg) if $msg; _info("status=WARN"); exit(1); }
sub failure { my $msg = shift; _err($msg) if $msg; _info("status=FAILURE"); exit(2); }
sub unknown { my $msg = shift; _err($msg) if $msg; _info("status=UNKNOWN"); exit(3); }
# OPTIONS
my $host = "127.0.0.1";
my $port = 22;
my $account = 'healthcheck';
my $keyfile = '/home/healthcheck/.ssh/id_healthcheck';
my $kbdinteractive = 0;
GetOptions(
"help" => \my $help,
"debug!" => \$debug,
"host=s" => \$host,
"port=i" => \$port,
"account=s" => \$account,
"keyfile=s" => \$keyfile,
"kbd-interactive" => \$kbdinteractive,
) or unknown("Failed parsing command-line");
# HELP
if ($help) {
print <<"EOF";
$PROBE_NAME [options]
--help This help message
--debug Increase verbosity of logs
--host HOST Host to connect to. Default: $host
--port PORT Port to connect to. Default: $port
--account ACCOUNT Account name to use to authenticate. Default: $account
--keyfile PATH Path to the private SSH key file to authenticate. Defaut: $keyfile
--kbd-interactive Allow keyboard-interactive authentication. Default: $kbdinteractive
Note: don't specify an other option than --help to get the proper default values.
EOF
unknown();
}
# CODE
if ($account !~ /^[a-zA-Z0-9._-]+$/) {
unknown("Specified account is invalid ($account)");
}
if ($host !~ /^[a-zA-Z0-9._-]+$/) {
unknown("Specified host is invalid ($host)");
}
if ($port <= 0 || $port > 65535) {
unknown("Specified port is invalid ($port)");
}
if (!-f -r $keyfile) {
unknown("Specified keyfile '$keyfile' is not readable or not a file");
}
# first; check that sudo is healthy
_dbg("Checking sudo viability...");
my $sysret = system(qw{ sudo -n -v });
if ($sysret != 0) {
critical("sudo is broken!");
}
my @cmd = ('ssh', '-l', $account, '-i', $keyfile, '-p', $port);
if ($kbdinteractive) {
push @cmd, ('-o', 'KbdInteractiveAuthentication=yes', '-o', 'PreferredAuthentications=publickey,keyboard-interactive');
}
push @cmd, ($host, '--', '-q', '--osh', 'info');
_dbg("Executing: " . join(" ", @cmd));
$sysret = system(@cmd);
if ($sysret == 0) {
success("Connection worked and ended successfully");
}
failure("Connection failed (SSH return code = " . ($sysret >> 8) . ")");

View file

@ -0,0 +1,133 @@
#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
#
# DESC: Warn if the bastion HTTPS proxy is down
use strict;
use warnings;
use File::Basename;
use Getopt::Long;
use LWP::UserAgent;
use IO::Socket::SSL;
use JSON;
my $PROBE_NAME = basename($0);
my $debug;
## no critic (Subroutines::RequireArgUnpacking)
## no critic (Subroutines::RequireFinalReturn)
sub _out {
my ($criticity, $msg) = @_;
printf "%s %4s - %s\n", $PROBE_NAME, $criticity, $msg;
}
sub _dbg { _out('dbg', $_[0]) if $debug; }
sub _info { _out('info', $_[0]); }
sub _warn { _out('WARN', $_[0]); }
sub _err { _out('ERR!', $_[0]); }
sub success { my $msg = shift; _info($msg) if $msg; _info("status=OK"); exit(0); }
sub warning { my $msg = shift; _warn($msg) if $msg; _info("status=WARN"); exit(1); }
sub failure { my $msg = shift; _err($msg) if $msg; _info("status=FAILURE"); exit(2); }
sub unknown { my $msg = shift; _err($msg) if $msg; _info("status=UNKNOWN"); exit(3); }
# OPTIONS
my $host = "127.0.0.1";
my $DEFAULT_PORT = 8443;
my $disabledOk = 0; # don't warn if proxy is disabled
my $port;
GetOptions(
"help" => \my $help,
"debug!" => \$debug,
"host=s" => \$host,
"port=i" => \$port,
"disabled-ok" => \$disabledOk,
) or unknown("Failed parsing command-line");
# attempt to get a better shot at the default port
my $json_data;
if (open(my $conf, "<", "/etc/bastion/osh-http-proxy.conf")) {
_dbg("opened https bastion config");
local $/ = undef;
$json_data = <$conf>;
close($conf);
$json_data =~ s/#.*//g;
my $json;
eval { $json = decode_json($json_data); };
if ($@) {
_dbg("error decoding json ($@), keeping default port to $DEFAULT_PORT, and assuming proxy is enabled");
$json->{'enabled'} = 1;
}
# if config has a port and no port is specified on cmdline
if ($json->{'port'} && !$port) {
$port = $json->{'port'};
_dbg("will use port $port as default, from config");
}
# proxy is disabled by config
if (!$json->{'enabled'}) {
if ($disabledOk) {
success("Proxy is disabled, and got --disabled-ok");
}
else {
_warn("Proxy is disabled, but didn't get --disabled-ok, attempting to test nevertheless");
}
}
close($conf);
}
else {
if ($disabledOk) {
success("Specified --disabled-ok but couldn't find config file, assuming it's not installed");
}
_dbg("Couldn't open https bastion config, keeping default port to $DEFAULT_PORT");
}
$port = $DEFAULT_PORT if not defined $port;
# HELP
if ($help) {
print <<"EOF";
$PROBE_NAME [options]
--help This help message
--debug Increase verbosity of logs
--host HOST Host to connect to. Default: $host
--port PORT Port to connect to. Default: $port (tentatively
autodected from the HTTPS Bastion proxy configuration)
--disabled-ok Return success even if Proxy is disabled (from config)
EOF
unknown();
}
# CODE
# verify_hostname == 0 is ok because that's not what we're verifying here
my $ua = LWP::UserAgent->new(
agent => 'NRPE',
ssl_opts => {
verify_hostname => 0,
SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE
}
);
my $result = $ua->get("https://$host:$port/bastion-health-check");
_info("Got HTTP result code " . $result->code);
if ($result->code == 200) {
success("> $_") for split /\n/, $result->decoded_content;
}
elsif ($result->code == 202) {
warning("> $_") for split /\n/, $result->decoded_content; # daemon should be reloaded
}
else {
failure("> $_") for split /\n/, $result->decoded_content;
}

View file

@ -0,0 +1,60 @@
#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
#
# DESC: Warn if bastion is locked (/home encrypted)
use strict;
use warnings;
use File::Basename;
use Getopt::Long;
my $PROBE_NAME = basename($0);
my $debug;
## no critic (Subroutines::RequireArgUnpacking)
## no critic (Subroutines::RequireFinalReturn)
sub _out {
my ($criticity, $msg) = @_;
printf "%s %4s - %s\n", $PROBE_NAME, $criticity, $msg;
}
sub _dbg { _out('dbg', $_[0]) if $debug; }
sub _info { _out('info', $_[0]); }
sub _warn { _out('WARN', $_[0]); }
sub _err { _out('ERR!', $_[0]); }
sub success { my $msg = shift; _info($msg) if $msg; _info("status=OK"); exit(0); }
sub warning { my $msg = shift; _warn($msg) if $msg; _info("status=WARN"); exit(1); }
sub failure { my $msg = shift; _err($msg) if $msg; _info("status=FAILURE"); exit(2); }
sub unknown { my $msg = shift; _err($msg) if $msg; _info("status=UNKNOWN"); exit(3); }
# OPTIONS
GetOptions(
"help" => \my $help,
"debug!" => \$debug,
) or unknown("Failed parsing command-line");
# HELP
if ($help) {
print <<"EOF";
$PROBE_NAME [options]
--help This help message
--debug Increase verbosity of logs
EOF
unknown();
}
# CODE
if (-d "/home/allowkeeper") {
_dbg("/home/allowkeeper exists and is a directory");
success("bastion /home is unlocked");
}
_dbg("/home/allowkeeper doesn't exists or is not a directory");
failure("bastion /home is locked!");

View file

@ -0,0 +1,192 @@
#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
#
# DESC: Check that a process with attached tty running as root
# is not there since more than X hours
use strict;
use warnings;
use File::Basename;
use List::Util qw/first/;
use IPC::Open3 'open3';
use Getopt::Long;
$SIG{'CHLD'} = 'IGNORE'; # don't bother using waitpid on this short-lived probe
my $PROBE_NAME = basename($0);
my $debug;
## no critic (Subroutines::RequireArgUnpacking)
## no critic (Subroutines::RequireFinalReturn)
sub _out {
my ($criticity, $msg) = @_;
printf "%s %4s - %s\n", $PROBE_NAME, $criticity, $msg;
}
sub _dbg { _out('dbg', $_[0]) if $debug; }
sub _info { _out('info', $_[0]); }
sub _warn { _out('WARN', $_[0]); }
sub _err { _out('ERR!', $_[0]); }
sub success { my $msg = shift; _info($msg) if $msg; _info("status=OK"); exit(0); }
sub warning { my $msg = shift; _warn($msg) if $msg; _info("status=WARN"); exit(1); }
sub failure { my $msg = shift; _err($msg) if $msg; _info("status=FAILURE"); exit(2); }
sub unknown { my $msg = shift; _err($msg) if $msg; _info("status=UNKNOWN"); exit(3); }
# OPTIONS
my $warnAfterMinutes = 30;
my $critAfterMinutes = 120;
GetOptions(
"help" => \my $help,
"debug!" => \$debug,
"warn-after-minutes=i" => \$warnAfterMinutes,
"crit-after-minutes=i" => \$critAfterMinutes,
) or unknown("Failed parsing command-line");
# HELP
if ($help) {
print <<"EOF";
$PROBE_NAME [options]
--help This help message
--debug Increase verbosity of logs
--warn-after-minutes NB Exit with a WARN exit code after a root process has been logged in for more than
this amount of minutes. Use 0 to never WARN. Default: $warnAfterMinutes
--crit-after-minutes NB Exit with a CRIT exit code after a root process has been logged in for more than
this amount of minutes. Use 0 to never CRIT. Default: $critAfterMinutes
Note: don't specify an other option than --help to get the proper default values.
EOF
unknown();
}
# CODE
_dbg("Getting system clock tick");
my ($stdin, $stdout);
eval { open3($stdin, $stdout, '>&STDERR', qw{ getconf CLK_TCK }); };
if ($@) {
unknown("Couldn't start 'getconf' process");
}
close($stdin);
my $clockTick = <$stdout>;
close($stdout);
chomp($clockTick);
_dbg("clocktick is $clockTick");
_dbg("Getting uptime");
open(my $fh, '<', "/proc/uptime") or unknown("Cannot open /proc/uptime: $!");
my $uptimeData = <$fh>;
close $fh;
my $uptime;
if ($uptimeData =~ /^(\d+)/) {
$uptime = $1;
}
else {
unknown("Cannot parse uptime! '$uptimeData'");
}
_dbg("Uptime is $uptime seconds");
_dbg('Getting the list of processes that have a tty');
$stdin = $stdout = undef;
eval { open3($stdin, $stdout, '>&STDERR', qw{ ps aho pid }); };
if ($@) {
unknown("Couldn't start 'ps' process");
}
close($stdin);
my @pidlist = <$stdout>;
close($stdout);
s/^\s+|\s+$//g for @pidlist;
_dbg('Found ' . (scalar @pidlist) . ' PIDs having a tty');
my $criticalCount = 0;
my $warningCount = 0;
PID: foreach my $pid (@pidlist) {
next if $pid !~ /^\d+$/;
my $fh;
if (not open($fh, '<', "/proc/$pid/status")) {
_dbg("Couldn't open /proc/$pid/status ($!), probably a disappeared process (race condition)");
next;
}
while (<$fh>) {
next if (not /^[UG]id:/); # parse Uid / Gid numbers
my ($id1, $id2, undef, $id4) = /(\d+)/g;
next PID if (not grep { $_ == 0 } ($id1, $id2, $id4)); # Root detected
_dbg("process $pid running as root, analyzing tty");
# Checking if exe is agetty, as it triggers the probe but is NOT a security issue
my $binary = readlink("/proc/$pid/exe");
chomp($binary);
_dbg("Binary is $binary");
# The regex with 'deleted' handles upgrade of binaries, which are tagged deleted in proc/exe
next PID if ($binary =~ m{^(/usr)?/s?bin/agetty( \(deleted\))?$});
next PID if ($binary =~ m{^/usr/bin/sudo( \(deleted\))?$});
next PID if ($binary =~ m{^(/usr)?/bin/minijail0( \(deleted\))?$});
_dbg("check age of $pid");
my $stat;
if (not open($stat, '<', "/proc/$pid/stat")) {
_dbg("couldn't open /proc/$pid/stat ($!), probably a disappeared process (race condition), getting to the next one");
next PID;
}
my @stats = split(/\s+/, <$stat>);
close $stat;
my $startTime = $stats[21]; # in %llu, number of clock ticks, see man 5 proc
my $processUptime = $uptime - ($startTime / $clockTick);
$processUptime = int($processUptime / 60); # minutes conversion
_dbg("$pid Up since $processUptime minutes");
# Get guilty Admin
my $guilty = '??UNKNOWN??';
if (open(my $envfh, "<", "/proc/$pid/environ")) {
my $guiltyEnv = first { /LC_BASTION=(\w+)/ } <$envfh>;
if (defined $guiltyEnv and $guiltyEnv =~ /LC_BASTION=(\w+)/) {
$guilty = $1;
}
close $envfh;
}
# Get cmdline
my $cmdline = '??UNKNOWN??';
if (open(my $envfh, "<", "/proc/$pid/cmdline")) {
$cmdline = <$envfh>;
chomp $cmdline;
close $envfh;
# Just in case the cmdline contains sensitive info, we just keep the first word
$cmdline =~ s/ .+//;
}
if ($critAfterMinutes > 0 && $processUptime > $critAfterMinutes) {
_info "Root process $pid ($cmdline) by $guilty, up for $processUptime minutes (> than $critAfterMinutes min)";
$criticalCount += 1;
}
elsif ($warnAfterMinutes > 0 && $processUptime > $warnAfterMinutes) {
_info "Root process $pid ($cmdline) by $guilty, up for $processUptime minutes (> than $warnAfterMinutes min)";
$warningCount += 1;
}
}
close $fh;
}
# check Results
if ($criticalCount) {
failure("$criticalCount critical cases found");
}
elsif ($warningCount) {
warning("$warningCount warning cases found");
}
# is ok
success("No long-lived root process found");

View file

@ -0,0 +1,131 @@
#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
#
# DESC: Warn if a more recent bastion version is available
use strict;
use warnings;
use File::Basename;
use Getopt::Long;
my $PROBE_NAME = basename($0);
my $debug;
## no critic (Subroutines::RequireArgUnpacking)
## no critic (Subroutines::RequireFinalReturn)
## no critic (InputOutput::ProhibitBacktickOperators)
sub _out {
my ($criticity, $msg) = @_;
printf "%s %4s - %s\n", $PROBE_NAME, $criticity, $msg;
}
sub _dbg { _out('dbg', $_[0]) if $debug; }
sub _info { _out('info', $_[0]); }
sub _warn { _out('WARN', $_[0]); }
sub _err { _out('ERR!', $_[0]); }
sub success { my $msg = shift; _info($msg) if $msg; _info("status=OK"); exit(0); }
sub warning { my $msg = shift; _warn($msg) if $msg; _info("status=WARN"); exit(1); }
sub failure { my $msg = shift; _err($msg) if $msg; _info("status=FAILURE"); exit(2); }
sub unknown { my $msg = shift; _err($msg) if $msg; _info("status=UNKNOWN"); exit(3); }
# OPTIONS
GetOptions(
"help" => \my $help,
"debug!" => \$debug,
"basedir=s" => \my $basedir,
"no-warn-on-diff" => \my $noWarnOnDiff,
) or unknown("Failed parsing command-line");
# HELP
if ($help) {
print <<"EOF";
$PROBE_NAME [options]
--help This help message
--debug Increase verbosity of logs
--basedir DIR Specify the base directory of The Bastion (default: /opt/bastion)
--no-warn-on-diff Never return a WARN code even if we find a git diff
EOF
unknown();
}
$basedir ||= "/opt/bastion";
# CODE
# get current version
my $current_version;
if (open(my $fh, '<', "$basedir/lib/perl/OVH/Bastion.pm")) {
while (<$fh>) {
if (m{^\s*our\s+\$VERSION\s*=\s*.([0-9a-zA-Z.-]+)}) {
$current_version = $1;
}
}
close($fh);
if ($current_version) {
_info("Bastion version $current_version found");
}
else {
unknown("Couldn't find version in Bastion.pm file!");
}
}
else {
unknown("Couldn't find current bastion version ($!)");
}
my @out;
my $ret;
if (!chdir("$basedir")) {
unknown("Couldn't chdir to $basedir!");
}
@out = qx{git rev-parse --abbrev-ref HEAD};
$ret = $?;
if ($ret != 0) {
_info("Bastion main path is not a git repo, or failed to rev-parse");
}
else {
_dbg("output: $_") for @out;
my $branch = $out[0];
chomp $branch;
_info("Bastion is on branch $branch");
}
@out = qx{git rev-parse HEAD};
$ret = $?;
if ($ret != 0) {
_info("Bastion main path is not a git repo, or failed to rev-parse");
}
else {
_dbg("output: $_") for @out;
my $commit = $out[0];
chomp $commit;
_info("Bastion is on commit $commit");
}
@out = qx{git diff};
if ($ret != 0) {
_info("Bastion main path is not a git repo, or failed to diff");
}
else {
_dbg("output: $_") for @out;
my $difflines = @out;
if ($difflines > 0) {
if ($noWarnOnDiff) {
success("Found $difflines lines of diff");
}
else {
warning("Found $difflines lines of diff");
}
}
else {
success("Found no git diff");
}
}

View file

@ -0,0 +1,5 @@
# This is a sudoers example file for The Bastion contrib NRPE probes. Adjust to your system.
nagios ALL=(healthcheck) NOPASSWD: /opt/bastion/contrib/nrpe/probes/bastion-healthcheck
nagios ALL=(root) NOPASSWD: /opt/bastion/contrib/nrpe/probes/bastion-version