安全なリリースを検証して届ける

サイバーセキュリティBeginner
オンラインで実践に進む

はじめに

役立つリリースは、実際にチェックに合格したバージョンでなければなりません。パッケージに別のイメージが含まれていたり、ステージングで古いバージョンが動いていたりするなら、「合格」と書かれたレポートだけでは不十分です。

この DeskLite の累積的な初期環境には、すでに学習したソース、認証情報、依存関係、コンテナ、ログ記録、ゲートの対策が適用されています。このラボでは、現在のソースコミット、実際にチェック済みのイメージ、生成されたレポート、パッケージのバイト列、稼働中のローカルステージングを結び付けます。新しく扱う操作は、提供されたリリースワークフロー、tar によるパッケージ化、チェックサムの検証だけです。

これまでの対策を備えた動作中の初期環境を確認する

このステップでは、これからリリースするソースバージョンと、動作する初期環境を確認します。

cd /home/labex/project/ticket-release
git status

作業ツリーに未コミットの変更がないはずです。git rev-parse HEAD は、現在のコミットの完全な識別子を表示します。HEAD は、現在チェックアウトしているバージョンを指します。

git rev-parse HEAD

識別子はセッションによって異なります。後で、リリースマニフェストと稼働中アプリケーションのバージョンに一致する必要があります。

cat Dockerfile

明示的な業務ファイルのコピー、オフラインの依存パッケージのインストール、USER nobody を探してください。キャッシュ済みの Python ベースと wheel は用意されています。イメージの構築中にパッケージをビルドすることと、最終的なアプリケーションが実行時に非 root の ID を使うことは別です。

.venv/bin/python -m pip show requests

2.32.4 が表示されるはずです。同じ固定バージョンの要件が、候補イメージにもインストールされます。

bash /srv/ticket-release-client/sender.sh

HTTP 200 と元のチケットが返るはずです。この専用クライアントは、すでに保護された代わりの Token ファイルを読み取り、古い Token は失効しています。どちらの値もリリースメタデータにコピーしないでください。

実際のゲートと失敗を確認する比較ケースを実行する

このステップでは、パッケージ化の前に、候補とゲートの両方が動作することを確認します。

bash gate.sh

用意されたステージのラッパーは、実際の秘密情報と履歴、依存関係、ソースのチェックを実行し、コミット済みアプリケーションを Docker イメージにビルドして、その実際の候補を起動します。機能テストは、ソースバージョン、Requests 2.32.4、実際の非 root の UID 65534、元のチケット、古い Token/Token なし/誤った Token の拒否を確認します。

ゲートは、まだ最終パッケージを公開しません。チェックとテストが同じソースおよびイメージについて一致した後にだけ、受け入れ済みの候補を記録します。

次に、信頼できる失敗確認用の比較ケースを実行します。

course-release gate-test

このヘルパーは、実際の固定ルールによる認証情報の検出と、実際の入力欠落によるスキャナーエラーを使って、同じゲートを実行します。両方がビルド/テストの前に、ステータス 1 と 2 で阻止されるはずです。その後は通常の制御モードに戻し、稼働中のステージングは変更しません。

チェックの対象は引き続き、コースの固定された練習用 Token/SQL ルールと、選定された 2 件の依存関係のアドバイザリーです。本番向けの包括的なレビューではありません。

チェック済みイメージに結び付いたメタデータを生成する

このステップでは、合格したという主張を入力するのではなく、実際の受け入れ結果からリリースの証拠を生成します。

course-release manifest

ヘルパーは、実際のチェック済み Docker イメージをエクスポートし、release の下に image.tar、checks.json、manifest.json の 3 ファイルを作成します。これらはエンジニアリング上のデリバリー入力であり、学習者が別途作成する調査レポートではありません。

cat release/manifest.json

source_commit は git rev-parse HEAD に等しい必要があります。image_id は、移動可能なタグではなく、ビルドした正確なイメージを識別します。checks_sha256 は、実際の機密値をマスクしたチェックレポートを結び付け、image_sha256 は、エクスポートしたイメージのバイト列を結び付けます。run_id は、この記録を実際に受け入れられたチェック実行に結び付けます。

cat release/checks.json

ステータス 0、個々のチェックのステータス、ツールバージョン、同じソースコミットがあるはずです。認証情報の値をここに含めてはいけません。マニフェストは自動生成されます。別の成果物が合格したことにするために、フィールドを編集しないでください。

リリースのバイト列をパッケージ化して確認する

このステップでは、実際のアーカイブと、そのチェックサムを作成します。

tar は、複数のファイルをアーカイブにまとめます。-c は新規作成、-f は出力ファイル名の指定、-C release は内容を読み取るディレクトリの選択です。最後の . は、そのディレクトリの全内容を意味します。

tar -cf release.tar -C release .

アーカイブは入力ディレクトリの外に置かれるため、自分自身を含みません。-t は既存アーカイブの内容を一覧表示し、-f はその名前を指定します。

tar -tf release.tar

生成された 3 ファイルと、ディレクトリエントリが表示されるはずです。先頭に ./ が付く場合があります。

