及时知道"谁在什么时候登录了服务器",是安全监控的基本需求。通过在 SSH 登录时触发脚本,将登录事件发送到邮件或 Webhook,可以实现近乎实时的登录告警。本文提供两种方案:PAM 模块挂载和 profile 脚本,并给出过滤可信 IP 减少噪音的技巧。
本文要点
- 利用 PAM pam_exec.so 在登录时触发脚本
- 通过系统邮件或 Webhook 发送登录通知
- 过滤白名单 IP,只通知陌生来源
- 脚本执行失败不影响正常登录
方案一:PAM 登录时执行脚本(推荐)
PAM(Pluggable Authentication Modules)可在任何 SSH 成功登录后执行脚本,比 profile 方案更可靠,不依赖 Shell 类型。
第一步:创建通知脚本
nano /usr/local/bin/ssh-notify.sh#!/bin/bash
LOGIN_USER="${PAM_USER}"
LOGIN_IP="${PAM_RHOST}"
LOGIN_TIME="$(date +'%Y-%m-%d %H:%M:%S')"
HOSTNAME_VAL="$(hostname)"
# 只在 SSH 登录时触发(排除其他 PAM 场景)
[ "${PAM_TYPE}" != "open_session" ] && exit 0
MESSAGE="[登录告警] ${HOSTNAME_VAL} 有新登录\n用户:${LOGIN_USER}\nIP:${LOGIN_IP}\n时间:${LOGIN_TIME}"
# 发送系统邮件(需已安装 mailutils/postfix)
echo -e "${MESSAGE}" | mail -s "[登录告警] ${HOSTNAME_VAL}" admin@example.comchmod +x /usr/local/bin/ssh-notify.sh第二步:挂载到 PAM
nano /etc/pam.d/sshd在文件末尾添加:
session optional pam_exec.so /usr/local/bin/ssh-notify.sh用 optional 而非 required
将 pam_exec.so 设为 optional,即使脚本执行失败(如邮件发送超时)也不影响 SSH 登录,避免通知脚本出错导致无法登录的严重问题。
方案二:通过 Webhook 发送通知
将脚本中的邮件发送替换为 curl Webhook 调用(以飞书机器人为例):
#!/bin/bash
[ "${PAM_TYPE}" != "open_session" ] && exit 0
WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/你的HOOK_ID"
HOSTNAME_VAL="$(hostname)"
MESSAGE="服务器 ${HOSTNAME_VAL} 有新登录\n用户:${PAM_USER}\nIP:${PAM_RHOST}\n时间:$(date +'%Y-%m-%d %H:%M:%S')"
curl -s -X POST "${WEBHOOK_URL}" \
-H "Content-Type: application/json" \
-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"${MESSAGE}\"}}"只在陌生 IP 登录时告警
在脚本中维护可信 IP 白名单,白名单内的 IP 不发通知:
#!/bin/bash
[ "${PAM_TYPE}" != "open_session" ] && exit 0
# 可信 IP 白名单(空格分隔)
TRUSTED="203.0.113.10 198.51.100.20"
for IP in ${TRUSTED}; do
[ "${PAM_RHOST}" = "${IP}" ] && exit 0
done
# 非白名单 IP 才发通知
echo "[告警] 陌生 IP ${PAM_RHOST} 以 ${PAM_USER} 登录 $(hostname)" \
| mail -s "[登录告警]" admin@example.com安装邮件发送工具
# Debian/Ubuntu
apt install -y mailutils
# 配置时选 Internet Site,填入服务器域名通知方式对比
| 通知方式 | 依赖 | 适用场景 |
|---|---|---|
| 系统邮件 | mailutils / postfix | 有邮件服务器或配置了 SMTP 转发 |
| 飞书 Webhook | curl | 团队使用飞书,快速集成 |
| 钉钉 Webhook | curl | 团队使用钉钉,快速集成 |
| 自定义 HTTP | curl | 对接内部监控告警系统 |
结合 fail2ban 使用效果更好
登录告警负责"通知你有人进来了",fail2ban 负责"把反复尝试的人拦在门外"。两者配合,主动防御加被动感知,形成互补。
小结
- PAM pam_exec.so 是最通用的登录触发方式,不依赖 Shell
- 脚本类型设为 optional,出错不影响登录
- Webhook 比邮件更实时,推荐用于运维场景
- 白名单过滤可信 IP,减少告警疲劳
常见问题
脚本出错会不会导致 SSH 无法登录?
不会,只要在 /etc/pam.d/sshd 中用 optional 而非 required,脚本失败不影响登录流程。
能不能只在 root 登录时发告警?
可以,在脚本开头加 [ "${PAM_USER}" != "root" ] && exit 0,只有 root 登录才执行后续通知逻辑。
Webhook URL 泄露了有什么风险?
他人可以用该 URL 向你的群组发送消息。发现泄露后立即在机器人管理后台禁用并重新生成 Webhook URL。