AWS CodePipeline CI/CDワークフローをSUSE Securityで保護
ゲスト寄稿者: Dominik Wombacher, シニアパートナーソリューションアーキテクト、AWS
本ブログでは、SUSE Securityを活用してAWS CodePipeline CI/CDワークフローをどのように保護するかをご紹介します。このプロセスでは、パイプライン内でセキュリティテストを実施し、脆弱性のないアーティファクトのみが次のフェーズに進むことを保証します。プロダクション環境では、SUSE Securityがライフサイクル全体を通じてワークロードをスキャンし、保護を提供します。
軽減すべきリスク
従来のCI/CDワークフローは、コードのビルド、ユニットテストや統合テストの実行、アーティファクトのプロダクションへの展開に重点を置いています。このアプローチ(図1参照)には特に問題はありませんが、セキュリティの観点が欠落しています。セキュリティは通常、コードがプロダクションで稼働してから初めて考慮されます。
図1: 従来のCI/CDワークフローは、コードのビルド、テスト、プロダクションへの展開に重点を置いている。
本ブログで紹介するサンプルソリューションでは、SUSE Securityをビルドおよびステージングフェーズに追加し、セキュリティの焦点を開発・デプロイのワークフローの初期段階にシフトします。
概略
まずアーキテクチャ概要を確認し、その後に各ステップを詳細に解説します。

図2: AWS CodePipelineの例。SUSE Securityがビルドフェーズとプロダクションでの継続的な保護に組み込まれている。
ワークフローの流れ:
1.バグの修正またはアプリケーションのソースコードへの機能追加
2.コードの変更をコミットしてGitリポジトリにプッシュ
3.AWS CodePipelineが新しいコミットを検出
4.最新バージョンのコードがソースステージで取得される
5.AWS CodeBuildがコンテナイメージを作成し、SUSE Securityが脆弱性をテスト。問題がない場合、イメージがAmazon ECRにプッシュされる
6.アプリケーションをテストステージでさらなる検証のためにデプロイ
7.すべてのテストに合格すると、アプリケーションがプロダクションにデプロイされる
8.SUSE Securityがアプリケーションをライフサイクル全体で保護およびスキャン
ソリューション
本ブログで説明するサンプルソリューションは、ワークフローステップの1~5をカバーしています。使用されたBuildspecやScanスクリプトはGitHubのaws-samplesで公開されています。スクリーンショットや説明を交えた手順に従って操作を行うことが可能です。

図3: バグ修正または機能追加後、ソースコードの変更がGitリポジトリにコミットおよびプッシュされる。
デモアプリケーションのDockerfile(図3)では、Node.jsバージョン16向けのSUSE Base Container Image(BCI)を使用しています。Npmパッケージを更新し、http-serverをインストールします。コンテナが起動すると、サーバーはポート8080で稼働します。これらの変更をコミットし、Gitリポジトリにプッシュします。コードは下記です:
FROM registry.suse.com/bci/nodejs:16
WORKDIR /app
COPY . .
RUN npm update \-g \\
&& npm install http-server \-g
CMD \["http-server", "-o", "/app"\]
EXPOSE 8080

図4: AWS CodePipelineがコードの変更を検出し、最新バージョンをソースステージで受信
コードが変更されてプッシュされると、図4のようにAWS CodePipelineが変更をチェックします。そして、新しい変更(コミット)を見つけると、その内容をダウンロードします(これがSourceステージです)。

図5: AWS CodePipelineがAWS CodeBuildをトリガー
Sourceステージが無事に終わると、図5に示されている通り、AWS CodeBuildがBuildステージを実行します。

図6: デモアプリケーションのDockerfileを含む最後のプッシュのGitコミットハッシュ
ビルドプロセス全体を通じて、図6に示されるGitコミットハッシュ(6909610f)が一意の識別子として使用されます。これにより、個々のビルドとコンテナイメージの基盤となるソースコードの関係を特定することが可能です。

図7: AWS CodeBuildのステータスとフェーズの詳細概要
図7で示されるようにINSTALLフェーズとPRE_BUILDフェーズは、BUILDフェーズの前に実行されます。これらのフェーズでは、AWS Elastic Container Registry(ECR)へのログインやローカルDockerレジストリの起動など、ビルドとセキュリティスキャンの準備を行います。
新しく作成されたイメージは、まずローカルレジストリに保存され、その後SUSEのセキュリティスキャンを実行します。これは、スキャン結果にDigestまたはRepoDigestという特定の情報が含まれていないと、SUSEセキュリティコントローラーがエラーを返すため、それを回避するための方法です。
ERRO|SCN|main.main: Failed to submit scan result - error=Submit scan result failed with status code 400.
イメージがAWS CodeBuild内でdockerを使ってローカルにビルドされる場合、これらの値は生成されません。これは設計上の仕様であり、docker全般の動作方法に基づくものです。この値は、イメージがレジストリにプッシュされた時点で生成され、設定されます。
SUSE Securityの仕様が変わるまでは、スキャン結果を出すために、この追加の作業を行う必要があります。

図8: 作成されたイメージ、適用されたタグ、およびSUSE Securityスキャン結果に関するAWS CodeBuildログ
AWS CodeBuildはコンテナイメージを作成し、Gitコミットハッシュをタグとして付与します。このイメージはSUSE Securityによってスキャンされます。図8の例では、スキャン結果として合計72件の脆弱性が特定され、その内訳は、高深刻度が31件、中深刻度が25件、低深刻度が16件でした。

図9: コンテナイメージ内のnpmモジュールに関するスキャン結果を含むAWS CodeBuildログ
ベースイメージのパッケージに加えて、コード関連のパッケージ(例: npm)もスキャンされました。図9では、中程度の深刻度のCVEがtarパッケージで確認されたことが強調されています。このスキャンレポートは、SUSE Securityに正常に送信されました。