SHA-256 は、ファイルのバイト列からダイジェストを計算します。sha256sum は、ダイジェストとファイル名を表示します。見慣れた > リダイレクトで、その結果を保存します。

sha256sum release.tar > release.tar.sha256

-c は、保存したチェックサム記録を読み取り、実際のファイルと比較します。

sha256sum -c release.tar.sha256

release.tar: OK と表示されるはずです。これは、バイト列が記録されたダイジェストと一致することを示します。チェックサムだけでは、誰がファイルを公開したか、そのチェックが有効だったかは証明できません。

レポートと成果物の結び付きを検証する

このステップでは、パッケージが自ら提示するチェックサムだけでなく、それ以上の内容を確認します。

course-release verify release.tar

リリース用ヘルパーは実際のアーカイブを読み取り、予期しないメンバーや重複メンバーを拒否し、マニフェストを実際のチェック済みエクスポートと比較して、元のレポートを確認し、含まれるイメージのバイト列をハッシュ化します。現在のソースコミットの一致も要求します。

ソース、レポート、イメージ、パッケージ全体のダイジェストを結び付ける PASS が表示されるはずです。これにより、コースのローカルリリースワークフロー内で、この正確なパッケージのバイト列に対する承認が登録されます。checks.json を合格と書き換えたり、変更したイメージのチェックサムを再計算したりしても、一致する受け入れ済みチェック実行は作れません。

これは、保護されたローカル記録を使う学習用ワークフローです。学習者が sudo アクセスを持つため、この VM は本番の信頼境界にはなりません。テストしているのは、提供されたリリース手順です。公開者の署名や外部の認可機関を実装したと主張しているわけではありません。

その正確なパッケージをデプロイして実行状態を確認する

このステップでは、承認されたバイト列をデプロイし、実際の動作を生成済みの記録と比較します。

course-release deploy release.tar

ヘルパーは再びパッケージを検証し、その中のイメージを読み込んで、その正確なイメージ ID からローカルステージングを起動します。公開するのはローカルサービスのポートと、必要な読み取り専用の発行元の登録情報だけです。非公開の認証情報はイメージに埋め込まれていません。

course-release state

状態には、同じソース/イメージの識別子と、パッケージ全体のダイジェストが含まれます。次に、アプリケーション自体を確認します。

curl http://127.0.0.1:8080/health

同じ source_commit、Requests 2.32.4、UID 65534 が返るはずです。

bash /srv/ticket-release-client/sender.sh

HTTP 200 と元のチケットが返るはずです。認証なしのアクセスを確認します。

curl -i http://127.0.0.1:8080/tickets

401 が返るはずです。候補のゲートでは、古い Token と誤った Token もテストしました。マニフェストが一致するだけでは、この実際の稼働動作は証明できませんでした。

バイト列を変更したパッケージを拒否する

このステップでは、稼働中のサービスを変更せずに、完全性の強制をテストします。

cp は、ファイルをコピーします。有効なパッケージとバイト単位で同一のバックアップを残します。

cp release.tar release-original.tar

printf は、この既知のマーカーを出力します。>> はファイルに追記し、> なら置き換えます。演習のパッケージだけに、数バイトを追記します。

printf 'changed' >> release.tar
sha256sum -c release.tar.sha256

release.tar: FAILED と表示され、非ゼロで終了するはずです。tar の読み取り処理が末尾のデータを無視する場合でも、パッケージ全体のバイト列は変わっています。

course-release deploy release.tar

その正確なバイト列は承認されていないため、RELEASE BLOCKED になるはずです。この非ゼロの結果は意図したものです。新しくユーザーが作成したチェックサムでは、ワークフローのソース/レポート/イメージの結び付きや、元のパッケージへの承認を置き換えることはできません。

curl http://127.0.0.1:8080/health

以前承認されたバージョンが稼働したままです。次のステップで、最終検証の前に有効なパッケージを復元します。

復元して最終デリバリーを確認する

このステップでは、元の検証済みパッケージと、動作するステージングを維持して終えます。

cp release-original.tar release.tar
sha256sum -c release.tar.sha256

再び release.tar: OK と表示されるはずです。

course-release verify release.tar
course-release state

復元したパッケージは、実際のチェック済みソース/イメージと、すでに稼働中のステージングに一致します。コースのチェックは独立して、ゲートの失敗確認用ケースをテストし、変更したバイト列を拒否し、実際のイメージ層に対象の認証情報がないかを確認して、稼働中の成功/拒否動作を検証します。

リリースアーカイブ、チェックサム、生成されたマニフェストと実際のレポート、それらに一致する実行中バージョンがそろいました。手書きの調査は不要です。本番のデリバリーでは、公開者の身元、外部の認可、より広いセキュリティ範囲などの対策も必要です。このコースは、ローカルのチェックサムからそれらまで証明できるとは主張しません。

まとめ

実際のチェック済みソースコミット、テスト済みの非 root イメージ、元の生成されたレポート、リリースパッケージのバイト列、稼働中のローカルステージングのバージョンを結び付けました。変更したバイト列が拒否される一方で、成功と拒否の動作は正しく維持されました。チェックサムは完全性を支えますが、このローカルワークフローは、公開者の署名や外部の本番向け認可を示すものではありません。