UbuntuへのSSHログインをDiscordに通知してみる
概要
Linux PAM (Pluggable Authentication Modules)を使い、SSHログイン時にDiscordへログイン通知を送る方法を記載しています。
PAMはLinuxでのユーザーの認証処理をカスタマイズできるもので、例えば、Google Authenticator PAM moduleを使うとログイン時の二要素認証が実現できたりします(SSHやVSCodeのリモート接続は頻繁に使うので、普段使いの環境では二要素認証はそう使わないでしょうが)。また、指定の実行ファイルをキックさせることも可能です。
不正ログインを検知する仕組み作りに役立つかもしれません。知らんけど。メモとして残していますので、ご参考までにお願いします。
環境
- Ubuntu Server 22.04.1
- Python 3.11.1
実施した作業
- Discordで通知を受け取るチャンネルからWebhookを作成
- Pythonスクリプト、シェルスクリプトを作成
- PAM設定を修正しスクリプトを実行させるようにする(/etc/pam.d/sshd)
DiscordでのWebhook作成方法は以下を参考にしました。
PAMが何かについては、以下を参考に(ググれば情報はかなり出てきますが)。
コード
スクリプトは2つ作成しています。
・WebhookにPOSTリクエストを投げるPythonスクリプト(本体)
・Pythonを実行するシェルスクリプト
Pythonスクリプトではrequestsとnetifaces(NICのIPアドレスを取得するライブラリ)を使用していますので、事前に仮想環境を作成するなりして、pip install
しておきます。
Pythonスクリプト
bashのシェルスクリプトでも作成できるかもしれませんが、今回はPythonで作成しました。
contentオブジェクト中のcontent
が通知メッセージの本文、username
が表示される名前です。
os.getenv
は環境変数を取得しますが、pam_execのマニュアルによるとPAM_RHOST
で接続元ホストを取得できるとあります。
import requests
import socket
import os
import datetime
import netifaces as ni
webhook_url = "[WebhookのURL]"
header = "Content-Type: application/json"
def getIPaddress(nface: str) -> str:
"""
Get IPv4 Address of NIC.
Args:
nface str: NIC Name
Returns:
IP Address v4
"""
return ni.ifaddresses(nface)[ni.AF_INET][0]["addr"]
def main():
bot_usernm = f'{socket.gethostname()} Login notification'
login_dt = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
content = {
'username': bot_usernm,
'content': f'{os.getlogin()} logged in at {login_dt} from {os.getenv("PAM_RHOST")}\n'\
f'({getIPaddress("en01")}, {getIPaddress("ts01")})'
}
res = requests.post(webhook_url, data=content)
if __name__ == "__main__":
main()
上記スクリプトを呼び出すbashシェルスクリプトは以下。なお、実行権限をつけておきます。
#!/bin/bash
cd /home/yukim/notify_discord
source .env/bin/activate
python notify_discord.py
/etc/pam.d/sshdを修正
/etc/pam.d/sshd
の下部に以下を追加。
session optional pam_exec.so type=open_session /home/yukim/notify_discord/notify_discord.sh
オプションの解説は上で挙げたマニュアルに記載されていますが、type=open_session
を付けることでログイン時にのみスクリプトを実行させることができます。これがないとログアウト時にも実行されてしまいます。
通知を確認する
試しにSSHで接続してみます。
以下のような通知が来ました。
PAMだとSSHのログインだけでなく物理端末からのログイン操作に対しても処理ができるので、調べてみる余地がありそうです。
参考
- Intro to Webhooks – Discord: Discord webhookの作り方
- Discord Developer Portal — Documentation — Webhook: POSTするjsonフォーマットに関して
- Ubuntu Manpage: PAM, pam - Pluggable Authentication Modules for Linux: PAMの概説
- Ubuntu Manpage: pam_exec - PAM module which calls an external command: pam_execの解説
Discussion