DevSecOps におけるアセット作成と証拠収集
DevSecOps プロセスにおいて、セキュリティコンプライアンスを維持するためには、構築、テ スト、配備の内容を追跡する必要がある。 資産作成と証拠収集がこのトレーサビリティを提供し、セキュリティがソフトウェア開発ライフサイクルの各段階とシームレスに統合されることを保証する。 このアプローチは、「シフト・レフト・セキュリティ」のコンセプトを具現化するものであり、セキュリティは後付けではなく、開発プロセスに内在するものである。
このガイドでは、 DevSecOps のパイプラインにアセットベースのエビデンス収集を導入する方法を説明する。 これらの実践に従うことで、あなたはできるようになる:
- CI/CDパイプラインで生成されたすべての成果物を追跡する
- セキュリティ・スキャンとコンプライアンス・チェックの証拠を収集する
- 規制遵守のための監査可能な証跡の維持
- 課題管理と変更要求の自動化
ワークフローを理解する
資産と証拠の収集プロセスは、主に3つの段階を踏む:
- アセット情報の取得- アーティファクト(イメージ、デプロイメントなど)を構築する際に、そのメタデータを保存します
- インベントリへの登録- 環境にまたがって資産を追跡するインベントリエントリを作成します
- 証拠を収集する- セキュリティスキャンの結果とテスト結果を特定の資産に関連付ける
このワークフローは、パイプライン内のすべてのアーティファクトが、ビルドからデプロイまで、完全なコンプライアンス履歴を持つことを保証します。
資産とは何か?
DevSecOps,、 資産とは、セキュリティテストとスキャンを受けるあらゆる人工物や実体を指す。 資産とは、コンプライアンス・チェックの「対象」であり、テストし、スキャンし、最終的に展開するものだと考えてください。
一般的な資産タイプ
パイプラインにおいて、資産はさまざまな形をとることができる:
- ソースコードのコミット- ビルドおよびテストされるコード
- コンテナイメージ- ビルドによって生成された Docker イメージ
- デプロイメント成果物- Kubernetes マニフェスト、 Helm チャート、または構成ファイル
- パイプラインの実行- パイプラインの実行そのもの
でサポートされている様々なアセットタイプを下図に示します。 DevSecOps:
資産を特定する方法
各資産は、ユニークかつ不変的に識別されなければならない。 これにより、パイプラインが複数回実行されても、アセットに対して収集されたエビデンスが常にまったく同じアーティファクトを参照するようになります。
資産識別フォーマット:
-
コミットアセット :リポジトリとコミットハッシュ
https://repo.url/org/repo#<COMMIT-SHA> -
画像アセット : Docker 画像とそのダイジェスト
docker://registry.URL/name@sha256:<SHA256-DIGEST> -
パイプライン・ラン・アセット :パイプラインとランID
pipelinerun://<PIPELINE_ID>/<RUN_ID> -
その他の資産有資格者 URL 例
- アセットをファイル名(ヘルムチャートまたは設定ファイル)でコミットします:
https://repo.url/org/repo#<COMMIT-SHA>/<filename> - アーティファクト資産:
<artifactory-url>/artifact.<filetype>
- アセットをファイル名(ヘルムチャートまたは設定ファイル)でコミットします:
エビデンスが常に正確なアーティファクトのバージョンを参照するように、変更可能なラベル(タグ、ブランチ)ではなく、不変の識別子(コミットSHA、イメージダイジェスト)を使用する。
エビデンスとは何か?
証拠とは、特定のセキュリティスキャン、テスト、コンプライアンスチェックが資産に対して実施されたことを証明する記録である。 エビデンス・エントリーには
- 実行されたチェックの種類(脆弱性スキャン、ユニットテストなど)
- チェックを実行したツール(例: SonarQube, Jest)
- 結果のステータス (成功、失敗、保留)
- 詳細な結果、課題、添付ファイルへのリンク
エビデンスとは、資産、収集のために実行したツール、その結果、添付ファイルがあればそれを示すメタデータである。 この設計により、各資産の真実の単一のソースを維持しながら、複数の環境にわたってコンプライアンスを追跡することができます。
在庫管理基準
インベントリは、環境全体にわたるすべてのアセットのメタデータの中央レジストリとして機能します。 一貫性を確保し、自動化されたissue管理を可能にするため、アセットを保存し、インベントリエントリーを作成する際には、以下のフィールド標準に従ってください:
-
タイプ :アーティファクトのタイプを示す予約キーワード:
commitコミット資産image画像アセット用genericパイプライン稼働資産の場合
その他のアーティファクト タイプの場合は、固有のタイプを適切に示す文字列を選択できます(たとえば、ディプロイメント ファイルの場合は
deployment、tar ファイルの場合はtar)。 -
名前 :パイプラインの実行中は、アーティファクト名を静的に維持します。 自動クローズ問題の正しさを保証するために、コミットハッシュのような動的要素を名前に組み込むことは避ける。
例:
us.icr.io/my-registry/my-app:20230828074614-master-commit-1@sha256:sha256-1my-app-202304211845444721_IKS_deployment
-
証明 :アーティファクトの出所を証明するために、完全修飾ドメイン URL。
例:
us.icr.io/my-registry/my-app:20230828074614-master-commit-1@sha256:sha256-1
-
ダイジェスト正規表現パターンに従ってください:
sha256で始まり、コロン (:) が続き、実際の SHA256 ハッシュ (sha256:<sha256>) が続く。次に例を示します。
sha256:sha256-1
-
署名 :成果物に署名がある場合は、関連する署名情報を含める。
これらの標準化されたガイドラインに従うことで、在庫管理プロセスが強化され、資産の正確な追跡と取得が確保されます。
ワークフローの実装
コンセプトを理解したところで、3段階のワークフローをパイプラインに実装してみよう。
ステージ1:資産情報の取得
パイプラインがアーティファクトをビルドするときに、 save_repo と save_artifact コマンドを使用してメタデータをキャプチャします。 この情報は、後日、インベントリー・エントリーを作成し、証拠を収集するために使用される。
リポジトリ情報の保存
パイプラインがソースコードをチェックアウトしたら、 save_repo コマンドを使って リポジトリの詳細を記録します。 これにより、ビルド成果物は、それらを生成した特定のコミットと関連付けられる。
例:
save_repo app-repo \
url=<app_url> \
path=my-app \
commit=commit1 \
branch=master \
buildnumber=1
アーティファクト情報の保存
アーティファクト(イメージ、デプロイメントファイルなど)をビルドしたら、 save_artifact コマンドを 使用してその詳細を記録します。 これはアーティファクトの名前、タイプ、ダイジェスト、出所をキャプチャする。
どのような時に使うのか:
- Docker イメージ構築後
- デプロイメントマニフェストの生成後
- デプロイされるアーティファクトを作成した後
例 Docker 画像の保存
パイプラインがビルドし、 Docker イメージをプッシュした後:
save_artifact app-image \
name=us.icr.io/my-registry/my-app:20230828074614-master-commit-1@sha256:sha2561 \
type=image \
digest=sha256:sha2561 \
tags=mytag1 \
source=<source_url> \
signature=sign-1 \
provenance=us.icr.io/my-registry/my-app:20230828074614-master-commit-1@sha256:sha2561
例配置アーティファクトの保存
Kubernetes マニフェストや Helm チャートなど、画像以外のアーティファクトの場合:
save_artifact artifact-1 \
name=my-app_IKS_deployment \
type=deployment \
signature=sign2 \
deployment_type=IKS \
provenance=<url>
ステージ2:インベントリー・エントリーの作成
資産情報を取得したら、インベントリに登録します。 インベントリは、環境全体の資産を追跡し、開発から本番までの推進ワークフローを可能にする。
在庫パラメータを理解する
以下のパラメータを指定して cocoa inventory add コマンドを使う:
| 引数 | 説明 | 必須 / 任意指定 | 注記 |
|---|---|---|---|
artifact |
成果物名 | [文字列] [必須] | 課題管理の対象として使用 |
version |
アプリケーションのバージョン | [文字列] [必須] | 成果物のバージョン |
repository-url |
アプリケーションのリポジトリ | [文字列] [必須] | URL このアセットが構築されたリポジトリの |
pipeline-run-id |
パイプラインランのID | [文字列] [必須] | CDおよびCCパイプラインのエビデンスのスコープに使用される |
commit-sha |
アプリケーション・バージョンの正確なコミット | [文字列] [必須] | このアセットがビルドされているリポジトリ URL のコミット SHA |
name |
アプリケーション名 | [文字列] [必須] | 資産のファイル名またはインベントリエントリー |
build-number |
製造番号 | [文字列] [必須] | インサイトの更新に使用されるアセットのビルド番号 |
type |
アーティファクトのタイプ: commit, image, generic, deployment, またはその他のカスタムタイプ |
[文字列] [必須] | save_artifact コマンドで保存したタイプと一致しなければならない |
app-artifacts |
資産に関する追加情報 | [文字列] [オプション] | 追加メタデータのJSONフォーマット |
sha256 |
アーティファクトの SHA256 ハッシュ | [文字列] [必須] | ロッカー内の資産のパスを定義するために使用されます |
provenance |
アーティファクトが格納されている完全修飾 URL | [文字列] [必須] | 完全な URL アーティファクトの場所まで |
signature |
工芸品のサイン | [文字列] [必須] | 資産の署名を検証するために使用 |
environment |
項目を追加する必要がある環境の名前 | [文字列] [オプション] | エントリを追加するインベントリブランチ (デフォルトは master) |
インベントリエントリーの作成
以下の例では、さまざまな資産タイプのインベントリエントリを作成する方法を示します。 パラメータが save_artifact で保存した情報と一致していることに注意。
例 Docker 画像をインベントリに登録する
この例では、先ほど保存した Docker 画像のインベントリエントリーを作成します:
cocoa inventory add \
--artifact=us.icr.io/my-registry/my-app:20230828074614-master-commit-1@sha256:sha2561 \
--name=my-app \
--app-artifacts='{ "app": "my-app", "tags": "20230828074614-master-commit1" }' \
--signature=sign1 \
--provenance=us.icr.io/my-registry/my-app:20230828074614-master-commit-1@sha256:sha2561 \
--sha256=sha256:sha2561 \
--type=image \
--repository-url=<repo_url> \
--commit-sha=commit1 \
--version=commit1 \
--build-number=1 \
--pipeline-run-id=pipeline-run-1 \
--org=Org \
--repo=my-inventory-20230421184544472 \
--git-provider=github \
--git-token-path=./inventory-token \
--git-api-url=<api_url>
例配置アーティファクトをインベントリに登録する
デプロイメント成果物についても、プロセスは同様ですが、 deployment タイプを使用します:
cocoa inventory add \
--artifact=my-app_IKS_deployment \
--name=my-app_IKS_deployment \
--app-artifacts='{ "app": "my-app", "tags": "20230828074614-master-commit1" }' \
--signature=sign2 \
--provenance=<provenance_url> \
--sha256=sha256:sha2562 \
--type=deployment \
--repository-url=<repo_url> \
--commit-sha=commit1 \
--version=commit1 \
--build-number=1 \
--pipeline-run-id=pipeline-run-1 \
--org=Org \
--repo=my-inventory-20230421184544472 \
--git-provider=github \
--git-token-path=./inventory-token \
--git-api-url=<api_url>
ステージ3:証拠の収集
パイプラインがセキュリティスキャンとテストを実行するときに、その結果と特定の資産とを関連付ける証拠を収集する。 これにより、各アーティファクトに対してどのチェックが行われたかを示す監査可能な証跡が作成される。
資産の証拠収集
を使用する。 collect-evidence コマンドを使用する。 asset-key パラメータは、 save_artifact または save_repo でアセットを保存する際に使用したキーと一致する必要があります。 すべてのパラメータ、サポートされるツール形式、およびCLIの使用方法など、
collect-evidence コマンドの詳細については、 collect-evidenceスクリプトを 参照してください。
例ソースコードに対するテストの証拠収集
ソースコード・リポジトリに対して実行されるテストの場合:
collect-evidence \
--tool-type "jest" \
--status "success" \
--evidence-type "com.ibm.unit_tests" \
--asset-type "repo" \
--asset-key "repo-1"
例成果物の単体テストの証拠を収集する
受け入れテストを実施した後、成果物に関する証拠を収集する:
collect-evidence \
--tool-type "jest" \
--status "success" \
--evidence-type "com.ibm.acceptance_tests" \
--asset-type "artifact" \
--asset-key "app-image"
受け入れテストを実施した後、複数の成果物について証拠を収集する:
collect-evidence \
--tool-type "jest" \
--status "success" \
--evidence-type "com.ibm.acceptance_tests" \
--evidence-per-asset \
--assets "app-image:artifact" \
--assets "artifact-1:artifact"
ベスト・プラクティス
不変識別子を使用する
タグやブランチ名ではなく、常にコミットのSHAとイメージダイジェストを使用する。 変更可能な参照は変更される可能性があり、証拠と資産の間のリンクが壊れる。
一貫したネーミングの維持
パイプラインの実行中は、アーティファクト名を固定します。 issueの適切な追跡と自動閉鎖を確実にするため、nameフィールドにタイムスタンプのような動的な値を埋め込むことは避けてください。
アセットタイプに合わせる
cocoa inventory add の type パラメーターが save_artifact で使用されているタイプと一致していることを確認する。 タイプの不一致は証拠収集の失敗の原因となる。
デプロイメントにおける参照実績
CDパイプラインでは、 artifact フィールドではなく、 provenance フィールドを使用して成果物をダウンロードします。 出所 URL は、成果物の完全で不変の場所を提供する。
次のステップ
アセットベースのエビデンス収集についてご理解いただけただろうか:
最適化されたパイプライン実行のための証拠再利用
パイプラインの実行時間とリソース使用量を最適化するには、エビデンスの再利用を有効にします。 この機能により、スキャン対象のアセット(アーティファクトまたはリポジトリ)が前回のスキャン以降に変更されていない場合に、スキャンやテストをスキップすることができます。
再利用の条件、有効期間、高度な設定など、エビデンスの再利用の詳細については、 PRおよびCIパイプライン間でのエビデンスの再利用を 参照してください。
CD パイプラインでは、成果物をダウンロードするために、デプロイメントは成果物ではなく生成フィールドを参照する必要があります。