シェルスクリプトで業務を自動化
前回までで、シェルとシェルスクリプトについては一通り説明を行った。今度は機能を使って実用的なシェルスクリプトを作ってみよう。シェルやシェルスクリプトを使う最大の目的の1つは処理の自動化だ。人間が手動で処理するのではなく、コンピュータにデータの処理を行わせる。シェルスクリプトはその最も簡単な方法の1つだ。
今回はその例として、sshdのログファイルを解析して、大量に不正ログインを実行しようとしてくるホストのIPアドレスを取り出す方法を取り上げようと思う。サーバ管理者であれば、パブリックIPに接続した段階から、sshポートに対して不正ログインが試みられることはよくご存知だろう。
危険性の高いIPアドレスを取り出してファイアウォールにブロックを追加するというのは1つの運用手段だ。スクリプトを使うと完全に処理を自動化して、自動的にブロックルールを更新するといったこともできる。今回はログデータを整理する処理をシェルスクリプトで実施する例を紹介する。
ワンライナーでざっくり作成
この手の処理を行うときは、ワンライナーからはじめていくと処理が簡単だ。まず、次のようにしてログファイルからsshdに関するログデータを取り出してみる。これは「sshd[プロセスID]」という文字列が含まれている行を取り出す処理になっている。
# grep -E 'sshd\[[0-9]*\]' /var/log/auth.log | head -20
Jul 31 07:18:59 virt sshd[4600]: error: maximum authentication attempts exceeded for root from 170.80.226.29 port 51154 ssh2 [preauth]
Jul 31 07:19:07 virt sshd[4603]: error: maximum authentication attempts exceeded for root from 170.80.226.29 port 51158 ssh2 [preauth]
Jul 31 07:19:25 virt sshd[4610]: error: maximum authentication attempts exceeded for invalid user admin from 170.80.226.29 port 51170 ssh2 [preauth]
Jul 31 07:19:33 virt sshd[4614]: error: maximum authentication attempts exceeded for invalid user admin from 170.80.226.29 port 51176 ssh2 [preauth]
Jul 31 07:19:46 virt sshd[4621]: error: maximum authentication attempts exceeded for invalid user oracle from 170.80.226.29 port 51186 ssh2 [preauth]
Jul 31 23:40:29 virt sshd[47403]: error: maximum authentication attempts exceeded for root from 27.41.190.25 port 28590 ssh2 [preauth]
Aug 1 17:49:51 virt sshd[40750]: error: Received disconnect from 180.149.125.152 port 33524:7: Service not available [preauth]
Aug 2 08:22:45 virt sshd[37061]: error: maximum authentication attempts exceeded for root from 59.125.69.40 port 43106 ssh2 [preauth]
Aug 2 08:22:48 virt sshd[37063]: error: maximum authentication attempts exceeded for invalid user admin from 59.125.69.40 port 43111 ssh2 [preauth]
Aug 2 08:22:53 virt sshd[37067]: error: maximum authentication attempts exceeded for root from 59.125.69.40 port 43112 ssh2 [preauth]
Aug 2 08:22:55 virt sshd[37070]: error: maximum authentication attempts exceeded for root from 59.125.69.40 port 43116 ssh2 [preauth]
Aug 2 19:55:03 virt sshd[49535]: error: maximum authentication attempts exceeded for root from 223.199.221.178 port 38235 ssh2 [preauth]
Aug 2 22:44:10 virt sshd[53073]: error: maximum authentication attempts exceeded for root from 113.109.110.51 port 43758 ssh2 [preauth]
Aug 3 01:38:55 virt sshd[66889]: error: maximum authentication attempts exceeded for invalid user admin from 168.205.194.9 port 40676 ssh2 [preauth]
Aug 3 12:28:40 virt sshd[83372]: error: maximum authentication attempts exceeded for root from 14.118.206.120 port 33252 ssh2 [preauth]
Aug 3 12:39:09 virt sshd[83589]: error: maximum authentication attempts exceeded for root from 183.128.224.219 port 43194 ssh2 [preauth]
Aug 3 19:12:55 virt sshd[91666]: error: maximum authentication attempts exceeded for root from 113.17.31.61 port 43055 ssh2 [preauth]
Aug 4 01:42:05 virt sshd[7432]: error: maximum authentication attempts exceeded for root from 115.213.143.250 port 48576 ssh2 [preauth]
Aug 4 04:08:55 virt sshd[10828]: error: maximum authentication attempts exceeded for invalid user 1234 from 188.92.77.12 port 39217 ssh2 [preauth]
Aug 4 04:23:18 virt sshd[11119]: error: maximum authentication attempts exceeded for invalid user adm from 188.92.77.12 port 48984 ssh2 [preauth]
#
データとして欲しいのは日付データとログインを試みたユーザー名、それにアクセス元のIPアドレスといったところだ。次のようにawkコマンドをつなげて、該当する列だけを取り出していく。
# grep -E 'sshd\[[0-9]*\]' /var/log/auth.log | awk '{print $1,$2,$3,$12,$14}' | head -20
Jul 31 07:18:59 root 170.80.226.29
Jul 31 07:19:07 root 170.80.226.29
Jul 31 07:19:25 invalid admin
Jul 31 07:19:33 invalid admin
Jul 31 07:19:46 invalid oracle
Jul 31 23:40:29 root 27.41.190.25
Aug 1 17:49:51 33524:7: not
Aug 2 08:22:45 root 59.125.69.40
Aug 2 08:22:48 invalid admin
Aug 2 08:22:53 root 59.125.69.40
Aug 2 08:22:55 root 59.125.69.40
Aug 2 19:55:03 root 223.199.221.178
Aug 2 22:44:10 root 113.109.110.51
Aug 3 01:38:55 invalid admin
Aug 3 12:28:40 root 14.118.206.120
Aug 3 12:39:09 root 183.128.224.219
Aug 3 19:12:55 root 113.17.31.61
Aug 4 01:42:05 root 115.213.143.250
Aug 4 04:08:55 invalid 1234
Aug 4 04:23:18 invalid adm
#
必要のない行も含まれていることがわかる。IPアドレスが掲載されていない行は必要がないので、さらに次のようにIPアドレスが含まれている行だけをgrepコマンドで抽出していく。
# grep -E 'sshd\[[0-9]*\]' /var/log/auth.log | awk '{print $1,$2,$3,$12,$14}'| grep -E '[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}' | head -20
Jul 31 07:18:59 root 170.80.226.29
Jul 31 07:19:07 root 170.80.226.29
Jul 31 23:40:29 root 27.41.190.25
Aug 2 08:22:45 root 59.125.69.40
Aug 2 08:22:53 root 59.125.69.40
Aug 2 08:22:55 root 59.125.69.40
Aug 2 19:55:03 root 223.199.221.178
Aug 2 22:44:10 root 113.109.110.51
Aug 3 12:28:40 root 14.118.206.120
Aug 3 12:39:09 root 183.128.224.219
Aug 3 19:12:55 root 113.17.31.61
Aug 4 01:42:05 root 115.213.143.250
Aug 4 09:15:49 root 170.80.227.99
Aug 4 11:35:13 root 217.92.127.208
Aug 4 20:20:24 root 71.202.241.115
Aug 4 22:27:30 root 58.35.16.9
Aug 4 23:56:53 root 27.222.223.201
Aug 5 13:51:12 root 31.181.215.22
Aug 5 20:01:50 root 113.215.220.89
Aug 6 01:25:36 root 101.235.114.131
#
「[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}」はIPアドレスに一致する正規表現だ(厳密にIPアドレスのみに一致するわけではないのだが、この用途ではこれで十分だ)。データ抽出に関してはこのくらいで十分だろう。
シェルスクリプトに整理する
ワンライナーで基本となるコマンドの動作を確認したら、今度はワンライナーをシェルスクリプトにまとめていく。ここでは次のようにシェルスクリプト「ssh-check」をまとめてみた。
#!/bin/sh
logfile=/var/log/auth.log
# ログデータを取得
cat $logfile |
# sshdに関するログのみを選択
grep -E 'sshd\[[0-9]*\]' |
# 必要なデータのみを抽出
# 1列目: 月
# 2列目: 日
# 3列目: 時:分:秒
# 12列目: ユーザ名
# 14列目: アクセス元IPアドレス
awk '{print $1,$2,$3,$12,$14}' |
# 必要なログのみを選択
grep -E '[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}' |
# 日付データを正規化(年月日時分秒)
while read mon day time user ip
do
date=$(date --date="$mon $day $time" +%Y%m%d%H%M%S)
echo "$date $user $ip"
done
# 1:年月日時分秒 2:ユーザ名 3:アクセス元IPアドレス
ワンライナーとの違いは、最後に「Aug 6 01:25:36」といった感じで出力されている日付を20190806012536といった形式に整えている点にある。GNU coreutilsに含まれているdateコマンドは—dateオプションという機能があり、このような感じのフォーマット変換ができるようになっている。
また、最後にはタブ区切りでデータを出力させている。この辺りは、自分が使いやすいデータ形式にしてもらえればよい。カンマ区切りにすればCSVになる。
作成したssh-checkスクリプトを実行すると次のようになる。
# ./ssh-check
20190731071859 root 170.80.226.29
20190731071907 root 170.80.226.29
20190731234029 root 27.41.190.25
20190802082245 root 59.125.69.40
20190802082253 root 59.125.69.40
20190802082255 root 59.125.69.40
20190802195503 root 223.199.221.178
20190802224410 root 113.109.110.51
20190803122840 root 14.118.206.120
20190803123909 root 183.128.224.219
20190803191255 root 113.17.31.61
20190804014205 root 115.213.143.250
20190804091549 root 170.80.227.99
20190804113513 root 217.92.127.208
20190804202024 root 71.202.241.115
20190804222730 root 58.35.16.9
20190804235653 root 27.222.223.201
20190805135112 root 31.181.215.22
20190805200150 root 113.215.220.89
20190806012536 root 101.235.114.131
20190806041631 root 183.159.195.55
20190806083625 root 121.25.24.86
20190806083642 root 76.20.69.183
20190806121535 root 177.184.189.209
20190806121544 root 177.184.189.209
20190806215749 root 113.215.193.142
20190806234122 root 91.250.22.133
20190807000655 root 188.92.75.248
20190807000854 root 188.92.75.248
20190807000859 root 188.92.75.248
20190807000906 root 188.92.75.248
20190807000910 root 188.92.75.248
20190807000914 root 188.92.75.248
20190807000929 root 188.92.75.248
20190807000932 root 188.92.75.248
20190807000936 root 188.92.75.248
20190807000940 root 188.92.75.248
20190807000944 root 188.92.75.248
20190807000949 root 188.92.75.248
20190807000958 root 188.92.75.248
20190807001003 root 188.92.75.248
20190807001007 root 188.92.75.248
20190807001026 root 188.92.75.248
20190807001029 root 188.92.75.248
20190807001034 root 188.92.75.248
20190807001037 root 188.92.75.248
20190807001046 root 188.92.75.248
20190807001050 root 188.92.75.248
20190807030112 root 49.69.83.42
20190807071353 root 125.42.179.246
20190807092650 root 49.130.34.61
20190807113440 root 115.213.128.113
20190807204659 root 115.59.120.27
20190808015054 root 124.91.188.127
20190808025740 root 114.236.111.192
20190808051431 root 121.234.62.143
20190808125819 root 180.69.95.125
20190808131159 root 73.153.145.9
20190808223543 root 182.86.99.103
20190809100145 root 14.145.21.169
20190809113933 root 60.184.127.149
20190810021324 root 114.236.205.156
20190810080309 root 118.112.91.138
20190810155600 root 113.122.54.85
20190810161007 root 36.26.115.174
20190810180254 root 183.191.223.60
20190810184841 root 27.44.240.37
20190810190739 root 27.10.230.41
20190811045451 root 79.105.214.148
20190811164947 root 222.140.18.37
20190811185757 root 1.28.3.152
20190811201904 root 118.112.91.138
20190812012034 root 39.187.73.53
20190812092544 root 61.147.42.240
20190812174217 root 168.205.194.23
20190813005553 root 220.141.144.17
20190813054308 root 182.243.121.39
20190813144706 root 221.223.95.29
20190813145320 root 115.209.80.158
20190813204448 root 178.248.87.113
20190814022117 root 114.248.106.156
20190814062028 root 122.189.222.238
20190814065936 root 178.69.74.35
20190814081613 root 112.123.68.214
20190814182723 root 171.123.196.194
20190814233809 root 27.211.110.13
20190815010116 root 114.91.131.79
20190815023707 root 114.217.214.92
20190815030819 root 106.111.72.217
20190815040938 root 118.168.131.152
20190815093608 root 193.189.87.216
20190815130927 root 190.142.211.194
20190815143204 root 67.182.89.30
20190815155723 root 95.238.21.47
20190815202302 root 36.251.149.219
20190816030555 root 1.170.18.101
20190816054335 root 50.98.130.158
20190816122130 root 115.216.39.37
20190816212806 root 36.248.182.119
20190817055516 root 95.81.121.121
20190817055527 root 95.81.121.121
20190817063533 root 39.82.165.124
20190817083816 root 103.119.82.220
20190817094555 root 46.150.230.54
20190817100717 root 36.230.99.91
20190817155145 root 36.230.99.91
20190817203241 root 42.239.176.213
20190818021743 root 49.70.151.179
20190818163134 root 182.119.156.35
20190819024959 root 125.114.22.221
20190819194308 root 113.91.169.110
20190820090542 root 182.119.154.243
20190820162334 root 112.246.50.25
20190820195338 root 27.129.238.107
20190820201501 root 106.118.29.177
20190820235332 root 175.43.163.84
20190821013511 root 125.109.141.104
20190821041219 root 45.7.108.95
20190821051739 root 114.253.120.188
20190821071459 root 222.78.76.80
20190821144648 root 175.166.225.213
20190821151246 root 153.34.196.52
20190821203441 root 58.55.40.180
20190821232227 root 37.255.15.124
20190822125701 root 113.229.70.29
20190822184017 root 115.59.161.203
20190823014523 root 111.59.184.154
20190823030850 root 14.117.245.25
20190823084328 root 124.230.246.25
20190824005329 root 110.88.116.49
20190824051808 root 46.159.26.118
20190824085148 root 183.184.1.44
20190824114000 root 112.242.187.85
20190824211956 root 1.252.42.102
20190824231103 root 221.231.49.178
20190825012547 root 36.106.167.197
20190825071308 root 223.241.254.22
20190825135313 root 113.215.223.108
20190825171011 root 171.117.148.213
20190826061317 root 119.165.192.72
20190826074303 root 149.147.186.20
20190826074312 root 149.147.186.20
20190826091634 root 168.90.143.166
#
ここまでデータを整理すれば、あとはスプレッドシートアプリケーションに流し込んで処理することもできる。
コマンドやシェルスクリプトの扱いに慣れてくれば、このくらいのシェルスクリプトなら1、2分で作れるようになる。「ログファイルからデータを取り出す作業を手動で」なんて、とてもじゃないが面倒でやっていられない。シェルスクリプトを使えば、こんな感じでサクッと処理することができる。知っているのと知っていないのとでは大きな違いだろう。一度自動化してしまえば、業務がぐっと楽になる。ぜひともいろいろな処理の自動化に挑戦してもらいたい。