cofounder-ssh-key-rotation について
デプロイ済み環境の全 VM を対象に SSH キーをローテーションするスキルです。Agent にキー交換、GitHub Secret とワークフローの更新、アクセス確認を案内し、停止と旧キー失効について事前説明と確認を求めます。
主な機能
- 01環境ごとのキー交換
- 02実行前の警告と確認
- 03GitHub 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 キーのローテーション、再生成、または置き換えを依頼した場合。
- ローカルキーがない場合:エージェントが VM に SSH 接続する必要がある(ログの確認、デバッグ、データベースへのアクセスなど)ものの、想定されるキーファイルがディスク上に存在しない場合。
キーがないことの検出
SSH 操作の前に、エージェントはキーのパスを解決します。
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 キーがあります。ローテーションの対象は指定した環境のみです。
実行前に、明示的な確認を求めてください。
ローテーションの手順
Step 1:環境を特定する
ローテーションが必要な環境を特定します。
- ユーザーが環境を指定した場合は、それを使用します。
- トラブルシューティング中にエージェントがキーがないことを検出した場合は、対象としていた環境を使用します。
- 環境が不明確な場合は、ユーザーに確認します。
Step 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
Step 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
Step 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
Step 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
Step 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'"
Step 7:元のタスクを再開する
トラブルシューティングのためにエージェントが SSH アクセスを必要としてローテーションを開始した場合は、新しいキーを使って元の操作(ログの確認、デバッグ、データベースへのアクセスなど)を再開します。
ワークフローの入力
再利用可能なローテーションワークフロー(rotate-ssh-key.yml@v1)が受け付ける入力:
| 入力 | 型 | デフォルト | 説明 |
|---|---|---|---|
env_name | string | "preview" | 環境名(デプロイ済みの環境名と一致する必要があります) |
必須のシークレット:
| シークレット | 説明 |
|---|---|
CLOUDSTACK_API_KEY | CloudStack API キー |
CLOUDSTACK_SECRET_KEY | CloudStack シークレットキー |
SSH_PRIVATE_KEY | 新しい SSH 秘密鍵(Step 3 で更新済みのもの) |
ローテーションで行われる処理(サーバー側)
- SSH キーペアとネットワークが CloudStack に存在することを確認します(安全性チェック)
- 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>(大文字) |