5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

リモート拠点のグローバルIPアドレスの変更を検知し通知する

Last updated at Posted at 2021-04-23

はじめに

今回は、リモート拠点にあるLinuxベースの機器で、リモート拠点側のグローバルIPアドレスの変更を検知し、Slackに通知してもらう方法について書きたいと思います。

システム概要図

簡単ですが、今回のシステム構成図です。

システム概要図.png

※この構成図はLucidchartを利用させてもらい作成しました。(無料枠)
 Webサービスなのでもっさりした感はありましたが、UIが直観的でスムーズに作成することができました。

大まかなフローは以下の通りです。

  1. グローバルIP問い合わせ
  2. 通知(新しいグローバルIP)
  3. 確認
  4. SSH接続(ポートフォワード)

グローバルIP問い合わせ

グローバルIPアドレスの取得と変更を検出するスクリプトをcronで定期的に動かします。
今回はRaspberryPiを利用した場合の説明を記載します。
cron+シェルスクリプトが動くLinuxベースの機器であれば問題ありません。(Armadilloなど)

なお今回利用するNginxは、自社サービス向けに立てているWebサーバーを間借りして利用しています。
おそらく今回程度の利用(不特定多数の公開はしない or アクセス数が少ない)であればt2.microの無料枠でも実現可能かもしれません。

通知(新しいグローバルIP)

シェルスクリプトでグローバルIPアドレスの変更を検知した場合に、その情報をSlackに投稿します。
今回、これまた諸事情もあり旧式ではありますがWebHookの仕組みを利用します。(ここで紹介するのはWebHookのURLおよびcurlコマンド例だけで、詳細については省きます)

確認

Slackに投稿されると通知が来ますので、変わったことを知ることができます。

SSH接続(ポートフォワード)

ポートフォワードによって、グローバルIPアドレスベースでリモート拠点内のRaspberry Pi・各種デバイスにSSH接続します。(ここではそういう方式でSSH接続しますよという説明だけで、詳細については省きます)

詳細説明

このシステム構成の中で主に紹介するのは、

  • グローバルIPアドレスを取得するNginxの設定
  • グローバルIPアドレスをチェックし、変更を検知したら通知するシェルスクリプト

の2点です。
仰々しくシステム構成図まで作成しましたが、なんてことはない、手順①だけの説明でしたね。

グローバルIPアドレスを取得するNginxの設定

昨今、オフィスや拠点のグローバルIPアドレスを知るサービスはあまたあります。
今回はシェルスクリプト内から利用するので、curlなどのCLIで確認できるサービスになりますが、

httpbin.org/ip
ifconfig.io
inet-ip.info

などなど。
詳しく知りたい方は「curl グローバルIP 確認」などで検索してみてください。

私も実はちょっと前まで上記のサービスの一つを利用していました。

ですが応答が空になったことがあったり、またこの手のサービスは公開終了などが考えられましたので、自前で立てる方法はないかなと調べたら、なんとNginxの設定でサクッとできることが分かったので、今回はその方法を記載しようと思います。難しいスクリプトは作らずnginx.confに数行を追加するだけのシンプルなものです。

具体的な設定は以下の通りです。(後半の4行のみ。その他は追加場所が分かりやすいように記載しているだけです)

