用 PAM 模块重构 SSH 实现飞书登录报警
AI-摘要
GPT
AI初始化中...
介绍自己
生成本文简介
推荐相关文章
前往主页
前往tianli博客
在常规的 SSH 登录通知方案中,我们常使用 .bashrc 或 /etc/ssh/sshrc。但在实际生产环境中,这些方案往往会因为 VS Code Remote、SFTP 或多通道连接导致通知瞬间“刷屏”。
为了实现单次会话仅通知一次的精准预警,我们改用 Linux 系统底层的 PAM 模块 进行重构。
一、 重构思路
PAM 方案的逻辑在于:当 sshd 成功验证用户身份并准备开启会话(Session)时,通过 pam_exec.so 调用我们预设的脚本。
- 触发位置:系统级会话开启时,不依赖用户使用哪种 Shell。
- 防刷逻辑:PAM 会话逻辑保证了在一个完整的 SSH 连接周期内,通知脚本仅被触发一次。
- 数据来源:直接调用 PAM 环境变量(如
$PAM_RHOST),获取数据更直接。
二、 落地步骤
1. 编写核心通知脚本
在 /usr/local/bin/ 目录下创建通知脚本,这种方式可以避开用户家目录权限问题。
Bash
sudo nano /usr/local/bin/ssh_feishu_notify.sh
粘贴以下代码:
Bash
#!/bin/bash
# 只有在开启会话(open_session)时才执行发送逻辑
if [ "$PAM_TYPE" = "open_session" ]; then
# 1. 提取基础信息
LOGIN_IP=$PAM_RHOST
LOGIN_USER=$PAM_USER
HOST_NAME=$(uname -n)
# 2. 修正时区:确保在任何系统设置下,通知均显示北京时间
FULL_DATE=$(TZ='Asia/Shanghai' date +"%Y-%m-%d %H:%M:%S")
LOGIN_TIME=$(TZ='Asia/Shanghai' date +"%H:%M:%S")
# 3. 登录方式识别 (解析 Ubuntu/Debian 常见的 auth.log)
LAST_AUTH=$(grep "Accepted " /var/log/auth.log 2>/dev/null | grep "$LOGIN_IP" | tail -n 1)
if echo "$LAST_AUTH" | grep -q "publickey"; then
AUTH_TYPE="SSH 密钥登录 (Key)"
elif echo "$LAST_AUTH" | grep -q "password"; then
AUTH_TYPE="账号密码登录 (Password)"
else
AUTH_TYPE="SSH 登录 (Session)"
fi
# 4. 构建飞书交互式卡片 JSON (符合 Schema 2.0 规范)
JSON_DATA=$(cat <<EOF
{
"msg_type": "interactive",
"card": {
"schema": "2.0",
"body": {
"direction": "vertical",
"elements": [
{ "tag": "markdown", "content": "${FULL_DATE}" },
{ "tag": "markdown", "content": "**登录成功来源**" },
{ "tag": "markdown", "content": "时间:${LOGIN_TIME}\n设备 IP:${LOGIN_IP}\n登录用户:${LOGIN_USER}\n登录方式:${AUTH_TYPE}" },
{ "tag": "hr" },
{ "tag": "markdown", "content": "<font color='grey'>来自 ${HOST_NAME} (PAM Service)</font>" }
]
},
"header": {
"title": { "tag": "plain_text", "content": "【${HOST_NAME}】${LOGIN_IP} 通过 SSH 登录了服务器" },
"template": "blue"
}
}
}
EOF
)
# 5. 异步推送 Webhook (防止网络延迟阻塞登录速度)
curl -s -X POST -H "Content-Type: application/json" \
-d "$JSON_DATA" \
"https://open.feishu.cn/open-apis/bot/v2/hook/你的机器人密钥" > /dev/null 2>&1 &
fi
2. 配置权限
确保脚本具有可执行权限,否则 PAM 无法调用:
Bash
sudo chmod +x /usr/local/bin/ssh_feishu_notify.sh
3. 挂载到 PAM 配置
编辑 SSH 的 PAM 配置文件:
Bash
sudo nano /etc/pam.d/sshd
在文件末尾添加一行(注意路径准确):
Plaintext
session optional pam_exec.so /usr/local/bin/ssh_feishu_notify.sh
三、 技术要点复盘
1. 为什么不用环境变量锁?
之前的方案尝试在内存中设置环境变量来防抖,但现代 IDE(如 VS Code)会开启完全隔离的会话进程。PAM 方案通过 optional 模式挂载,仅在 sshd 建立主会话时由 root 触发一次,从根本上解决了进程级重复的问题。
2. 时区修正
脚本中显式声明 TZ='Asia/Shanghai' 是最稳妥的做法。很多云服务器或路由器固件(如 iStoreOS)默认使用 UTC,如果不加声明,收到的通知会有 8 小时的偏差。
3. 静默处理
在 curl 命令末尾添加 > /dev/null 2>&1 & 是性能优化的关键。它将推送任务丢入后台异步执行,即便飞书服务器响应慢,也不会导致你在 SSH 输入完密码后卡顿。
四、 结语
通过 PAM 模块进行的这次重构,我们将原本琐碎、不稳定的登录报警逻辑,提升到了系统服务级别。这不仅让通知更准、更稳,也让服务器的运维管理变得更加专业和优雅。
- 感谢你赐予我前进的力量
赞赏者名单
因为你们的支持让我意识到写文章的价值🙏
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 ShiDai
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果

