Bash: 2 способа логгирования запуска пользовательских приложений

    Если вы работали с syslog'ом, то знаете, что у него есть приложение logger, необходимое для логгирования каких-то действий от обычных пользователей. И если многие программы умеют работать с syslog'ом самостоятельно, то логгировать все действия пользователей — это не всегда простая задача.

    Тем не менее, есть как минимум два способа это сделать с использованием bash.


    Способ 1. Переменная PROMPT_COMMAND + logger.


    В bash есть одна малоизвестная переменная с названием PROMPT_COMMAND, назначение которой — выполнение какой-то команды перед выводом приглашения, заданного переменной $PS1. В этой переменной можно задать скрипт, который будет выполняться перед каждым выводом приглашения для новой команды.
    PROMPT_COMMAND="/sbin/userlog"
    

    Вот пример скрипта (userlog)
    LAST_COMMAND=`history 1`
    logger -t USER_$USER "$LAST_COMMAND"
    

    Желательно сразу запретить изменение скрипта обычным пользователям, но оставить права на выполнение.
    После этого можно прописать переменную в файл ~/.profile, например, и запретить пользователю его изменять.
    shebang указывать не нужно, потому что тогда для выполнения будет запускаться еще один экземпляр оболочки.

    В чем плюсы такого способа?
    1) Далеко не все знают о такой переменной, которая командой env, например, не показывается (хотя, возможно, в каких-то системах и показывается).
    2) Можно централизованно собирать логи syslog и достаточно легко их анализировать по тэгу USER_$USER, если надо выяснить, какие команды конкретный пользователь выполнил, при этом будет указано время окончания работы команды, которое можно сравнить со временем нужного события, например, удаления общего документа или push'а в репозиторий (или еще чего-нибудь, не суть).
    3) Достаточно просто включать для вновь создаваемых пользователей, достаточно добавить эту переменную в файл /etc/skel/.profile, тогда действия всех создаваемых пользователей будут автоматически логгироваться без каких-то дополнительных действий.

    В чем минусы?
    1) Запись о выполнении команды будет только после окончания работы команды.
    2) Можно отключить логгирование таким образом, если переназначить переменную PROMPT_COMMAND (правда, только для текущего сеанса, при новых входах эта переменная будет снова установлена). Плюс использование других конфигурационных файлов bash (~/.bashrc, используемый при запуске экземпляра bash не в режиме login shell), в которых можно unset'ить переменную.

    Способ 2. Скрипт-компаньон + logger.


    Способ, применимый к запуску какого-то конкретного приложения.
    Способ на основе известного со времен DOS'а принципа. Файл приложения переименовывается во что-нибудь наподобие program.bin и на его месте создается файл-скрипт с именем program, который логгирует запуск приложения, а потом запускает само приложение и передает ему параметры командной строки.

    Пример скрипта
    #!/bin/bash
    COMMAND_LINE="$0 $@"
    logger -t APPNAME_$USER "$COMMAND_LINE"
    exec $0.bin $@
    


    Какие тут есть особенности?
    1) Обработка входного потока (stdin), если приложению передаются данные через поток (Лично мне это ни разу не пригодилось, поэтому спорный вопрос, нужно ли это).
    2) При обновлении приложения при помощи пакетного менеджера скрипт-компаньон скорее всего будет переписан новой версией бинарного файла приложения.

    Если у вас есть какие-то способы, позволяющие без дополнительных приложений логгировать работу пользователей минимальными усилиями, был бы признателен за указание их в комментариях.
    Поделиться публикацией
    Комментарии 15
      0
      Спасибо за первый вариант, пригодится. А вот второй использовать не буду и другим не рекомендую, уж очень костылем попахивает.
        0
        Это форменный костыль и есть, его если и имеет смысл использовать, то только для записи того, какие параметры были использованы при запуске, для составления списка параметров при отладке, при которых, например, программа работает нестабильно.
        +3
        После этого можно прописать переменную в файл ~/.profile, например, и запретить пользователю его изменять.

        Не слишком ли жестоко? У меня некоторые вещи, нужные для нормальной работы, прописаны в .profile. Поэтому я практически сразу туда лезу и сразу заметил бы неизвестную переменную.
        Да и к тому же система логирования, которую юзер может временно отключить — это очень плохая штука. Вы будете уверены, что все хорошо, а на самом деле все будет плохо, т.к. умный юзер перед деланием гадости будет скидывать эту переменную.
        P.S. На некоторых системах файлик называется .bash_profile
          0
          Ну, я, собственно, об этом и написал в минусах.
          А .bash_profile — это другой файлик, хотя да, можно и его использовать.
            +2
            Это не минус, это МИНУС. Можно считать, что аккаунтинга нету.

            When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and
            executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile,
            ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.

            Так что не сказал бы, что «другой файлик»

            Кстати, есть такая штука — acct. Только сам никогда не пробовал — все руки не доходят. И мануальчик. В centos/redhat кстати вроде и доставлять ничего не нужно
              0
              За мануальчик спасибо, но я, честно говоря, не понял, умеет ли оно целиком командную строку сохранять и работать с syslog'ом. Не встречали такой информации?
                0
                Выдал все, что знал :) Остальное, видимо, только опытным путем.
          +1
          так делать не стоит !!!

          Во-первых, если скрипт нельзя прочитать — его нельзя выполнить:

          -bash-4.2$ echo echo script works! > tmp.sh
          -bash-4.2$ chmod a+x tmp.sh
          -bash-4.2$ ./tmp.sh
          script works!
          -bash-4.2$ chmod a-r tmp.sh
          -bash-4.2$ ./tmp.sh
          bash: ./tmp.sh: Permission denied
          -bash-4.2$

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

          Правильные способы — логирование всего ввода-вывода терминала (сейчас сходу не помню решение, но была статья в каком-то номере samag на эту тему), приведенный выше process accounting и аналогичные способы сбора статистики уровня ядра.

          В третьих, есть /etc/bashrc, /etc/profile, /etc/profile.d и другие для глобальных вещей, за подробноcтями — обратитесь к man bash
            +1
            Посмотрите это: sourceforge.net/projects/snoopylogger/
            Перехватывает вызов execve() и пишет всё в syslog.
            Пользователь выгрузить не может.
              0
              Зачем что-то придумывать, когда есть уже готовые инструменты: 1, 2, 3.
                0
                1) Just for fun
                2) Чтобы побудить людей читать man bash, как уже указали
                3) Возможно, кому-то объяснить, что не надо заколачивать гвозди микроскопом, когда это не надо. И не надо заморачиваться с системами мониторинга уровня ядра, если вам надо это на 20 минут. На постоянку — да, на 20 минут — нафиг не надо, дольше устанавливать будете и перезагружаться.
                4) Размять голову и помочь размять ее другим.
                5) Собрать в одном месте в комментах список средств для мониторинга активности пользователей.
                Как-то так.
                Печально, что некоторые воспринимают всерьез костыли (причем сразу сказано, что это самые настоящие костыли). Я бы сам за такое в продакшене руки клавиатурой отбил.
                  0
                  Люто плюсую.
                  +1
                  Вот тут на fl.ru попалась ссылка по теме: Remote Logging Using Syslog And Logging Shell Commands Remotely
                    0
                    Наиболее правильный способ имхо. Bash 4 уже имеет встроенное логирование в syslog (только включить при сборке), а для Bash 3 есть небольшой патчик, который делает тоже самое.
                    0
                    Если хотите, чтобы протоколирование действий пользователя было действительно надёжным, то надо реализовывать средствами ядра, например, при помощи linux auditd, который умеет протоколировать с точностью до системного вызова, и даже имеет встроенный key logger.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое