ssh
(bash
から開始されたコマンドラインopensshクライアント)で使用するすべてのリモートコマンドのローカルのタイムスタンプ付きレコードをどのように保持できますか?
要件:
必須:
高優先度:
持っていると便利:
ssh
または_su <user>
_セッション中に入力されたコマンド)bash
ベースの非ルートソリューションが最適です(おそらく、alias
またはbash
ラッパースクリプトでssh
コマンドを実行しますか?)私のスキルレベル:
bash
と「Linuxの方法」をまだ学習しているので、簡単な説明付きのコードサンプルをいただければ幸いです。可能な戦略
screen
スクロールバックダンプを1秒に1回、それらの間で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]
_
または、ファイルの先頭でセッションを開始するために使用されるコマンドラインを使用して、セッションごとに個別のログが作成される可能性があります。
私はあなたの質問に興味をそそられました。もともと答えるつもりはなかったのですが、夢中になりました。
これは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}"
ノート:
uptime
コマンドの場合)、「uptime」ではなく「upt\t」がログファイルに記録されます。^?
(バックスペース文字)が表示されます。現在、以下のbashスクリプトを使用しています。これには多くの問題がありますが、すべての要件、優先度、および「所有するのが良い」(少なくともほとんどの場合)に対処する唯一の解決策です。
この回答 は、sshセッションをローカルでログに記録することが非常に難しい理由を説明しています。
これまでに見つけたスクリプトの問題:
複数行コマンドは問題を引き起こします:
チェーンされたセッション(リモートエンドでssh
またはsu
コマンドを使用)を使用すると、履歴のスクロールで、実際に使用されたコマンドではなく、スクロールされて渡されたコマンドが記録されます。
正規表現は改善することができ、特定の環境では変更が必要になる場合があります。
cat -v
で変換してごまかします。その結果、コマンドで^[[
のような文字列を使用した場合、有効なコンテンツが削除される可能性があります。ホスト名などのsshコマンドのbash補完はありません。alias ssh="sshlog"
を使用してこのスクリプトをssh
にエイリアスすると、bash補完を取得できます
スクリプトのソースとインストール:
インストールするには、以下を〜/ bin/sshlogに貼り付けて実行可能にします。 sshlog <ssh command options>
で呼び出します。オプションで、ユーザーの.bashrcファイルの「ssh」のエイリアス。
#!/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]
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
:pidにアタッチN
私の答えはそれほど複雑ではなく、キーロガーではありません。サーバーログから独立しているという点はわかりません(つまり、すべてのアクションをサーバーに対して実行する必要があり、すべてのログはサーバー側のログです)。したがって、システム全体の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
これ以降、すべてのsshセッションのすべてのコマンドは、debianシステムでは/ var/log/syslogに記録され、/ var/log/messagesではログに記録されますcentosシステム。
別のファイルにログを記録し、他のログファイルを台無しにしたくない場合は、以下を使用できます。
Prompt_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
たとえば、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