用时间戳和 HMAC 实现一次性密码:构建安全、无明文的部署认证机制
用时间戳和 HMAC 实现一次性密码:构建安全、无明文的部署认证机制
在自动化部署中,明文密码常常是不可避免的风险点。尤其是在使用如 rsync、SFTP 等基于静态密码验证的工具时,部署脚本中往往不得不将密码暴露在 CI 系统或环境变量中。这种方式虽然便捷,但却带来了显著的安全隐患。
本文将介绍一种基于 HMAC 和 UTC 时间戳的动态认证方案。该机制无需存储明文密码,每次自动生成短时有效的一次性密码,可用于 CI/CD 流水线中的自动部署任务,并且对现有系统结构几乎无侵入。
1. 背景:自动化部署中的明文密码困境
自动部署系统中,我们通常会使用 rsync
、scp
或 ftp
将构建产物上传至远程服务器。
为了实现无人工干预的部署,这些命令常常需要配合密码认证。最常见的做法是:
- 将密码写入 CI Secrets 或脚本中
- 配置
--password-file
或环境变量传递密码
这种方式虽然方便,但一旦 Secrets 泄露或日志配置不当,就可能导致密码暴露,造成严重后果。
2. 灵感来源:TOTP 与 HMAC
本方案受 TOTP(Time-based One-time Password)机制启发。
TOTP 使用时间戳和一个共享密钥,通过 HMAC 生成短效一次性验证码。这种方式广泛用于二步验证。
而在部署场景中,我们可以借鉴这一思路,使用 Bash 脚本 + openssl 实现一个轻量版本:
- 密钥: 固定字符串 + 时间戳 + 用户名
- 输入: 用户名本身
- 输出: HMAC-SHA256 值,作为密码
3. 实现机制:生成一次性密码
示例代码如下:
1 | USER="user1" |
每 5 分钟会生成一组唯一的密码,且仅对当前用户名有效。
机制特点:
- 每个用户密码不同(基于用户名)
- 密码每 5 分钟变一次,过期即失效
- 不保存明文密码,可重复计算
- 可在客户端(CI)和服务端同步生成
4. 服务端实践:动态生成 rsync 密码文件
在服务器上,可使用如下脚本,每 5 分钟生成一次密码文件:
1 |
|
并配置 rsyncd.conf
使用该文件:
1 | auth users = user1,user2 |
搭配 cron
每 5 分钟自动刷新即可:
1 | */5 * * * * /path/to/generate_tmp_password.sh |
5. 可扩展性:不仅限于 rsync
虽然这套机制是为 rsync
场景设计的,但只要目标系统支持密码认证,它就能工作。
适用场景包括:
- SFTP(可配合
expect
脚本) - HTTP Webhook 验签
- 临时 API Token
- 内网机器之间的定时传输任务
你也可以加入:
- 多时间窗口容错(±1 时间片)
- 用户独立密钥支持
- HMAC 结果截断(如只取前 8~12 位)以便人工使用
6. 总结与下一步
本文介绍了一种轻量、安全的动态密码方案,通过时间戳 + HMAC 在客户端和服务端分别生成同步密码,避免明文暴露。
在下一篇文章中,我们将介绍如何将此机制接入 GitHub Actions,结合 Secrets 和自动构建流程,实现真正“自动化但不裸奔”的安全部署。