用 GitHub Actions + 动态密码部署构建产物

前提是服务端已经按 用时间戳 + HMAC 给 rsync 生成一次性密码 配置好了每 5 分钟轮换的 rsyncd.secrets。这篇只讲 CI 这一侧

Secrets

不存放密码,存放生成密码的命令。三个 Secrets:

  • RSYNC_ADDRESSuser@host::module
  • RSYNC_PORT873
  • RSYNC_PASSWORD_COMMAND
echo -n "deploy_user" | openssl dgst -sha256 -hmac "deploy_user$(( $(date -u +%s) / 300 * 300 ))SALT" | awk '{print $2}'

密钥格式和服务端脚本一致:用户名 + 窗口时间戳 + 盐。命令本身就算泄露,算出来的密码也只在当前 5 分钟内有效

生成密码文件

- name: Generate Rsync Password
  run: |
    set +x
    PASSWORD=$(eval "${{ secrets.RSYNC_PASSWORD_COMMAND }}")
    echo "$PASSWORD" > /tmp/rsync.password
    chmod 600 /tmp/rsync.password

set +x 关闭命令回显,避免密钥被输出到日志

上传

nick-fields/retry 包装上传步骤。上传如果正好跨过 5 分钟边界会认证失败,重试前重新生成一次密码:

- name: Deploy to Server
  uses: nick-fields/retry@v3
  with:
    max_attempts: 3
    timeout_minutes: 5
    command: |
      rsync -avz --password-file=/tmp/rsync.password ./dist/ ${{ secrets.RSYNC_ADDRESS }} \
        --delete --port=${{ secrets.RSYNC_PORT }} 2>&1 | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/[REDACTED-IP]/g'
    on_retry_command: |
      rm -f /tmp/rsync.password
      set +x
      PASSWORD=$(eval "${{ secrets.RSYNC_PASSWORD_COMMAND }}")
      echo "$PASSWORD" > /tmp/rsync.password
      chmod 600 /tmp/rsync.password

末尾那段 sed 把 rsync 输出里的 IPv4 地址替换掉,公开仓库的 Actions 日志谁都能看

清理

- name: Cleanup Password File
  if: always()
  run: rm -f /tmp/rsync.password

if: always() 保证上传失败时也会删除

效果

  • 仓库和 CI 里没有任何长期有效的凭证
  • 密码只在当前构建的几分钟内有效,重放无效
  • 服务端不需要额外开启认证服务,rsyncd 原生的密码认证就足够

配合 commit message 触发发布的做法见 用 commit message 触发 GitHub Actions 自动发版

评论

评论加载中…

输入关键词开始搜索。

选择Enter 打开Esc 关闭CtrlK 唤起