Почему systemctl не возвращает значение при проверке NRPE?

У меня проблема с проверкой NRPE, которую я написал.

Это простой сценарий оболочки, который запускает "systemctl is-active [service_name]" и возвращает значение нашему Thruk.

Когда я запускаю сценарий напрямую с пользователем nrpe, он работает:

-bash-4.2$ /usr/lib64/nagios/plugins/check_service_active.sh --service dynflowd
dynflowd
Service dynflowd démarré

Но когда я запускаю его с NRPE локально, он сообщает мне, что служба остановлена:

-bash-4.2$ ./check_nrpe -H 127.0.0.1 -c check_service_active -a 'dynflowd'
dynflowd
Service dynflowd arrêté

После нескольких тестов я выяснил, что он связан с командой systemctl. Когда я заменяю systemctl другой командой, например "echo", она работает.

Итак, я думаю, что есть что-то с NRPE и systemctl, но я не могу найти что? И я ничего об этом не нахожу в Google.

И вот я здесь!

Заранее благодарим вас за ответ и извините, если я недостаточно понимаю.

Вот мой сценарий:

#!/bin/sh
#
# Script d'interrogation d'un service via systemctl

# Nagios return codes
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4

#Recuperation des parametres
while test -n "$1"; do
        case "$1" in
                --service)
                        SERV=$2
                        shift
                        ;;

                -u)
                        print_usage
                        exit $STATE_OK
                        ;;
        esac
        shift
done

STAT=$(systemctl is-active $SERV)

if [[ $STAT  == "active" ]]
then
        echo "Service $SERV démarré"
        exit $STATE_OK
else
        echo "Service $SERV arrêté"
        exit $STATE_CRITICAL
fi

2 ответа

Решение

Я наконец нашел проблему: версия NRPE!!!

На моем сервере NRPE находится в nrpe-3.2.1-6.

Я запускаю свой сценарий через NRPE на другом сервере, и он работает.

Этот другой сервер работает nrpe-3.2.1-8.

Итак, решение: обновление!

Спасибо за ваше время и идеи, особенно >> /tmp/paxdebug.dynflowd 2>&1 идея, которая помогла мне разобраться в проблеме.

Хорошо, похоже на cronзадания, может быть, что NRPE (сервер) работает в среде, отличной от среды вашей оболочки, и эта отдельная среда каким-то образом не работаетsystemctl должным образом.

Легкий способ увидеть это - изменить:

STAT=$(systemctl is-active $SERV)

линия временно, чтобы вы могли видеть, что происходит. Измените сценарий так, чтобы теперь эта строка стала следующей:

(
    echo ==== $(date) ==== ${SERV}
    systemctl is-active $SERV
) >> /tmp/paxdebug.dynflowd 2>&1
STAT=$(systemctl is-active $SERV)

Это, помимо запуска скрипта для получения статуса, напишет некоторую полезную информацию в /tmp/paxdebug.dynflowd файл, который затем можно изучить, чтобы точно увидеть, что происходит в экземпляре сценария, запущенном NRPE.

Надеюсь, он скажет что-нибудь простое, например Cannot find systemctl (указывает на проблемы с путями), но, что бы он ни дал вам, это должно помочь точно выяснить, в чем проблема.


Обновление 1: на основе ваших комментариев, которые пытались запустить systemctl привело к:

systemctl: command not found

Это почти наверняка потому, что путь неправильный. Вы можете проверить путь, добавив следующую строку в опубликованный мной отладочный код:

echo "PATH is [$PATH]"

Чтобы исправить это, либо измените свой путь в скрипте, чтобы включить /usr/bin (при условии, что это где systemctl находится) или просто запустите абсолютный путь (как в отладочной, так и в исходной областях):

/usr/bin/systemctl is-active ${SERV}
STAT=$(/usr/bin/systemctl is-active ${SERV})

Обновление 2: на основе ваших комментариев, при использовании абсолютного пути теперь вы получаете:

/usr/lib64/nagios/plugins/check_service_active.sh: line 32:
    /usr/bin/systemctl: Permission denied

Это, вероятно, будет NRPE работает на низком уровне привилегий, или как другой пользователь, чтобы обеспечить безопасность от атак. Учитывая, насколько systemd важен для работы системы, было бы неразумно разрешать неограниченный доступ к нему.

Итак, как и в предыдущем обновлении, добавьте в область отладки следующее:

/bin/ls -al /usr/bin/systemctl # Check "ls" is in this directory first.
/usr/bin/id                    # Ditto for "id".

Первая строка предоставит вам разрешения, вторая - ваши данные пользователя. В этот момент это становится упражнением в выяснении того, как бегать.systemctl без нарушения безопасности.

Если выяснится, что это проблема разрешения или пользователя, одна из возможностей - предоставить хорошо защищенныйsetuid скрипт, который будет принадлежать (и, следовательно, запускаться от имени) пользователю, которому разрешено запускать systemctl. Но я действительно имею в виду хорошо защищенный, поскольку вы не хотите открывать дыру:

# SysCtlIsActive.sh: only allows certain services to be queried.

# Limit to these ones (white-space separated).

allowed="dynflowd"

# If not allowed, reject with special status.

result="GoAway"
for service in ${allowed} ; do
    [[ "$1" = "${service}" ]] && result=""
done

# If it IS allowed, get actual status.

[[ -z "${result}" ]] && result="$(/usr/bin/systemctl is-active "$1")"

echo "${result}"

Могут быть и другие методы (и они могут быть лучше), но, надеюсь, это будет хорошим началом, если проблема действительно в этом.


Просто знай, что я думаю setuid игнорируется для сценариев оболочки, в которых есть строка shebang (например, #!/usr/bin/env bash), поэтому вам, возможно, придется обойти это, возможно, создав настоящий исполняемый файл для выполнения этой работы.

Если вам действительно нужно создать для него настоящий исполняемый файл, вы можете начать со следующего кода C, который представляет собой адаптацию сценария оболочки, приведенного выше:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    // Check service name provided.

    if (argc < 2) {
        puts("NoServiceProvided");
        return 1;
    }

    // Check service name allowed.

    static char *allowed[] = { "dynflowd", NULL };
    int isAllowed = 0;
    for (char **service = &(allowed[0]); *service != NULL; service++) {
        if (strcmp(*service, argv[1]) == 0) {
            isAllowed = 1;
            break;
        }
    }
    if (! isAllowed) {
        puts("InvalidServiceName");
        return 1;
    }

    // Try to allocate memory for command.

    char *prefix = "/usr/bin/systemctl is-active ";
    char *cmdBuff = malloc(strlen(prefix) + strlen(argv[1]) + 1);
    if (cmdBuff == NULL) {
        puts("OutOfMemory");
        return 1;
    }

    // Execute command, free memory, and return.

    sprintf(cmdBuff, "%s%s", prefix, argv[1]);
    system(cmdBuff);
    free(cmdBuff);

    return 0;
}
Другие вопросы по тегам