Локальное, с меткой времени, ведение журнала всех команд ssh?

Локальное, с меткой времени, ведение журнала всех команд ssh?

Как мне сохранить локальную запись с временными метками всех удаленных команд, которые я использую ssh(клиент командной строки openssh запущен через bash)?

Требования:

  • Существенный:

    • 100% клиентская часть без необходимости ведения журналов на сервере
    • Настраивается или устанавливается для каждого пользователя, журналы хранятся в домашнем каталоге пользователя.
    • Поддержка различения нескольких одновременных сеансов с разными пользователями и хостами.
    • Ненавязчивый (нет необходимости активировать его каждый раз и не оказывает существенного влияния на использование ssh)
  • Высокий приоритет:

    • Либо вывод не регистрируется, либо фильтруется по возможности.
    • Либо ввод пароля не регистрируется, либо файл зашифрован.
    • Указывает фактически использованные команды (после завершения табуляции/истории, возврата на одну позицию, CTRL+ Cи т. д. были обработаны)
  • Приятно иметь:

    • Также регистрирует команды в связанных сеансах (команды, введенные во время удаленных sshсеансов su <user>)
    • Начало и конец сеанса должны регистрироваться.
    • bashЛучшим решением будет простое решение без полномочий root (возможно, aliasскрипт bash-оболочка для sshкоманды?)

Мой уровень мастерства:

  • Я не новичок в программировании, но все еще учусь bash«пути Linux», поэтому примеры кода с краткими пояснениями были бы весьма признательны.

Возможные стратегии

  • кейлоггер-- Проблема: регистрирует пароли, не регистрирует заполнение вкладок/истории (см.ответ гленна)
  • screenс прокруткой дампа один раз в секунду и diffмежду ними для поиска новых строк прокрутки-- Проблема: как это можно реализовать в автоматизированном режиме?
  • ssh "$@" | tee >(some_cleaner_function >> $logfile)-- Проблема: невозможно обработать многострочные команды или историю в связанных сеансах, необходима тщательная очистка (см. мой ответ)
  • Сочетание некоторых из вышеперечисленных вариантов

Пример

Следующий сеанс SSH:

user@local:~$ ssh user@remote
Last login: Tue Jun 17 16:34:23 2014 from local
user@remote:~$ cd test
user@remote:~/test$ ls
a  b
user@remote:~/test$ exit

Может привести к появлению журнала, ~/logs/ssh.logнапример:

2014-06-17 16:34:50   [user@remote - start]
2014-06-17 16:34:51   [user@remote] cd test
2014-06-17 16:34:52   [user@remote] ls
2014-06-17 16:34:53   [user@remote] exit
2014-06-17 16:34:53   [user@remote - end]

Или, возможно, для каждого сеанса будет создан отдельный журнал с командной строкой, используемой для запуска сеанса, в верхней части файла.

решение1

Меня заинтриговал ваш вопрос. Изначально я не собирался отвечать, но меня зацепило.

Это приложение использует expectи на самом деле является кейлоггером.

#!/usr/bin/expect -f

proc log {msg} {
    puts $::fh "[timestamp -format {%Y-%m-%d %H:%M:%S}]: $msg"
}

set ssh_host [lindex $argv 0]
set ::fh [open "sshlog.$ssh_host" a]

log "{session starts}"

spawn ssh $ssh_host

interact {
    -re "(.)" {
        set char $interact_out(1,string)
        if {$char eq "\r"} {
            log $keystrokes
            set keystrokes ""
        } else {
            append keystrokes $char
        }
        send -- $char
    }
    eof
}

log "{session ends}"

Примечания:

  • он добавляется к файлу с указанием назначения ssh в имени
  • это кейлоггер: если вы не настроили ключи ssh, вы получите пароль пользователя в файле журнала
  • это блокируется автодополнением: если пользователь вводит uptTab(для uptimeкоманды), в файле журнала вы получите "upt\t", а не "uptime"
  • ^?он захватывает символы в «сыром» режиме: если пользователь плохо печатает, в файле журнала будет много (символов возврата на одну позицию).

решение2

В настоящее время я использую скрипт bash ниже. Он имеет много проблем, но это единственное решение, которое я нашел, которое отвечает всем требованиям, приоритетам и "приятно иметь" (по крайней мере, большую часть времени).

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

