egressview

Release署名鍵の運用手順

English

この手順は、正式な署名付きportable releaseの信頼起点を確立します。CIは毎回破棄する 試験鍵を使うだけで、releaseの真正性は保証しません。 release-signing/trusted-fingerprints.jsonにactiveな鍵が登録されるまでは、正式な project鍵で署名済みとは表現しません。

署名鍵

リリース鍵はAWS KMSの非対称鍵です。秘密鍵はKMS内で生成され取り出せないため、 保管・バックアップ・紛失・漏えいの対象になる鍵ファイルが存在しません。署名には ファイルの所持ではなく、認証されたAWS principalが必要です。

   
エイリアス alias/egressview-release
リージョン ap-northeast-1
鍵仕様 ECC_NIST_EDWARDS25519SIGN_VERIFY
署名アルゴリズム ED25519_SHA_512MessageType: RAW

署名できるのはEgressViewRelease permission setだけです。 この制限はIAMではなく キーポリシーにあります。アカウント管理用のstatementはkms:Signを意図的に含まないため、 管理者は鍵のrotation・ポリシー変更・削除予約はできても、その鍵でリリースに署名することは できません。他のロール、とりわけEC2インスタンスロールへkms:Signを付与しないでください。 署名はメンテナのworkstationから行うもので、サーバ側にこの権限は不要です。

リリース前にサインインします。

aws sso login --profile egressview-release

公開鍵とfingerprintの取得:

aws kms get-public-key --profile egressview-release \
  --key-id alias/egressview-release --query PublicKey --output text \
  | base64 -d > /tmp/egressview-release.der
openssl pkey -pubin -inform DER -in /tmp/egressview-release.der \
  -out /tmp/egressview-release.pub.pem
node scripts/release-key-fingerprint.js /tmp/egressview-release.pub.pem

fingerprintの算出は独立してもう一度実行し、全桁を比較してください。先頭や末尾だけの 比較は不可です。

Fingerprintの登録・公開

公開鍵とactive recordをrelease-signing/trusted-fingerprints.jsonへreview付きPRで 追加します。key ID、完全なSHA256:<64文字の小文字hex> fingerprint、生成日、公開鍵 pathを記録します。同じ完全なfingerprintを次の全経路で公開します。

Releaseに同梱した.pub.pemだけでは信頼起点になりません。リポジトリも同様です。 利用者は、このリポジトリの侵害が及ばない経路から取得したfingerprintと照合します。

署名・公開

メンテナのワークステーションで、1コマンドです。 タグをcheckoutしてから、

aws sso login --sso-session egressview
AWS_PROFILE=egressview-release npm run release:publish -- --tag v2.0.3

これが手順のすべてです。1コマンドにしているのは意図的です。 2.0.0・2.0.1・2.0.2はいずれも署名済み資産なしで公開されました。パイプラインが失敗したのではなく、実行されなかったのです。「リリースする」と「署名する」が、人が順に思い出して実行する別々の行為だったためです。3回連続で飛んだという事実は、覚えていることが管理策ではないことの証拠です。

順序が本質であり、コマンドがそれを強制します。

  1. HEADがタグと厳密に一致し、作業ツリーがclean、npm run release:checkが通ることを確認するまで着手しません。dirtyな状態から作ったリリースはタグが指すものではなく、後から署名しても直りません。
  2. 既に公開済みのタグは、ビルドと署名を費やす前に拒否します。
  3. KMS鍵でビルドと署名を行います。
  4. バンドルを検証し、さらに改竄3ケースが落ちることを証明します(アーカイブの改変、チェックサムの書き換え、署名の偽造)。
  5. fingerprintをtrust registryとDNS TXTレコードに照合します。DNSはこのリポジトリとは別系統の資格情報で提供されています。成果物の隣にしか公開されていないfingerprintは何も証明しません。
  6. draftとしてリリースを作成し、4点をアップロードします。
  7. その資産をGitHubから落とし直して検証します。手元のディスク上のものではなく、リリースページが実際に配信するものを見ます。
  8. ここまで通って初めて、draftを公開へ切り替えます。

draft先行が、未署名のリリースを「起こりにくい」ではなく「作れない」にしている点です。 どこかで落ちれば残るのはdraftであって、「検証手段が無い公開済みリリース」にはなりません。2.0.xが置かれていたのは、まさにその状態でした。

--dry-run を付けると、GitHub上に何も作らずに5番までを実行できます。

その後ろのゲート

.github/workflows/release-gate.yml が、リリースの公開時と編集時、および週次で npm run release:verify-published を実行します。手動実行に検査対象を選ばせません — 実行する人が何を検査するか選べるものはゲートではないからです。古いタグを1つ調べたいときは、手元で npm run release:verify-published -- --tag <tag> を実行します。リリースページが配信するものをダウンロードして検証するので、GitHubのWeb画面など別経路で作られたリリースも、公開後に資産が削除・差し替えられた場合も捕まえます。AWSアクセスは不要です。

この手順より前に公開され署名されなかったリリースは、理由付きで release-signing/unsigned-releases.json に記録してあり、ゲートは永久に失敗するのではなく既知の事実として報告します。常に失敗するゲートは、人が無視することを学ぶゲートです。 方針の発効日以降に公開されたリリースの登録はテストが拒否するため、このリストが新しい失敗を黙らせる抜け道になることはありません。

署名はワークステーションに置いたままにします

GitHub Actionsに kms:Sign のOIDCロールを与えて人を完全に排除する案は魅力的ですが、それは署名できる主体を「SSOセッションを持つ人がワークステーションで」から「ワークフローで実行される何か」へ広げます。鍵ポリシーで署名を専用プリンシパルに限定し、trust anchorを意図的にリポジトリの外に置いているプロジェクトで、規律の問題をサプライチェーンの問題に置き換える取引です。鍵は今の場所に置き、ワークステーション側の作業を1コマンドにします。

offline:bundle--private-key は引き続き利用でき、KMSの代わりにローカルの鍵ファイルを取ります。すべてのpull requestで使い捨て鍵により機構を動かし続けるCIのため、および独自に配布物を作る人のためのものです。公式リリースを作るものではありません。

リリースノート

成果物名、チェックサム、完全なfingerprint、署名鍵ID、検証ガイドへのリンクを必ず記載します。リリース番号とHubのバージョンが異なる場合(2.0.2はHub 1.10.0を含み、成果物名はHubのバージョンに従います)は両方を明記し、成果物名とノートが黙って食い違わないようにします。

Rotation・漏えい対応

計画rotationでは、旧鍵と新鍵で個別に署名したartifactを1 releaseだけ併記し、両fingerprintを 独立経路でも告知します。overlap releaseの公開後に旧鍵をretiredへ変更します。

overlap releaseは旧鍵で署名する必要があるため、rotation時にKMS鍵の削除を予約しないで ください。 待機期間が過ぎると削除は取り消せません。検証は同梱の公開鍵とopensslだけで 完結し鍵を必要としないので、旧鍵を残すコストは$1/月にすぎず、何かあった時に再度署名できる 余地を買えます。明確な理由がない限り保持してください。

漏えいの疑いがあればreleaseを直ちに停止します。鍵をrevokedにし、完全なfingerprintと incident日を全公開経路で告知し、KMS鍵を無効化するか、release permission setからkms:Signを外します。新鍵を作成し、review済みtagから影響artifactを再構築します。既存GitHub Releaseのartifactを、 明示的なincident noticeと新versionなしに差し替えません。