🙌

自宅サーバのSSHにログインしたらIPアドレスと位置情報をLINE通知する

2021/07/18に公開

こんにちは(๑╹ω╹๑ )
久しぶりに自宅サーバに関連する記事を書きます!
(前回:入門自宅サーバ

序盤は前回以降に新しく構築した環境を紹介します!

成果物
日本ならregionに都道府県、cityに市区町村情報が入っています。

きっかけ

  • fail2banの環境構築をしているがsshにログインしたIPアドレス情報は念の為通知させておきたい
  • ログインするのは自分だけ(のはず?)なので通知で埋もれることは無い(はず?)

新しく構築した環境

弐号機とスイッチングハブを調達

手元のEthernetポートが足りなくなってきたため近いうちにもう一つ調達予定。

Proxmox VEで宅内クラスタ構築

物理ノード2台構成でクラスタ構築をしました
(スナップショット取得するのが案外楽しい

環境構築用のスクリプト群を実装

今日紹介するスクリプトはこちらにあります。
init-root_user.shをコピペで実行するとgit等のパッケージを諸々インストールしながら、
同リポジトリをその場でcloneして実行権限付与しながら一通りの環境構築をします。

https://github.com/huuyafwww/home-server-settings

SSHにログインしたらLINE通知する

本題に入っていきます!

事前準備物

  • 自宅サーバ
  • LINE NotifyのAPIキー
  • jqコマンド

環境

# rootへの直ログインが無効になっている
cat /etc/ssh/sshd_config | grep "^PermitRootLogin"
# => PermitRootLogin no

# ログインshellはbash
echo ${SHELL};
# => /bin/bash

ローカルネットワークの設定

ホスト部は末尾8ビット。
(ローカルネットワーク内のクライアントからSSHログインされたことを判定するために利用

名称 設定
IPアドレス 192.168.0.1
サブネット 255.255.255.0

グローバルIPを記録しておく

ローカルネットワーク内のサーバへインターネットゲートウェイ経由でアクセスした場合の通知を除外するために利用します。

curl -s ifconfig.io > /tmp/global_ipaddress;

フックとなるスクリプト

下記のスクリプトを ~notify_to_line_on_login_shell.sh という名称で設置。

#!/bin/sh

line_notify(){
  referrer_ipaddress=${!1};
  country=${!2};
  region=${!3};
  city=${!4};
  message="shellにログインしました
ip_address:${referrer_ipaddress}
country:${country}
region:${region}
city:${city}";
  curl "https://notify-api.line.me/api/notify" \
    -s \
    -XPOST \
    --header "Authorization: Bearer ${LINE_ACCESS_TOKEN}" \
    --form "message=${message}" \
    > /dev/null;
};

isLocalNetworkReffered(){
  referrer_ipaddress=${!1};
  if [ "`echo "${referrer_ipaddress}" | grep "192.168.0"`" ]; then
    return 1;
  else
    return 0;
  fi
}

isSameGlobalIpAddress(){
  referrer_ipaddress=${!1};
  global_ipaddress=`cat /tmp/global_ipaddress`;
  if [ ${referrer_ipaddress} == ${global_ipaddress} ]; then
    return 1;
  else
    return 0;
  fi
}

record_last_referrer_ipaddress(){
  last_referrer_ipaddress=${!1};
  echo ${last_referrer_ipaddress} > /tmp/referrer_ipaddress;
};

referrer_ipaddress=`echo ${SSH_CLIENT} | cut -f1 -d' '`;
last_referrer_ipaddress=`cat /tmp/referrer_ipaddress`;

# 最後にアクセスしたリファラIPアドレスの場合
if [ ${referrer_ipaddress} == ${last_referrer_ipaddress} ]; then
  exit;
fi

isLocalNetworkReffered referrer_ipaddress;

# ローカルネットワーク経由のログインの場合
if [ ${?} -eq 1 ]; then
  exit;
fi

isSameGlobalIpAddress referrer_ipaddress;

# ローカルネットワーク内のサーバにインターネットゲートウェイ経由でアクセスしている場合
if [ ${?} -eq 1 ]; then
  exit;
fi

# アクセス元のIPアドレス情報記録
curl -s http://ip-api.com/json/${referrer_ipaddress}?lang=ja > /tmp/referrer_ipaddress_info.json

country=`cat /tmp/referrer_ipaddress_info.json | jq .country | sed -e 's/"//g'`
regionName=`cat /tmp/referrer_ipaddress_info.json | jq .regionName | sed -e 's/"//g'`
city=`cat /tmp/referrer_ipaddress_info.json | jq .city | sed -e 's/"//g'`

# shellにログインしたIPアドレス情報をLINEに通知する
line_notify referrer_ipaddress country regionName city;

# リファラIPアドレスを記録する
record_last_referrer_ipaddress referrer_ipaddress;

exit;

通知を除外するルール

  • ローカルネットワーク内からのSSHログイン
  • 最後にSSHへログインした時と同一のIPアドレス
  • ローカルネットワーク内のクライアントだがインターネットゲートウェイ経由でのSSHログイン

リファラIPのgeo location情報の取得について

ip-apiを利用しています。
(無料プランの場合はAPIキーは不要ですが、1分間に最大45回のリクエスト、SSL通信が利用できない等の制限があります。

https://members.ip-api.com/

curl -s http://ip-api.com/json/${referrer_ipaddress}?lang=ja

以下がAPIドキュメント

https://ip-api.com/docs/api:json

SSHログイン時に発火させる

SSHログイン時に発火させるために /etc/ssh/sshrc に上記までのスクリプトを実行する記述をします。

.bashrc ファイルに記述してもフック可能ですが、
下記の事象でもフックされてしまうため /etc/ssh/sshrc に記述します。

sshログイン => rootユーザにログイン => rootユーザからログアウト

環境変数の LINE_ACCESS_TOKEN はスクリプト実行前に読み込まれている必要があります。

echo "export LINE_ACCESS_TOKEN=アクセストークン
~/notify_to_line_on_login_shell.sh" >> /etc/ssh/sshrc

さいごに

沼の底が見えない。。。

Discussion