はじめに
サーバを複数台管理しています。
ホスト数が増えてくるとどうしても管理が大変になってきますね。
僕の場合にはチームで管理していたり、一部の作業を委託したりするのですが、その場合にセキュリティ的に大丈夫かな?というのが気になっていました。
「サーバのセキュリティ」というと個別にはfail2banですとか、ファイアーウォールですとか色々あるのですが、「ログイン、sudoを早めに知る」ことに重きを置きました。
- 早めに知ること
- 一元化してチームで知ること
- 「監視出来ていること」による抑止効果
「早めに知ること」は、不正なアクセスや不正な作業を行われた場合に早く対処することが重要です。
ログの追跡やファイルの退避、復元を行うためには時間が勝負です。色々と埋もれてしまっては被害が拡大します。
Slack通知
ということで、サーバで起きた重要な事、特に「SSHでのログイン」と「sudoで実行されたコマンド」をSlackで通知することにしました。
やりかた
@sak39 くんがパッケージ化してくれました。ありがとうございます!
curl https://raw.githubusercontent.com/yousan/swatcher/master/init.sh | sudo bash - && sudo bash <(curl https://raw.githubusercontent.com/yousan/swatcher/master/etc/swatch.sh)
上記のパッケージでは /usr/local/bin/slack_notify.sh
として通知部分を落としてくるので、そのファイルのSlack NotifyのWEBHOOK_URLを書き換えておきます。
!/bin/bash
USERNAME="Gatekeeper"
CHANNEL="#l2tp_server_notify"
ICON=":ghost:"
TEXT=$*
WEBHOOK_URL="https://hooks.slack.com/services/xxxxxx/xxxxxx/xxxxxxxxxx"
author="sa9sha9"
data=`cat << EOF
payload={
"channel": "$CHANNEL",
"username": "$USERNAME",
"icon_emoji": "$ICON",
"link_names": 1 ,
"attachments": [{
"text": "$TEXT"
}]
}
EOF`
curl -X POST --data-urlencode "$data" $WEBHOOK_URL
Swatchで検出するログの種類を
## SSHログイン検知
watchfor /Accepted/
echo
exec "\/usr\/bin\/slack_notify.sh $_ > /dev/null 2>&1"
### ssh失敗検知
#watchfor /Invalid user/
# echo
# exec "\/usr\/bin\/slack_notify.sh $_ > /dev/null 2>&1"
### ssh失敗検知
#watchfor /Failed/
# echo
# exec "\/usr\/bin\/slack_notify.sh $_ > /dev/null 2>&1"
### sudo実行検知
watchfor /.*COMMAND.*/
echo
exec "\/usr\/bin\/slack_notify.sh $* > /dev/null 2>&1"
動かした結果
いい感じですね!
技術について
Swatchというパッケージを使っています。
サーバのログを監視するSwatchの導入方法と使い方を解説
(日本語ですごく詳細な記事です。助かりました!)
Swatch自体は結構古いパッケージのらしいですが、ログを監視してアクションを起こす、という今回の要件に必要な基本的な機能を備えています。
- Swatchを常時起動化する
- Swatchで特定のログ(sshとsudo)を検出する
- Slackで通知する
という流れになっています。
Swatchでログを検出させる
confファイルでログを検出する条件を記述します。
watchfor /Accepted/
echo
exec "\/usr\/local\/bin\/slack_notify.sh $_ > /dev/null 2>&1"
ここで受け取った条件を元に exec
行で実行します。
このファイルでは/usr/local/bin/slack_notify.sh
を実行しています。
Swatchの常時起動
Swatcherは少し古いパッケージということもあり、常時起動していません。
常時起動する方法の情報がいくつか出てきたのですが、今回は「CRONでプロセスが死んでたら起動する」という方法を取りました。
本来であればCentOSなり、Ubuntuなりでサービスとして登録するスクリプトを書いてリポジトリに取り込んでもらったりすると幸せなんですが、書き方が分からなかった…、というが実情です。(どなたか教えてください!)
ということで /etc/cron.d
にswatchを起動するスクリプトを置きます。
# /etc/cron.d/swatchron: crontab entries for the swatch
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
@hourly root ps auxwwww | grep "/usr/bin/swatch -c /etc/swatch/conf/secure.conf -t/var/log/auth.log" | grep -v 'grep' >/dev/null || /usr/bin/swatch --daemon --awk-field-syntax / -c /etc/swatch/conf/secure.conf -t /var/log/secure
ps auxwwww | grep ...swatch... || /usr/bin/swatch
の箇所で、「起動していなければ起動する」を実現しています。(原始的ですね…👾)
--daemon
でデーモン化を、--awk-field-syntax
でログファイルにコロン(:
)が含まれていても尻切れトンボにならないようにしています。
コロンの箇所についてはSwatch本体がログファイルの文字列の取り込みにPerlの$_
を使っていて、その標準のデリミタがコロンのために切れていました。
辛抱強く調べてもらった @sak39 君さすがです!
Slackへの投稿
Slackへの投稿はcURLコマンドを使っています。
swatcherのインストールを行った後にsudo emacs /usr/local/bin/slack_notify
などでSlackのWebhookURLを書き換える必要があります。
#!/bin/bash
USERNAME="Gatekeeper"
CHANNEL="#l2tp_server_notify"
ICON=":ghost:"
TEXT=$*
WEBHOOK_URL="https://hooks.slack.com/services/xxxxxx/xxxxxxx/xxxxxxxxxxxx"
author="sa9sha9"
data=`cat << EOF
payload={
"channel": "$CHANNEL",
"username": "$USERNAME",
"icon_emoji": "$ICON",
"link_names": 1 ,
"attachments": [{
"text": "$TEXT"
}]
}
EOF`
curl -X POST --data-urlencode "$data" $WEBHOOK_URL
まとめ、雑感
ということでSlackに監視することができました。
SSHで入る場合には基本的にマシンの前にいるわけで、SSHで入った際にSlackでnotifyが飛んでくる、というのは邪魔じゃないかなと思います。
普段メールは開かない生活になっているのでSlackに集約できるのは有り難いですね。
もちろんですがnotifyの部分を変えることでメールでもLINEでも行けると思います。便利ですね。
ただ「sudoのコマンドにパスワードが含まれてたらSlackに流れる」ですとか「Slackのログあふれない?」ですとか運用して修正するポイントもありそうですが、今の所は便利だなーと思っています。
それから最近WordPressサイトのハッキング被害を受けたりもして、SwatcherのWordPress版もあると良いなぁと企んでいます。
今後とも良い監視ライフを送っていきたいですね。