关于 cofounder-ssh-key-rotation
用于轮换已部署环境中所有 VM 的 SSH 密钥,面向需要管理远程访问的 Agent。它指导更新密钥、GitHub Secret 与工作流,并要求操作前说明停机和旧密钥撤销风险、取得确认。
主要功能
- 01按环境轮换密钥
- 02轮换前警告并确认
- 03指导更新 GitHub Secret 和工作流
- 04监控轮换并检查访问
适用场景
- 01按明确请求替换密钥
- 02预期本地密钥缺失时恢复访问
- 03VM 密钥轮换后验证访问
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ locaweb/ cofounder --skill cofounder-ssh-key-rotation安装后在 Claude Code 中输入/cofounder-ssh-key-rotation确认已加载。
详细介绍
SSH 密钥轮换
轮换已部署环境中所有 VM 的 SSH 密钥。轮换后,只有新密钥可以授予访问权限——旧密钥会从每台 VM 中永久撤销。
何时使用
- 明确请求:用户要求轮换、重新生成或替换 SSH 密钥。
- 本地密钥缺失:Agent 需要通过 SSH 连接 VM(用于查看日志、调试、访问数据库等),但预期的密钥文件在磁盘上不存在。
检测密钥是否缺失
执行任何 SSH 操作前,Agent 会解析密钥路径:
REPO_NAME=$(gh repo view --json name -q .name)
# Preview environment
SSH_KEY=~/.ssh/$REPO_NAME
# Other environments (e.g., production)
SSH_KEY=~/.ssh/$REPO_NAME-production
如果文件不存在(test -f "$SSH_KEY" 失败),则表示密钥缺失,需要进行轮换。
警告(继续操作前务必告知用户)
开始轮换前,务必警告用户:
- 停机时间:轮换会停止每台 VM、重置其 SSH 密钥并重新启动。在此过程中,环境中的所有 VM 都会停机(先处理附属服务,再处理工作节点,最后处理 Web 服务,以尽量减少用户可感知的停机时间)。
- 撤销旧密钥:旧 SSH 密钥会从所有 VM 的
authorized_keys文件中永久删除。任何使用旧密钥的人都会立即失去访问权限。 - 各环境相互独立:每个环境(预览、生产等)都有自己的 SSH 密钥。轮换只会影响指定的环境。
继续操作前,请征得用户明确确认。
轮换流程
步骤 1:确定环境
确定需要轮换的环境:
- 如果用户指定了环境,则使用该环境。
- 如果 Agent 在排查问题时发现密钥缺失,则使用当时目标操作所针对的环境。
- 如果环境不明确,请询问用户。
步骤 2:在本地生成新的 SSH 密钥
删除旧密钥文件(如果存在),并按照标准命名约定生成新密钥:
REPO_NAME=$(gh repo view --json name -q .name)
# Preview environment
rm -f ~/.ssh/$REPO_NAME ~/.ssh/$REPO_NAME.pub
ssh-keygen -t ed25519 -f ~/.ssh/$REPO_NAME -N "" -C "$REPO_NAME-deploy"
chmod 600 ~/.ssh/$REPO_NAME
# Other environments (e.g., production)
rm -f ~/.ssh/$REPO_NAME-production ~/.ssh/$REPO_NAME-production.pub
ssh-keygen -t ed25519 -f ~/.ssh/$REPO_NAME-production -N "" -C "$REPO_NAME-deploy-production"
chmod 600 ~/.ssh/$REPO_NAME-production
步骤 3:更新 GitHub 密钥
将新的私钥上传到对应的 GitHub 密钥:
# Preview
gh secret set SSH_PRIVATE_KEY < ~/.ssh/$REPO_NAME
# Production (or other environment -- suffix matches env_name uppercased)
gh secret set SSH_PRIVATE_KEY_PRODUCTION < ~/.ssh/$REPO_NAME-production
步骤 4:创建并运行轮换调用工作流
创建一个调用可复用轮换工作流的调用工作流。此流程遵循与拆除工作流相同的模式:
# .github/workflows/rotate-ssh-key-preview.yml
name: Rotate SSH Key Preview
on:
workflow_dispatch:
permissions:
contents: read
jobs:
rotate:
uses: locaweb/locaweb-cloud-provision/.github/workflows/rotate-ssh-key.yml@v1
with:
env_name: "preview"
secrets:
CLOUDSTACK_API_KEY: ${{ secrets.CLOUDSTACK_API_KEY }}
CLOUDSTACK_SECRET_KEY: ${{ secrets.CLOUDSTACK_SECRET_KEY }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
对于其他环境,请调整 env_name 和 SSH_PRIVATE_KEY 密钥引用:
# .github/workflows/rotate-ssh-key-production.yml
name: Rotate SSH Key Production
on:
workflow_dispatch:
permissions:
contents: read
jobs:
rotate:
uses: locaweb/locaweb-cloud-provision/.github/workflows/rotate-ssh-key.yml@v1
with:
env_name: "production"
secrets:
CLOUDSTACK_API_KEY: ${{ secrets.CLOUDSTACK_API_KEY }}
CLOUDSTACK_SECRET_KEY: ${{ secrets.CLOUDSTACK_SECRET_KEY }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY_PRODUCTION }}
提交并推送工作流文件,然后触发它:
git add .github/workflows/rotate-ssh-key-preview.yml
git commit -m "Add SSH key rotation workflow for preview"
git push
# Trigger the workflow
gh workflow run rotate-ssh-key-preview.yml
步骤 5:监控轮换
# Watch the run
gh run list --workflow=rotate-ssh-key-preview.yml --limit=5
gh run watch <run-id>
向用户提供 GitHub UI 中可供查看的直接链接:
gh run list --limit=1 --json databaseId,url -q '.[0].url'
如果工作流失败,请查看日志:
gh run view <run-id> --log-failed
步骤 6:验证 SSH 访问
工作流成功完成后,验证新密钥是否有效:
REPO_NAME=$(gh repo view --json name -q .name)
# Get the web IP from the latest deploy run
rm -rf $HOME/tmp/provision-output
gh run list --workflow=deploy-preview.yml --status=success --limit=1
gh run download <run-id> --name provision-output --dir $HOME/tmp/provision-output
cat $HOME/tmp/provision-output/provision-output.json
# Test SSH with the new key
ssh -i ~/.ssh/$REPO_NAME -o ConnectTimeout=10 root@<web_ip> "echo 'SSH rotation successful'"
步骤 7:恢复原任务
如果触发轮换是因为 Agent 需要 SSH 访问权限来排查问题,则使用新密钥继续原操作(查看日志、调试、访问数据库等)。
工作流输入
可复用轮换工作流(rotate-ssh-key.yml@v1)接受以下输入:
| 输入 | 类型 | 默认值 | 描述 |
|---|---|---|---|
env_name | string | "preview" | 环境名称(必须与已部署的环境一致) |
必需的密钥:
| 密钥 | 描述 |
|---|---|
CLOUDSTACK_API_KEY | CloudStack API 密钥 |
CLOUDSTACK_SECRET_KEY | CloudStack 密钥 |
SSH_PRIVATE_KEY | 新的 SSH 私钥(已在步骤 3 中更新) |
轮换操作内容(服务端)
- 验证 CloudStack 中存在 SSH 密钥对和网络(安全检查)
- 从 CloudStack 中删除旧密钥对,并以相同名称注册新的公钥
- 对每台 VM(先处理附属服务,再处理工作节点,最后处理 Web 服务):
- 停止 VM
- 通过 CloudStack API 重置其 SSH 密钥
- 启动 VM
- 使用新密钥通过 SSH 连接,并将
authorized_keys覆盖为仅包含新密钥
- 输出结果摘要
密钥文件命名约定
| 环境 | 本地密钥路径 | GitHub 密钥 |
|---|---|---|
| 预览(默认) | ~/.ssh/<repo-name> | SSH_PRIVATE_KEY |
| 生产环境 | ~/.ssh/<repo-name>-production | SSH_PRIVATE_KEY_PRODUCTION |
其他 <env_name> | ~/.ssh/<repo-name>-<env_name> | SSH_PRIVATE_KEY_<ENV_NAME>(大写) |
评论
支持 Markdown