本文の内容は、2022年10月26日にEduardo Mínguezが投稿したブログ(https://sysdig.com/blog/docker-scanning-jenkins/)を元に日本語に翻訳・再構成した内容となっております。
Sysdig Secureを使ってJenkins上でコンテナイメージの脆弱性やバッドプラクティスをスキャンするのは、簡単なプロセスです。この記事では、Sysdig Secure Jenkinsプラグインを使用して行う方法のステップバイステップの例を示します。
このブログ記事は、2022年4月以降に利用できる脆弱性スキャナを中心にご紹介しています。レガシースキャナーを使用している場合は、公式ドキュメントを参照してください。
こちらからパイプラインの定義をご確認いただけます。
Sysdig Secureによるイメージの脆弱性スキャン
イメージスキャンにより、DevOpsチームは、コンテナが本番環境にデプロイされる前、またはイメージがコンテナレジストリにプッシュされる前に、パイプラインの初期段階で既知の脆弱性を検出し、コンテナビルド構成を検証することで、セキュリティをシフトレフトさせることができます。これにより、問題の迅速な検出と修正、本番環境での脆弱性の回避、クレデンシャルの漏洩の回避、本番環境へのデプロイ時間の短縮が可能になり、そのすべてがより安全な方法で行われます。
Sysdigのイメージスキャンプロセスは、ImageConfigのチェック(機密情報の漏洩など)、OSやサードパーティ製パッケージ(java、python、etc.)のチェックなど、さまざまなルールを含むカスタマイズ可能なポリシーに基づいて行われます。
Sysdigの脆弱性スキャンは、スキャン手順を実行する場所によって、イメージの分類が異なります。:
- パイプライン: ランタイムフェーズの前段階(開発者のワークステーション、CI/CDパイプラインなど)で、
sysdig-cli-scanner
ツールを使用してスキャンする場合。 - ランタイム: 実行ノードでイメージを実行し、Sysdigエージェントでスキャンを実行する場合。
今回は、Jenkinsを使用してパイプラインのステップでスキャンを実行する方法を、採用すべきベストプラクティスとして紹介します。
コンテナ・イメージに対してスキャナーを実行するのは、以下のようないくつかのフラグ(詳細は公式ドキュメントを参照)を付けて sysdig-cli-scanner
ツールを実行するのと同じくらい簡単です。
SECURE_API_TOKEN=<your-api-token> ./sysdig-cli-scanner --apiurl <sysdig-api-url> <image-name> --policy <my-policy>イメージはツールを実行するホスト、ラップトップやパイプラインを実行するコンテナ上でローカルスキャンされ、スキャン結果のみがSysdig Secureのバックエンドに送信されます。
Sysdig Secure Jenkins プラグインは
sysdig-cli-scanner
をラップし、Jenkins 環境で簡単に使用できるようにします。Pipelineジョブで使用するか、Freestyleジョブのビルドステップとして追加して、イメージ解析の実行、イメージに対するカスタムポリシーの評価、セキュリティスキャンの実行のプロセスを自動化することが可能です。Jenkinsによる脆弱性スキャン
Jenkinsはオープンソースの自動化サーバで、さまざまなイベントをトリガーとした強力なCI/CD(継続的インテグレーション/継続的デリバリーまたはデプロイメント)ワークフローを作成し、ソフトウェア開発タスクを自動化することができます。最も有名なCI/CDツールの1つで、統合やツールのための豊富なプラグインエコシステムが用意されています(1800以上のコミュニティプラグインがあります!)。
イメージスキャンは、開発プロセスの早い段階でセキュリティを導入することで、CI/CDワークフローの重要なステップとなっています(セキュリティ・シフトレフト)。私たちのワークフローでは、定義がGitHubリポジトリに保存されているコンテナイメージを構築し、Sysdig Secure Jenkinsプラグインを使ってローカルでイメージをスキャンします。スキャン結果はSysdigに送信されます。スキャンに失敗した場合、ワークフローは中断され、レジストリにイメージがアップロードされるのを防ぎます。Sysdig Secure Jenkinsプラグインによるコンテナイメージのスキャン
この例で使用するSysdig Secure Jenkinsプラグインのバージョンは、新しいスキャンエンジンが搭載された2.2.5です。レガシースキャナーを使用している場合は、Sysdig Secure JenkinsプラグインのGitHubリポジトリにある公式ドキュメントとREADME-legacy.mdファイルを参照してください。前提条件
Sysdig イメージスキャンを稼働させるための要件は簡単です:
- すでに稼働しているJenkinsサーバー(この例ではJenkinsバージョン2.361.2を使用しています)
- コンテナイメージの定義が格納されているGitリポジトリ(例:GitHub)
- スキャン結果を収集するSysdig Secureのアカウント。お持ちでない場合は、無料トライアルをリクエストしてください。
- ビルドする準備が整ったコンテナDockerfile。この例をフォークして使用することもできますが、独自のコンテナを使用する方がより楽しいでしょう!
準備ができたら、次に進みましょう!
この例で行っているステップは、Jenkinsの Configuration as Code を使用しても行うことができます。Sysdig Secure Jenkinsプラグインをインストールする
Sysdig SecureプラグインはJenkinsプラグインとして公開されており、Jenkins環境の管理者が利用できるWeb UIのManage Jenkins > Manage PluginsビューからPlugin Managerを使用して、任意のJenkinsサーバーにインストールすることが可能です。
クレデンシャル
レジストリパスワードやAPIトークンなどの機密データについては、Jenkins環境の管理者が利用できるManage Jenkins > Manage Credentialsビューを使用してクレデンシャルを作成することが推奨されます。
この例では、2つのクレデンシャルを使用します:
- sysdig-secure-api-token: Sysdig API トークンは、Sysdig API への問い合わせと、スキャン結果の送信に必要です。取得方法の詳細については、公式ドキュメントを参照してください。
- registry-credentials:コンテナレジストリにイメージをプッシュする際に使用するユーザ名とパスワード(またはアクセストークン)を格納します。
Jenkins上でイメージスキャンパイプラインをセットアップする
Jenkinsには、基本的な「フリースタイルプロジェクト」(UIで異なるステップを定義する)を使用したり、Jenkinsパイプラインを使用するなど、自動化を実現するいくつかの異なる方法があります。パイプラインは、Jenkinsfileファイルに格納されたgroovyコードとして実現されます。また、パイプラインの構文には「宣言型」と「スクリプト型」の2種類があり、UIに直接コード化するか、アプリケーションコードそのものと一緒にコードリポジトリに保存して簡単に利用することが可能です。
パイプラインはパラメータ化して必要に応じてより複雑にすることができますが、このブログ記事で使用しているワークフロー例(sysdiglabs/secure-inline-scan-examplesリポジトリに格納)は、Jenkinsパイプラインで実現できることの簡易版と言えます。
パイプラインを作成するには、「New Item」 -> 「Pipeline」ボタンを選択し、パイプラインの名前を入力します。そして、Jenkinsfileの内容を「Pipeline」のテキストボックスに貼り付けます。
では、パイプラインの定義を順を追って見ていきましょう。
pipeline { environment { image = "docker.io/edusysdig/myawesomeimage" + ":$BUILD_NUMBER" registryCredential = "registry-credentials" repository = 'https://github.com/sysdiglabs/secure-inline-scan-examples.git' SYSDIG_API_TOKEN_CRED = credentials('sysdig-secure-api-token') api_endpoint = 'https://eu1.app.sysdig.com' myimage = '' } agent any
これらの最初の行は、パイプラインの環境変数を定義するためのものです:
image
変数には、イメージのフルパス(レジストリ"docker.io/edusysdig/myawesomeimage"
を含む)とタグ(":$BUILD_NUMBER"
)を格納します。BUILD_NUMBER
変数(JenkinsのビルドIDを表す)は、異なる実行時に異なるイメージをビルドさせるためのトリックとして使用されます。registryCredential
変数は、先に作成したレジストリ認証情報を含む"registry-credentials"
クレデンシャルJenkinsオブジェクトを指しています。repository
は、コンテナイメージが格納されているURL('https://github.com/sysdiglabs/secure-inline-scan-examples.git'
)を格納します。SYSDIG_API_TOKEN_CRED
は、先に作成したsysdig-secure-api-token credential
の内容を格納しています。api_endpoint
は、地域に応じて適切な Sysdig 脆弱性スキャンエンドポイントを格納します。公式ドキュメントを参照してください。myimage
は、パイプラインの後半で使用される空の(現時点では)グローバル変数です。ここでは、すべてのステップに共通するように定義されています。
agent
セクションは、パイプライン(または特定のステージだけ)が実行される場所を指定します。
そして、パイプラインは単一または複数のステップを含むステージで定義されます:
stages { stage('Cloning Git') { steps { git branch: 'main', url: repository } }
最初のステージでは、git
function を使ってリポジトリの内容を取得します。ブランチとリポジトリの URL (repository
環境変数に格納) を指定します。
stage('Building image') { steps{ script { myimage = docker.build(image, "./jenkins/new-scan-engine/") } } }
第2段階では、Dockerパイプラインプラグインを活用してコンテナイメージをビルドします。docker.build
関数は、ビルドするコンテナイメージを指定するimage
引数と、Dockerビルド操作を実行するコンテキスト(この場合、Dockerfile
ファイルも含むレポの "./jenkins/new-scan-engine/"
フォルダー)を受け取ります。スキャンが正常に終了すると、myimage
の結果がコンテナレジストリにプッシュされます。
myimage
を活用しました。stage('Scanning Image') { steps { sysdigImageScan engineCredentialsId: 'sysdig-secure-api-token', imageName: "docker://" + image, engineURL: api_endpoint } }
ここまでが、Sysdig Secure Jenkinsプラグインの出番でした。見た目通り簡単です! 認証情報、イメージ、そしてオプションのSysdig SecureのURLを指定するだけです。それで完了です!
公式ドキュメントには、他にも指定できるパラメータがいくつかあり、例えば、スキャンで脆弱性が見つかった場合でもパイプラインを進行させる機能(bailOnFail
)などがあります。これらのパラメータは、「Manage Jenkins」 -> 「Configure System」セクションでプラグインを直接設定し、グローバルに指定することも可能です:
いよいよ最後のステップです:
stage('Deploy Image') { steps{ script { docker.withRegistry('', registryCredential) { myimage.push() myimage.push('latest') } } } } } }
最後のステージは、スキャンが正常に終了した後(終了した場合)、コンテナイメージをレジストリにプッシュするためのものです。docker.withRegistry
関数は、イメージをプッシュする先のレジストリ(この場合はデフォルトのdocker.ioレジストリを使用するため、内容は空です)と、コンテナレジストリへのイメージのプッシュに使用するクレデンシャルという2つの引数を受け取ることができます。
最後に、イメージは2回プッシュされます:1回目は指定した image:tag で、2回目は'latest'
タグで (ヒント: 実際のプッシュは1回だけで、2回目のプッシュはレポにタグを付けているだけです)。
Jenkinsでのイメージスキャン
すべての準備が整ったら、「Build Now」ボタンをクリックしてパイプラインを実行しましょう:
すべてがうまくいった場合、パイプラインは正常に終了し、すべてのステップが緑色で表示されます:
実行のたびに、Sysdig Secure Jenkinsプラグインは、実行の出力を記述するいくつかのJSONファイルを生成します:
また、”Sysdig Secure Report” セクションにサマリーが表示されます:
また、”Console Output” セクションでログを確認することもできます:
解析結果は、Sysdig Secureのアカウントにある「Vulnerability -> Pipeline」に反映されます:
成功!脆弱性は見つからず、レジストリにプッシュすることでイメージが公開されました。
このスキャン例では、デフォルトの「Sysdig Best Practices」ポリシーを使用しましたが(ログで確認できます)、チェックしたいポリシーを作成しカスタマイズすることができます。脆弱性ポリシーだけでなく、イメージのベストプラクティスを含むポリシーの作成とカスタマイズの方法については、公式ドキュメントを参照してください。
ポリシーが失敗したためにスキャンプロセスが成功しなかった場合、ここにあるように、ワークフローは停止し、イメージはレジストリにプッシュされません:
この例では脆弱性は発見されませんでしたが(やった!)、https://github.com/sysdiglabs/dummy-vuln-app のような別のアプリケーションを確認すると、そこではいくつかの脆弱性が見つかっています:
すでに修正が提供されているもの、および/または、攻撃手法が公開されているものをフィルタリングし、修正または更新が最も急がれるものに焦点を当てることができます:
脆弱性だけでなく、「ベストプラクティスではないもの」も確認することができます:
トリガーによる実行の自動化
リポジトリの変更ごとにパイプラインを自動的に実行する方法については説明しませんでした。これは、特定のニーズによって異なるアプローチがあるため、少し高度なトピックです。リポジトリをX分ごとにポーリングしたり、Webhooksを設定して変更が発生したときにJenkinsに通知されるようにしたりできます。次のスクリーンショットで詳細をご確認いただけます:
結論
ご覧の通り、JenkinsパイプラインはCI/CDを自動化するための強力なツールです。Sysdig Secure Inline Scanをワークフローに組み込むことは簡単で、イメージの脆弱性をスキャンし、ビルド時にベストプラクティスを実施し、レジストリ内の従来のイメージスキャンと比べていくつかの利点を提供することができます:
- CI/CDパイプラインにイメージスキャンを導入することは、脆弱性が発見された場合に、そのイメージが公開されるのを防止できることを意味します。
- 解析はランナー内でインライン(ローカル)で行われるため、構築された環境の外部など、イメージがどこかに送信されることはありません。解析の際、イメージからは実際のコンテンツではなく、メタデータ情報のみが抽出されます。
- 新たな脆弱性が発見されたり、ポリシーが変更されたりしても、アラートのためにイメージを新たにスキャンする必要はなく、解析で得られたメタデータを後で再評価することができます。ビルドを破棄したい場合は、ビルド内で新たなスキャンを起動させる必要があります。
- Sysdig Secureは、様々なコンテナのコンプライアンス基準(NIST 800-190やPCIなど)を実施・遵守するためのすぐに利用できるポリシーを提供します。
Sysdig Secureのイメージスキャンは、ほとんどのCI/CDパイプラインツールにシームレスに統合することができます。
まだSysdig Secureを利用していない場合は、今すぐデモをご依頼ください!