SSHログインの成功/失敗をslackに通知する

クラウドサーバを利用していたり、自宅サーバに外部から接続できるようにしていると、不正アクセスによる乗っ取りの可能性を考える必要があります。
**（少なくともパスワード認証を禁止して鍵認証によるログインは絶対にしておきましょう）**

それでも、本当にサーバが乗っ取られていないか心配ですよね。
そこで、SSH接続時に出力されるログを監視してログイン成否を通知してみます。
swatchを使用します。

# 環境
・動作環境：IDCFクラウド
・OS：CentOS 6.9

# インストール
epelリポジトリを追加する必要があります。

<pre>
rpm -ihv http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
yum -y install swatch
</pre>

# 設定ファイル作成
`/etc`配下に設定ファイルを作成して監視条件を指定します。
<pre>
mkdir /etc/swatch
mkdir /etc/swatch/conf
touch /etc/swatch/conf/secure.conf
</pre>

```bash:/etc/swatch/conf/secure.conf
### 成功時通知
watchfor /Accepted/
        exec "\/root\/slack\/bin\/authAlert.sh $_ > /dev/null 2>&1"

### 失敗時通知
watchfor /Invalid user/
        exec "\/root\/slack\/bin\/authAlert.sh $_ > /dev/null 2>&1"
```

`\ * + . ? { } ( ) [ ] ^ $ - | /`がメタ文字となるため、バックスラッシュでエスケープしています。
ここでは`watchfor`の後で指定する監視文字列をそれぞれ`"Accepted"`と`"Invalid user"`にしています。
これは`/var/log/secure`に出力されるSSHログイン成功時、失敗時の文字列です。他の出力例は[こちら](http://linux.just4fun.biz/?Linux%E7%92%B0%E5%A2%83%E8%A8%AD%E5%AE%9A/ssh%E3%81%AB%E3%82%88%E3%82%8B%E4%B8%8D%E6%AD%A3%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B)を参考にしてください。

そして、条件にマッチした際に`exec`でシェルスクリプトを実行してslackに通知します。引数の`$_`は検知行全体という意味です。
Slackへの通知はSlack APIでやります。[参考](http://qiita.com/rubytomato@github/items/6558bfdb37d982891c09)
今回用いる通知シェルスクリプトの中身はこんな感じです。

```bash:/root/slack/bin/authAlert.sh
#!/bin/bash
USERNAME="SSH-alert"
CHANNEL="#test"
ICON=":ghost:"
TEXT=$*
WEBHOOK_URL="https://hooks.slack.com/services/T2PBMxxxx/B2Q5xxxxx/JuG08e37bczxxxxxxxxxxx"

author="author name"

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
```
パーミッション変更も忘れずに。`chmod 700 /root/slack/bin/authAlert.sh`

swatchではその他にも様々な挙動をさせることができます：[参考](http://oxynotes.com/?p=7517)

# 動作確認
swatchを起動して動作確認してみます。書式はこんな感じです。
<pre>
swatch -c [設定ファイル] -t [監視対象ログファイル]

</pre>
監視ログファイルは`/var/log/secure`ですので、以下の通り実行します。

```bash:
swatch -c /etc/swatch/conf/secure.conf -t /var/log/secure &
```
ログインして通知されるか確認してみます。![sshalert.png](https://qiita-image-store.s3.amazonaws.com/0/154711/b9744f97-9119-d562-ba88-2ac9a005c611.png)

`"Accepted"`および`"Invalid user"`を含む行が通知されていることが分かります。
※上のほうにたくさん`"Invalid user"`が通知されていますが、**辞書式アタックというのは本当に頻繁に来ていることが分かります。**

# サービス登録
あとはサービス登録して自動起動するようにしておきます。

```bash:/etc/init.d/swatch
#/bin/sh
#
# swatch
#
# chkconfig: 2345 90 35
# description: swatch start/stop script
#
. /etc/rc.d/init.d/functions

[ ! -d /var/log/swatch ] && mkdir -p /var/log/swatch

PATH=/bin:/sbin:/usr/bin:/usr/sbin

start() {
  ls /var/run/swatch_*.pid 1> /dev/null 2>&1
  if [ $? -ne 0 ]; then
    echo -n "Starting swatch"
    pno=0
    RET=0
    for conf in /etc/swatch/conf/*.conf
    do
      log=`basename $conf | cut -d\. -f1`
      if [ -f /var/log/$log ]; then
        pno=`expr $pno + 1`
        swatch -c $conf -t /var/log/$log --daemon \
        --pid-file /var/run/swatch_$pno.pid 1>> /var/log/swatch.log 2>& 1
        RET=$?
        [ $RET != 0 ] && return $RET
      fi
    done
    if [ $pno -gt 0 ]; then
      echo
      [ $RET = 0 ] && touch /var/lock/subsys/swatch
    fi
    return $RET
  else
    echo "swatch already started"
  fi
}
stop() {
  ls /var/run/swatch_*.pid 1> /dev/null 2>&1
  if [ $? -eq 0 ]; then
    echo -n "Stopping swatch"
    for pid in /var/run/swatch_*.pid
    do
      kill $(cat $pid)
      rm -f $pid
    done
    echo
    rm -f /var/lock/subsys/swatch /tmp/.swatch_script.*
  else
    echo "swatch is not starting"
  fi
}
status() {
  ls /var/run/swatch_*.pid 1> /dev/null 2>&1
  if [ $? -eq 0 ]; then
    echo -n "swatch (pid"
    for pid in /var/run/swatch_*.pid
    do
      echo -n " `cat $pid`"
    done
    echo ") is running"
  else
    echo "swatch is stopped"
  fi
}

case "$1" in
  start)  start;;
  stop)    stop;;
  restart)stop && start;;
  status)  status;;
  *)      echo "Usage: swatch {start|stop|restart|status}" && exit 1;;
esac

exit $RET
```

<pre>
service swatch start
chkconfig swatch on
</pre>

以上です。