すべての ssh コマンドのローカルのタイムスタンプ付きログ記録ですか?

すべての ssh コマンドのローカルのタイムスタンプ付きログ記録ですか?

ssh( を通じて起動されたコマンドライン Openssh クライアントbash)で使用するすべてのリモート コマンドのタイムスタンプ付きのローカル記録を保持するにはどうすればよいですか?

要件:

  • 不可欠:

    • サーバーのログに依存せず、100%クライアント側で実行
    • ユーザーごとに構成またはインストールされ、ログはユーザーのホーム ディレクトリに保存されます。
    • さまざまなユーザーおよびホストとの複数の同時セッションを区別するためのサポート。
    • 非侵入的(毎回アクティブ化する必要がなく、ssh の使用に大きな支障をきたさない)
  • 優先度が高い:

    • 出力はログに記録されないか、可能な限りフィルタリングされます
    • パスワード入力が記録されていないか、ファイルが暗号化されています
    • 実際に使用されたコマンドを示します(タブ/履歴補完、バックスペース、CTRL+Cなどが処理された後)
  • あった方がよい:

    • 連鎖セッションのコマンドも記録します(リモート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]

または、セッションを開始するために使用されたコマンド ラインがファイルの先頭にあるセッションごとに個別のログが作成される場合もあります。

答え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、ログファイルには「uptime」ではなく「upt\t」が表示されます。
  • 文字は「raw」モードで取得されます。ユーザーの入力が下手な場合は、^?ログ ファイルに大量の (バックスペース文字) が記録されます。

答え2

現在、私は以下の bash スクリプトを使用しています。多くの問題がありますが、これは、すべての要件、優先順位、および「あれば便利な機能」(少なくともほとんどの場合) に対応する唯一のソリューションです。

この答えssh セッションをローカルにログ記録することがなぜ難しいのかについて説明します。

これまでに見つかったスクリプトの問題点:

  1. 複数行のコマンドは問題を引き起こします:

    • リモート履歴の複数行項目を(上下キーで)ページングすると、最新のコマンドではなく履歴項目が記録されます。これを回避するには、bash 履歴から削除する複数行のコマンドは、使用直後に終了します。
    • 複数行コマンドの最初の行のみがログに記録されます。
  2. 連鎖セッション(リモート側でsshまたはsuコマンドを使用)では、履歴スクロールで、実際に使用されたコマンドではなく、スクロールされたコマンドが記録されます。

  3. 正規表現は改善することができ、特定の環境に合わせて変更する必要がある場合があります。

    • 私は、クリーニングの前に、非表示文字を で変換することでごまかしていますcat -v。その結果、^[[コマンド内で のような文字列を使用すると、有効なコンテンツが削除される可能性があります。
    • 履歴を非常に速くページングした場合など、コマンドの前に追加のログ入力が記録されることがあります。通常、実際のコマンドの前には「^M」が続くため、必要に応じて削除できます。
    • 他の制御文字が時々出現します。どれを削除しても安全かがわかるまで、今のところはすべてそのままにしておきます。先ほど述べたように、^M は無効なログ入力を検出するのに役立ち、^C はコマンドが中止されたかどうかを知らせます。
    • プロンプトの正規表現は特定のプロンプトに合わせて変更する必要がある場合があり、リモート環境によって制御文字のパターンが異なる可能性があると考えられます。
  4. ホスト名などの ssh コマンドの bash 補完がありません。 このスクリプトを次のようにエイリアスすると、bash補完が使えるようになりますsshalias ssh="sshlog"

スクリプトのソースとインストール:

インストールするには、次の内容を ~/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]

答え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: pidにアタッチN

答え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セッションのすべてのコマンドが記録されます。ログファイルDebianシステムでは、/var/log/メッセージCentOS システム上。

別のファイルにログを記録して他のログ ファイルを混乱させたくない場合は、次を使用できます。


PROMPT_COMMAND='history -a >(tee -a ~/.bash_history | logger -p local6.info -t "$USER[$$] $SSH_CONNECTION")'
前の PROMPT_COMMAND の例の代わりに、必要に応じて rsyslogd を構成します。

例えばDebianシステムでは、設定ファイルファイル: 次の行を変更します:


.;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

関連情報