図10: ビルドステータスがFAILEDのAWS CodeBuildログ
検出された脆弱性のため、図10に示されるビルドステージが失敗し、コンテナイメージはレジストリにプッシュされませんでした。開発者は問題を修正し、高深刻度の脆弱性がないコードを再提出する必要があります。

図11: AWS CodePipelineでビルドが失敗したことを示す表示
AWS CodeBuildログのステータスに加え、AWS CodePipelineも図11に示されるようにビルドが失敗したことを示します。Gitコミットハッシュは、これが最新の更新に関連していることを確認します。

図12: SUSE Securityのリスクレポート概要に表示された失敗したビルドの詳細
SUSE Securityにスキャン結果を送信する価値は、後でアクセスできる点にあります。開発者や関係者は、特定のビルドのGitコミットハッシュを検索し、図12に示される詳細レポートにアクセスできます。これにより、特定された脆弱性の分析と修正方法の決定が可能になります。また、コンプライアンスおよび監査目的の長期アーカイブとしても使用できます。

図13: デモアプリのコードエディターでの変更およびGitリポジトリへのプッシュ
脆弱性を修正するためには、ベースイメージを最新のタグに変更する必要があります。図13に示されるように、最新の変更をGitコミットしてリポジトリにプッシュすると、AWS CodePipelineがトリガーされます。

図14: AWS CodePipelineがコードの変更を検出し、最新バージョンをソースステージで受信
最初のイテレーションと同様に、図14ではAWS CodePipelineが変更をポーリングし、最新のコミットからコードをソースステージで受信する様子を示しています。

図15: AWS CodePipelineがAWS CodeBuildをトリガー
新しいビルドがトリガーされ、図15はこの実行の一意の識別子となる新しいGitコミットハッシュ(9d911191)を示しています。

図16: 新しいGitコミットハッシュをタグとして付与されたコンテナイメージと、SUSE Securityのスキャン結果を含むAWS CodeBuildログ出力
AWS CodeBuildは再びコンテナイメージを作成し、SUSE Securityによるスキャンを開始します。この結果、今回は中程度の深刻度の脆弱性が1件だけ特定されました。図16では、スキャン結果がSUSE Securityに正常に送信されたことも示されています。

図17: 成功したビルドステータスを示すAWS CodeBuildログ
使用されているスキャンスクリプトは、高深刻度の脆弱性が検出された場合にビルドを失敗させるように構成されています。今回のスキャンでは中程度の脆弱性が1件だけだったため、図17に示されるようにビルドは成功としてフラグ付けされ、コンテナイメージがAWS ECRにプッシュされました。

図18: 検証 – イメージがAWS ECRで最新タグとGitコミットハッシュでタグ付けされている
図18に示されるECRリポジトリでは、最新のイメージがビルドをトリガーしたGitコミットハッシュと同じタグでタグ付けされていることが確認できます。

図19: Gitコミットハッシュを基にスキャンされたコンテナの詳細を返すリスクレポート
図19では、SUSE SecurityでGitコミットハッシュを検索してスキャンレポートを確認する最終的な検証ステップが示されています。このレポートはAWS CodeBuildステージの結果と一致しており、中程度の深刻度の脆弱性が1件特定されています。

図20: Buildspecの抜粋、環境変数NV_CONTROLLERおよびNV_PASSWORDの設定例
図20に示されているように、必要な環境変数はBuildspec内で設定されます。特にNV_PASSWORD変数が重要で、これはSUSE Security APIへの認証に使用されます。クリアテキスト(平文)のパスワードを回避するため、AWS Secrets Managerにパスワードを追加することが推奨されます。このBuildspecの例では、AWS CodeBuildがneuvector-admin-passwordという名前のシークレットを検索し、それを自動的にビルド環境に挿入するよう設定されています。
まとめ
このブログでは、SUSE SecurityがAWS CodePipelineのCI/CDワークフローをどのように保護するかを説明しました。サンプルソリューションは、GitHub上のaws-samplesプロジェクト「NeuVector vulnerability scanner in AWS CodeBuild」のBuildspecとスキャンスクリプトを使用しています。
さあ、あなたの番です!このサンプルソリューションをブループリントとして利用し、ご自身のニーズやユースケースに合わせて適応させてください。このBuildspecやスキャンスクリプトのコマンドはAWS CodePipelineに限定されず、他のCI/CDシステムにも応用可能です。
参考資料
SUSECON 24: [TUTORIAL-1156] NeuVector Integration into AWS CodePipeline CI/CD Workflow
openSUSE Conference 24: NeuVector Integration into AWS CodePipeline CI/CD workflow
SUSE Security – Standalone Scanner for Local Scanning
SUSE Security – Build Phase Image Scanning
AWS CDK Workshop
EKS Blueprints for CDK Workshop
寄稿者
DominikはAWSのLinuxパートナーチームでSUSE製品に焦点を当てたシニアパートナーソリューションアーキテクトとして活躍しています。オープンソース愛好家であり、寄稿者でもある彼は、2002年からIT中心のキャリアを歩み、多様な技術や分野に精通しています。AWSでは、パートナーや顧客が既存ワークロードを最適化し、新しいワークロードをAWSに移行する支援を行っています。
Related Articles
8月 03rd, 2023
SUSEとIBM: データセキュリティの強化 (テクニカル・リファレンス・ドキュメント・入門ガイド)
3月 05th, 2024
エッジでの産業用IoTデバイスの接続
5月 19th, 2023
SUSEがDell Technologiesのテレコム認定を取得
12月 17th, 2024