GitHub Actions でシークレットを共有する — Vault 不要
著者 Maxim Novak
Vaulted の GitHub Action を使えば、HashiCorp Vault なしで GitHub Actions 内のシークレットを共有できる。クライアントサイド AES-256-GCM 暗号化を使い、インフラゼロで暗号化された自己消滅型リンクを作成する。単一のワークフローステップとして動作し、Secrets Manager サーバーもクラウド設定も不要だ。
CI パイプラインは常に一時的な認証情報を必要とする。1 回のランだけ生きていればいいデプロイキー。マイグレーション中に 2 つのリポジトリ間で受け渡すトークン。あるワークフローでローテーションされ、別のワークフローで消費される認証情報。
一般的なアドバイスは「シークレット管理ツールを使え」だ。しかし、ワークフロー間で 1 つの認証情報を渡すためだけに HashiCorp Vault を立ち上げたり AWS Secrets Manager を設定したりするのは、手紙を 1 通送るために倉庫を借りるようなものだ。
GitHub リポジトリのシークレットは静的なケースにはうまく対応できる — 長期間有効な API キー、デプロイトークン、サービスアカウントの認証情報など。しかし、一時的または動的なものには対応しきれない。
課題: CI/CD における一時的なシークレット共有
リポジトリのシークレットは、変更頻度が低く単一リポジトリで消費される値を想定して設計されている。以下のシナリオには対応していない:
- キーローテーション時の一回限りの受け渡し — あるワークフローで認証情報をローテーションし、別のワークフロー(またはチーム)がその新しい値をちょうど一度だけ受け取る必要がある場合。
- リポジトリをまたいだ認証情報の共有 — 2 つのリポジトリが短命なトークンを交換する必要があるが、どちらも永続的に保存すべきでない場合。
- 時間制限付きのコントラクター用アクセス — コントラクターのデプロイ作業が終わったら失効させる CI トークン。
- シークレットがいつ消費されたかの把握 — リポジトリのシークレットには、値がいつ読まれたかどうかを確認する手段がない。
これらは一時的な問題であり、一時的な解決策が必要だ。
より軽量なアプローチ: 暗号化された自己消滅型リンク
Vaulted GitHub Action を使えば、ワークフローから直接、暗号化された自己消滅型シークレットを作成・取得できる — 管理するインフラは不要だ。
シークレットを作成する:
- name: Share rotated credential
id: share
uses: vaulted-fyi/share-secret@v1
with:
secret: ${{ steps.rotate.outputs.new_token }}
views: 1
expires: 1h
このステップは暗号化されたシークレットを含む URL を出力する。暗号化キーは URL フラグメントの中に存在するため、Vaulted のサーバーには届かない。
シークレットを取得する:
- name: Get shared credential
id: get
uses: vaulted-fyi/share-secret/get@v1
with:
url: ${{ needs.rotate.outputs.secret_url }}
- name: Deploy with rotated credential
run: ./deploy.sh
env:
API_TOKEN: ${{ steps.get.outputs.secret }}
取得後、リンクは消費され、サーバー側の暗号文(ciphertext)は削除される。シークレットはジョブの実行中のみランナーのメモリ上に存在する。
セキュリティモデル
CI/CD での利用を安全にする 3 つの特性がある:
-
Zero-Knowledge 暗号化。 シークレットは GitHub ランナー内でプロセスを出る前に AES-256-GCM で暗号化される。暗号化キーは URL フラグメント に埋め込まれており、サーバーに送信されることはない。Vaulted が保存するのは自分では復号できない暗号文のみだ。これは CI/CD に適用されたクライアントサイド暗号化だ。
-
自動ログマスキング。 Action は
core.setOutputの前にcore.setSecretを呼び出し、シークレット値の全行を GitHub のログマスカーに登録する。複数行のシークレットは行ごとにマスクされるため、部分一致もワークフローログから確実に削除される。 -
自己消滅型リンク。 閲覧回数制限と時間ベースの有効期限はサーバーサイドで強制される。
views: 1とexpires: 1hで作成されたシークレットは、最初の取得後または 1 時間後のいずれか早い方のタイミングで完全に削除される。
シークレット管理ツールとの使い分け
| シナリオ | シークレット管理ツール | Vaulted Action |
|---|---|---|
| 長期間有効な本番用認証情報 | 適切 | 不適 |
| アプリのランタイム設定(DB URL、API キーなど) | 適切 | 不適 |
| ワークフロー間の一回限りの認証情報受け渡し | 過剰 | 適切 |
| リポジトリをまたいだ一時トークンの共有 | 過剰 | 適切 |
| コントラクター向け時間制限付き CI アクセス | 過剰 | 適切 |
| ローテーション後の認証情報配布 | 過剰 | 適切 |
シークレット管理ツールは、アプリケーションがランタイムに消費するシークレットに適したツールだ。Vaulted は受け渡し — 認証情報がある場所から別の場所へ移動し、残留すべきでない瞬間 — のためにある。
はじめ方
任意のワークフローに Action を追加するだけだ:
- uses: vaulted-fyi/share-secret@v1
with:
secret: ${{ secrets.TEMP_CREDENTIAL }}
views: 1
expires: 1h
GitHub Marketplace で見つけられる。Action が作成したシークレットは Web アプリ と CLI と互換性がある — どれか 1 つで作成したものは別のいずれかで取得できる。
Vault サーバーなし。IAM ポリシーなし。インフラなし。ただ自己消滅する暗号化リンクだけ。
関連記事
- API キーを安全に共有する — API 認証情報向けの暗号化された自己消滅型リンク
- .env ファイルを安全に共有する — Slack を使わずに環境設定を共有する
- エンドツーエンド暗号化の解説 — ライブ暗号化デモ付きのビジュアルガイド