Проблемы со скриптом, которые я обнаружил на данный момент:

  1. Многострочные команды вызывают проблемы:

    • Если вы пролистаете многострочный элемент в удаленной истории (с помощью клавиш вверх/вниз), он запишет элемент истории вместо последней команды. Вы можете избежать этого,удаление из истории bashлюбые многострочные команды сразу после их использования.
    • Регистрируется только первая строка многострочных команд.
  2. Связанные сеансы (использующие команды sshили suна удаленном конце) приводят к тому, что при прокрутке истории записываются прокрученные переданные команды вместо фактически использованных команд.

  3. Регулярные выражения можно улучшить и, возможно, потребуется изменить для определенных сред:

    • Я обманываю, преобразуя непечатаемые символы с помощью cat -vперед очисткой. В результате допустимый контент может быть удален, если вы когда-либо используете строки, подобные ^[[вашим командам.
    • Иногда вы получаете дополнительный ввод перед командой, например, если вы очень быстро просматриваете историю. Обычно за этим следует "^M" перед фактической командой, и поэтому его можно убрать, если это необходимо.
    • Иногда встречаются и другие управляющие символы. Я оставляю их все, пока не узнаю, какие из них можно безопасно удалить. ^M, как я уже упоминал, полезен для обнаружения недопустимого записанного ввода, а ^C сообщит вам, была ли команда прервана.
    • Регулярное выражение подсказки может потребоваться изменить для конкретных подсказок, и я могу предположить, что в разных удаленных средах могут быть разные шаблоны управляющих символов.
  4. Нет автодополнения bash-команды ssh, например, для имени хоста. Вы можете получить автодополнение bash, если присвоите этому скрипту sshпсевдонимalias ssh="sshlog"

Исходный код скрипта и установка:

Для установки вставьте следующее в ~/bin/sshlog и сделайте исполняемым. Вызовите с помощью sshlog <ssh command options>. При желании укажите псевдоним 'ssh' в файле .bashrc пользователя.

#!/bin/bash
# A wrapper for the ssh command that produces a timestamped log of all ssh commands
declare -r logfile=~/logs/ssh.log
declare -r description="sshlog-${$} ${@}"
declare -r TAB=$'\t'

logdir=`dirname ${logfile}`
[ -d ${logdir} ] || mkdir "${logdir}";

clean_control_chars() {
    while IFS= read -r line; do
        # remove KNOWN control characters. Leave the rest for now.
        # line=$(echo "${line}" | sed 's/\^\[\[K//g')  # unkown control character: ^[[K
        # line=$(echo "${line}" | sed 's/\^\[\[[0-9]\+[P]//g')  # these are generated by up/down completion - e.g. ^[[2P
        line=$(echo "${line}" | sed 's/\^\[\[[0-9]*[A-Z]//g')  # all other ^[[..
        # replay character deletions (backspaces)
        while [[ $(echo "${line}" | grep -E --color=never '.\^H') != "" ]]; do
            line=$(echo "${line}" | sed 's/.\^H//')
        done
        # remove common control characters
        line=$(echo "${line}" | sed 's/\^M$//')  # remove end of line marker from end
        line=$(echo "${line}" | sed 's/^\^G//g')  # remove start marker from start
        # remove ^G from other locations - possibly a good idea
        # line=$(echo "${line}" | sed 's/\^G//g')
        # remove all other control characters - not recommended (many like ^C and ^M indicate which section was processed/ ignored)
        # line=$(echo "${line}" | sed 's/\^[A-Z]//g')
        echo ${line};
    done
}

filter_output() {
    while IFS= read -r line; do
        # convert nonprinting characters and filter out non-prompt (in Ubuntu 14.04 tests, ^G indicates prompt start)
        line=$(echo "${line}" | cat -v | grep -Eo '[\^][G].*[\$#].*')
        [[ ${line} != "" ]] && echo "${line}"
    done
}

format_line() {
    while IFS= read -r line; do
        raw=${line};
        line=$(echo "${line}" | clean_control_chars);
        prompt=$(echo "${line}" | grep -Po '^.*?(\$|#)[\s]*')
        command=${line:${#prompt}}
        timestamp=`date +"%Y-%m-%d %H:%M:%S %z"`
        echo -e "${timestamp}${TAB}${description}${TAB}${prompt}${TAB}${command}"
    done
}

echo "Logging ssh session: ${description}"
echo "[START]" | format_line >> ${logfile}
/usr/bin/ssh "$@" | tee >(filter_output | format_line >> ${logfile})
echo "[END]" | format_line >> ${logfile}

Пример содержания журнала:

2014-06-29 23:04:06 -0700   sshlog-24176 remote [START]
2014-06-29 23:04:12 -0700   sshlog-24176 remote oleg@remote:~$  cd test
2014-06-29 23:04:13 -0700   sshlog-24176 remote oleg@remote:~/test$     ls
2014-06-29 23:04:14 -0700   sshlog-24176 remote oleg@remote:~/test$     exit
2014-06-29 23:04:14 -0700   sshlog-24176 remote [END]

решение3

Как насчет strace -o /tmp/ssh_log -ff -s8192 -T -ttt -fp $(pidof sshd)? Это регистрирует все сеансы ssh. Вам может понадобиться инструмент для последующего анализа журнала или просто используйте grep, awkи т. д.

  • -f: трассировка разветвленных потомков
  • -ff: регистрируйте каждого ребенка отдельноssh_log.PID
  • -s8192: увеличить лимит записи в журнал строк (при необходимости)
  • -T -ttt: микросекундная маркировка в секундах с начала эпохи
  • -p N: прикрепить к pidN

решение4

У меня есть менее сложный ответ, и уж точно не кейлоггер. Я не понимаю, что вы имеете в виду независимость от серверного журнала (это означает, что все действия должны выполняться на сервере, и все журналы являются журналами на стороне сервера), и поэтому я подумал, что хорошей идеей будет передать в системный bashrc команду приглашения типа:


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -t "$USER[$$] $SSH_CONNECTION")'

В Debian вам следует отредактировать файл: /etc/bash.bashrc, а в CentOS файл: /etc/bashrc

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


source /etc/bash.bashrc

в системе Debian или


source /etc/bashrc
в системе CentOS.

С этого момента каждая команда каждого сеанса SSH будет регистрироваться в/var/log/syslogв системе Debian и в/var/log/сообщенияв системе Centos.

Если вы хотите записать их в отдельный файл и не мешать другим файлам журналов, вы можете использовать:


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
вместо предыдущего примера PROMPT_COMMAND, а затем настройте rsyslogd по мере необходимости.

Например, в системе Debian отредактируйте/etc/rsyslog.confфайл: измените строку:


.;auth,authpriv.none           -/var/log/syslog
к

.;auth,authpriv.none,local6           -/var/log/syslog
и добавьте следующую строку в конец файла:

local6.info                     /var/log/history.log

затем выполните:

touch /var/log/history.log && /etc/init.d/rsyslog restart

Связанный контент