Почему systemctl не возвращает значение в проверке NRPE? - PullRequest
1 голос
/ 22 апреля 2020

У меня проблема с проверкой 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 ]

0 голосов
/ 23 апреля 2020

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

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

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

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

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

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

0 голосов
/ 22 апреля 2020

Хорошо, аналогично 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

Вероятно, 1037 * будет NRPE, работающим с низким уровнем привилегий, или как другой пользователь для обеспечения защиты от атак. Учитывая то, как systemd является центральным для работы системы, было бы неразумно разрешать беспрепятственный доступ к ней.

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

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

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

Если окажется, что это разрешение или проблема пользователя, one вероятность будет предоставить хорошо защищенный скрипт 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 (например, * 1061) *) поэтому вам, возможно, придется обойти это, возможно, создав настоящий исполняемый файл, чтобы выполнить эту работу.

Если вам do нужно создать для него настоящий исполняемый файл, вы можете запустить со следующим 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;
}
...