Задача:
Собирать информацию о действиях пользователя (аудита) в консоли Linux, а именно вводимых им командах и выводимой на экран информации.
Предлагаемое решение:
screen по умолчанию для всех пользователей в Linux с логированием
Необходимые условия:
- Полное логирование всех пользователей в консоли, включая вывод информации процессами, чтобы можно было оценить почему пользователь принял то или иное решение
- Без возможности отключения логирования
- Раз уж выбрали screen — максимально используем его возможности (открытие новых окон, отключение по ^a + d, оставляя рабочие процессы запущенными и другие удобства)
- Максимальное удобство — не должно быть каких-либо несовместимостей с приложениями
- В случае использования пользователями, не знакомыми с screen — сделать работу максимально знакомой и близкой к обычной командной оболочке (shell)
Возможные варианты:
1) Предложенный на Хабре вариант. Рабочий, но есть несколько моментов:
- По-хорошему надо было бы указать shell пользователя в /etc/shells
- screen как таковой не работает. Иначе говоря дополнительные окна не открываются
- Логирование отключается банальным ^a + H (заглавная)
2) Тут тоже предложены варианты, но это больше сырые заготовки
Итак, приступим:
Имеется 2 возможных варианта использования screen для нашей задачи:
- Использование родной командной оболочки (shell), а затем вызывать screen автоматически скриптом
- Использование screen как командную оболочку пользователя
Судя по цитатам по ссылке, второй вариант нехорош по
определённым причинам
...this may break programs which run the login shell defined in /etc/passwd for various commands…
...It then becomes hard to do anything with your account other than log in. Also, your sysadmin probably doesn't have screen in /etc/shells...
...It then becomes hard to do anything with your account other than log in. Also, your sysadmin probably doesn't have screen in /etc/shells...
Создаём скрипт для запуска screen, чтобы при запуске командной оболочки bash (ведь у вас bash, правда?) все пользователи использовали этот файл и загружались в screen по умолчанию с включённым логированием. При выходе из screen – сессия закрывается:
vi /usr/local/bin/get_in.sh
#!/bin/sh
SCREEN=/usr/bin/screen
KILL=/bin/kill
## Check if we are already in screen ($STY is set)
if [ -z "$STY" ]; then
$SCREEN -LARR -S Shared -c /etc/screenrc
## Force SHELL close on exit - we don't want to allow users to escape logging outside screen
$KILL -SIGHUP $PPID
fi
Что мы имеем:
-L — направить весь лог в файл (куда именно — см. директиву logfile в файле /etc/screenrc ниже)
-A — Адаптировать размеры окон к размеру текущего терминала. Взято отсюда.
-RR — Переподключить сессию и, если необходимо, отсоединить (detach) её или создать заново. Используется первая сессия, если больше чем одна доступна. В случае отключения по ^a + d, при повторном входе откроется эта же сессия этого же пользователя.
-c — мы чётко указываем, какой конфигурационный файл использовать, чтобы избежать возможности отключения логирования и переназначения опций пользователями, к примеру созданием файла в ~/.screenrc.
-S — Назначаем сессии понятное имя. У каждого пользователя может быть одно и то же имя.
Делаем скрипт исполняемым:
chmod 0755 /usr/local/bin/get_in.sh
Делаем так, чтобы все использовали этот скрипт. Для этого в конец файла /etc/bash.bashrc добавляем строку:
/usr/local/bin/get_in.sh
Корректируем файл /etc/screenrc:
## Выбираем, хотим ли мы видеть заметку о правообладателях во время запуска. По умолчанию включено (on), как вы заметили.
startup_message off # default: on
## Отключаем визуальный сигнал - включается обычное "пикание" как в shell
vbell off
## Размер буфера прокрутки увеличиваем до 4096. Значение по умолчанию - 100.
defscrollback 4096 # default: 100
## Устанавливаем командную оболочку (shell), которая будет использоваться при создании новых окон. Переназначает значение переменной окружения $SHELL. Если команда начинается с символа '-' , то командная оболочка будет запущена как login-shell.
defshell -/bin/bash
## Влияет на копирование текста комадной ^a+[ .
crlf off # default: off
## Добавляет симпатичную строку состояния внизу экрана.
caption always "%{= kg} %H | %{kc}%?%-w%?%{kY}%n*%f %t%?(%u)%?%{= kc}%?%+w%? %=|%{kW} %l %{kw}| %{kc}%{-b}%D, %m/%d/%Y | %{kW}%{+b}%c %{wk}"
## Set terminal cap info
termcapinfo xterm* 'hs:ts=\E]0;:fs=\007:ds=\E]0;\007'
hardstatus off
## Отключаем возможность отключения логирования из самой сессии screen (^a + H)
bind H
## Устанавливаем расположение и именование лог-файлов
logfile /var/log/screen/$USER@%H-%Y%m%d-%c:%s.log
## By default, screen uses an 8-color terminal emulator. Use the following line to enable more colors, which is useful if you are using a more-capable terminal emulator:
term screen-256color
## Устанавливает функцию записи отметок времени в лог-файл
logtstamp on
Не забываем создать директорию для логов:
mkdir /var/log/screen
chmod 0777 /var/log/screen
Этим мы добиваемся, что все команды будут логироваться в лог-файлы вида:
/var/log/screen/user@server-20130716-19:52:34.log
В Debian, чтобы в screen работало автозавершение команд (bash_completion), необходимо раскомментировать в /etc/bash.bashrc:
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
Уважаемый 1ex подсказал решение, как с помощью wrapper-а для ssh логировать команды, выполняемые без входа в интерактивный режим bash вида: ssh user@host «ls -l». Для этого необходимо:
в /etc/ssh/sshd_config указать ссылку на обработку wrapper-ом:
ForceCommand /etc/ssh/hook.sh
Затем создать сам wrapper /etc/ssh/hook.sh:
#!/bin/sh
if [ ! -z "${SSH_ORIGINAL_COMMAND}" ]; then
echo "User "${USER}" remotely runs a command: ${SSH_ORIGINAL_COMMAND}" >> /var/log/screen/$USER@`hostname`-`date +%Y%m%d-%H:%M:%S`-command.log
bash -c "$SSH_ORIGINAL_COMMAND"
else
cat /etc/motd
${SHELL}
fi
Не забыть сделать его исполняемым:
chmod +x /etc/ssh/hook.sh
Этим мы добиваемся, чтобы все такие команды (и только команды — без информации, что выводится на экране) логировались в ту же директорию и будут дополнены суффиксом "-command":
/var/log/screen/user@server-20130717-12:47:53-command.log
Ну вот и всё. Теперь при подключении все пользователи (включая root — будьте осторожны, если потеряете возможность входа!) будут работать в screen, который запускается из bash. При выходе из screen, родительский bash закрывается и соединение прерывается. Если необходимо оставить работать процессы в фоне, то для выхода используем ^a+d. При следующем подключении эта сессия подключится автоматически.
Для дальнейшего изучения:
- Так как в логи пишется вывод команд — они могут занимать большое количество места. Необходимо предусмотреть методы сжатия для уменьшения объёма/трафика
- Лучшее место для логов — удалённая машина и далее обработку производить там, так как логи на локальной машине создаются с uid/guid пользователя и могут быть им удалены/изменены. Предполагается использование syslog.
- Возможно, есть методы обойти screen и, соответственно, логирования при этой конфигурации. Хотелось бы услышать их и внести изменения
Используемые источники:
- http://habrahabr.ru/sandbox/65904/
- http://superuser.com/questions/52297/use-gnu-screen-as-login-shell
- https://spaces.seas.harvard.edu/display/USERDOCS/How+to+use+%27screen%27+for+remote+shell+sessions
- http://www.linuxjournal.su/?p=3495
- http://www.howtoforge.com/options-for-user-auditing-on-linux-platforms
Update:
1) По замечанию joneleth пути изменены на жёсткие:
Абзац:
SCREEN=`which screen`
KILL=`which kill`
Заменён на:SCREEN=/usr/bin/screen
KILL=/bin/kill
На данный момент существуют 2 метода обхода логирования команд:
Уважаемый 1ex подсказал решение с помощью wrapper-а для ssh. Теперь все команды такого типа логируются. Изменения в текст внесены.
2) Подсказана ForeverYoung: команда screen -X log отключает логирование.
Возможности отключить эту особенность пока что нету, поэтому необходимо применять административные меры к пользователям, кто запускает эту команду (сама эта команда всё равно будет записана в лог).
Лучшие решения приветствуются.
ИТОГИ:
Как выяснилось screen не совсем предназначен для решения такого рода задач, а именно принудительного логирования команд и их вывода без возможности отключения логирования. Это приводит к тому, что приходится дополнительно править другие файлы.
Как порекомендовал уважаемый amarao для решения такого рода задач лучше посмотреть на другие решения:
а) сниффинга всего трафика, проходящего через псевдотерминалы (более серьёзно). kiltumподсказал conspy. Slipeer предложил Snoopy Logger.
б) систем аудита (SELinux/Apparmor/etc), которые будут записывать реально всё выполняемое.
Но эти решения выходят за рамки данной статьи.
Считаю, что несмотря на недостатки, использование screen для логирования действий пользователей и выводимой на экран информации в Linux оправдано, ввиду несложности реализации, а главное — простоты чтения логов (в отличие от auditd, напимер).