モチベーション
デプロイメントツールなどで、SSHで対象のサーバに入ってよしなに色々してくれるものがあります。
中で何やってるのか見てみたいなーという時がちょこちょこあるのですが、あまりピンとくる方法がなく、いつも時間切れで諦めてしまってました。
今回またそういう要件が出てきたので、再挑戦してみようと思います。
SSHのコマンドログを取る方法 基本方針
できるもの、できないものあるのですが、頭の整理のために並べてみます。
A. SSHDのロギングの機能を使うーNG
ログインの成否までは出せますが、中で叩いたコマンドはログに出ません。
B. ログイン時に呼び出されるShellに細工する
なんだかんだで現実的なのは、これですね。
C. 通信を横抜きーNG
したところで暗号化してるんですから。。。
D. プロキシを通す
Paramikoとか、、、?
現状Bのほうが筋が良さそうなので、まずはBで頑張って見ることにします。
Shellの細工方針
ググって調べた方針を整理します。
a. ログイン時に呼び出すシェルを、細工したスクリプトに置き換える
うまく行きそうだったのですが、後述のtrapの仕込みがうまく行きませんでした。
最後にbash -iを呼び出す際にtrapがそちらに引き継がれず。
exec側の方はうまく行ったのですが。。
トライしたのは以下。
$ echo $SHELL
/usr/local/bin/mtsh
$ cat /usr/local/bin/mtsh
#!/bin/bash
MT_LOGDIR=/var/log/sshlogs/
function log_history {
echo $(date) $$ $BASH_COMMAND >> ${MT_LOGDIR}/history_${USER}
}
readonly -f log_history
trap log_history DEBUG EXIT ERR RETURN
exec &> >(tee -a >(awk '{print strftime("[%Y/%m/%d %H:%M:%S] "),$0} {fflush()}' >> ${MT_LOGDIR}/log_${USER}))
bash -i
exit
b. プロファイルに仕込みを入れる
対話型でSSHに入るときと、コマンド実行だけさせるときで、読み出されるプロファイルが変わります。
.bashrcであればどちらのケースでも読まれるらしいので、そこに仕込みを入れます。
入れる内容は以下の2つ。
b-1. exec &> を仕込んでおく
以下を実行することで、標準出力と標準エラー出力をteeに食わせます。
実装は以下を参考にさせていただきました。
https://zenn.dev/lovegorira/articles/62849db9f25012
$ cat ~/.bashrc
...
MT_LOGDIR=/var/log/sshlogs/
exec &> >(tee -a >(awk '{print strftime("[%Y/%m/%d %H:%M:%S] "),$0} {fflush()}' >> ${MT_LOGDIR}/log_${USER}))
...
teeの後がちょっとひねってあり、ログに書き出す前にawkで時刻を頭につけるようにしています。
また、&>にすることで、標準出力と標準エラーを両方拾っています。
エラーも拾っておきたいというよりは、、ターミナルの頭の「[user01@localhost ~]$」の部分が標準エラー出力になるようでして、それを拾いたかった、という方が強いです。
b-2. trapでコマンドが叩かれる度にログを出す関数を呼び出します。
以下を参考にさせていただきました。
https://www.beex-inc.com/blog/linuxbashhistory
コマンドの結果の表示は拾えないのですが、叩いたコマンドは拾えます。
b-1で情報は包含しきれているのですが、別の用途で拡張するときに使えそうなので、仕込んでおくことにします。
b-1,2を実装した.bashrc配下の通り。
$ cat ~/.bashrc
...
# User specific aliases and functions
MT_LOGDIR=/var/log/sshlogs/
function log_history {
echo $(date) $$ $BASH_COMMAND >> ${MT_LOGDIR}/history_${USER}
}
readonly -f log_history
trap log_history DEBUG
exec &> >(tee -a >(awk '{print strftime("[%Y/%m/%d %H:%M:%S] "),$0} {fflush()}' >> ${MT_LOGDIR}/log_${USER}))
まとめ
とりあえずSSHで叩いたログが拾える状態になりましたが、ツールが叩く処理の中でリダイレクトをいじっている場合にb-1と干渉しないか?という感もあり。
軽く使ってみて様子を見てみようと思います。