nginx.conf
http {
    server {
        location / {
            root   D:/nginx/html;
            index  index.html index.htm;
        }

        location /remote_addr {
            default_type text/plain;
            return 200 "$remote_addr\n";
        }

これだけ。
この設定を間借りしているAmazon Linux 2上のNginxに追加します。

この設定は、

http://xxx.secual-inc.com/remote_addr

へのリクエストがあったらレスポンスBodyに$remote_addrの内容を返すだけの設定です。

グローバルIPアドレスをチェックし、変更を検知したら通知するシェルスクリプト

#!/bin/sh

WORKDIR="/public/toolz/check_globalip"
RESULT_NOW=$WORKDIR"/check_globalip_now.txt"
RESULT_PREV=$WORKDIR"/check_globalip_prev.txt"
RESULT_DIFF=$WORKDIR"/check_globalip_diff.txt"
RESULT_JSON=$WORKDIR"/check_globalip_json.txt"

LOCKFILE=$WORKDIR"/check_globalip.lock"
if [ -f $LOCKFILE ]; then
  exit 0
fi
trap "{ rm $LOCKFILE; exit 255; }" EXIT
touch $LOCKFILE

curl http://xxx.secual-inc.com/remote_addr > $RESULT_NOW

if [ -s $RESULT_PREV ]; then
  diff $RESULT_NOW $RESULT_PREV > $RESULT_DIFF
  if [ ! -s $RESULT_DIFF ]; then
    exit
  fi
fi

cat $RESULT_NOW > $RESULT_PREV

echo 'payload={"channel": "#service_checker", "username": "service checker", "text": "@here グローバルIP変更通知 \n```' > $RESULT_JSON
cat $RESULT_NOW | sed -z 's/\n/\\n/g' >> $RESULT_JSON
echo '```", "icon_emoji": ":guardsman:", "link_names" : true}' >> $RESULT_JSON

curl -s -X POST -d @$RESULT_JSON https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx

ロックファイルやtrapの話は、是非以下の記事を参照ください。

シェルスクリプト+ロックファイルで二重実行防止 - Qiita
https://qiita.com/SECUAL_masa/items/5b1b7e8c4ed13c420435

それ以外については、個別に説明していきます。

変数定義
WORKDIR="/public/toolz/check_globalip"
RESULT_NOW=$WORKDIR"/check_globalip_now.txt"
RESULT_PREV=$WORKDIR"/check_globalip_prev.txt"
RESULT_DIFF=$WORKDIR"/check_globalip_diff.txt"
RESULT_JSON=$WORKDIR"/check_globalip_json.txt"

今回のグローバルIPアドレス変更検知は、"今取得したIPアドレスと前回取得したIPアドレスとの比較"で実施しています。各情報はファイルに保存しているので、そのファイルの変数を定義しています。

グローバルIPアドレスの取得
curl http://xxx.secual-inc.com/remote_addr > $RESULT_NOW

"/remote_addr"は、上記nginx.confの"location /remote_addr {"のことですね。
こうすることでグローバルIPアドレスがcheck_globalip_now.txtに書き出されます。

新しく取得したIPと前回のIPとを比較
if [ -s $RESULT_PREV ]; then
  diff $RESULT_NOW $RESULT_PREV > $RESULT_DIFF
  if [ ! -s $RESULT_DIFF ]; then
    exit
  fi
fi

各ファイルに保存された情報をdiffで比較して、その結果をcheck_globalip_diff.txtに保存しています。

  • 比較結果が一致(前回と一緒)       → check_globalip_diff.txtのファイルサイズは0   -> 中断
  • 比較結果が一致(前回と異なる==変更有) → check_globalip_diff.txtのファイルサイズは0以外 -> 続行
次回用に保存
cat $RESULT_NOW > $RESULT_PREV

現在の結果を次回の比較用として保存しています。

Slack投稿用JSONデータの構築
echo 'payload={"channel": "#service_checker", "username": "service checker", "text": "@here グローバルIP変更通知 \n```' > $RESULT_JSON
cat $RESULT_NOW | sed -z 's/\n/\\n/g' >> $RESULT_JSON
echo '```", "icon_emoji": ":guardsman:", "link_names" : true}' >> $RESULT_JSON

Slackに投稿するJSONデータを構築しています。
JSONフォーマットについては、Slackの仕様を確認してください。

Slackへ投稿
curl -s -X POST -d @$RESULT_JSON https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx

前述で構築したJSONをWebHook URLを呼び出して投稿(POST)しています。

cron

あとはスクリプトをcronで指定して定期的に実行するようにします。

cron
0 */1 * * * /home/pi/tools/check_globalip/check_globalip.sh > /dev/null 2>&1

Slackへの通知

今回の仕組みで最終的に以下のようにSlackに投稿されます。

投稿結果.png

なぜこの仕組みが必要だったか?

一般的にリモート拠点のメンテナンスを行う場合はリモート拠点側のグローバルIPアドレスを固定にし、VPNを利用します。しかし今回は

  • 固定のIPアドレスが取得できない(グローバルIPアドレスはDHCP)
  • ルーターはコンシューマー向けのWiFiルーター

ということもあり、ポートフォワード(*1)によりリモート拠点内のデバイスにアクセスするようにしました。
そのためにリモート拠点側のグローバルIPアドレスが変わった場合はそのグローバルIPアドレスを知る必要がありました。

*1:YAMAHAのルーターなど、IPSecを利用したVPNで片方の拠点のグローバルIPアドレスがDHCPの場合でも利用可能な方法(設定)はありますが、今回はリモート拠点側のルーターがコンシューマー向けのWiFiルーターということもあり、ポートフォワードを採用しました。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?