皆様こんにちは。SEの小池と申します。
前回GitLabのコンテナレジストリにイメージを登録する話を記載したので、今回はそれに関連してGitLabのAuto DevOpsの1つであるコンテナスキャンを実装します。
なお、前回のブログの内容と重複する部分がございます。
前回のブログの続きでご覧いただいている方は、適宜読み飛ばしていただければと存じます。
本記事の対象の方
- GitLabのAuto DevOpsでコンテナスキャンを使ってみたい方。
今回のブログのゴール
このブログのゴールはこちらです。
- GitLabのAuto DevOpsを使ってコンテナスキャンを実装する。
このブログをお読みいただくにあたっての事前ご連絡事項
- 本記事はオンプレミス版 (Self-Managed) のGitLab Enterprise Edition 14.10.4-ee (Ultimate) における仕様をベースに記載しております。それ以外のエディションやバージョンではこの記事に記載の通りではない可能性がございます。
- 本記事ではGitLabのAuto DevOps 及び そのコンテナスキャンがどういったものなのかの説明は記載しておりません。これについては恐れ入りますがGitLab Docs (こちら) をご参照ください。
- 本記事のGitLabのGUIは日本語にローカライズした状態で掲載しております。それ以外の言語をご利用の方は適宜読み替えてください。
事前準備
GitLabの Auto DevOps でコンテナスキャンを使うにあたっては以下いずれかのRunnnerが必要になります。
- エクゼキューターが
docker
のRunner - エクゼキューターが
kubernetes
のRunner - エクゼキューターが
shell
且つ Docker Engine がインストール済のRunner
お手元のGitLab環境にこれを満たすRunnerがない場合は、GitLab Docsや弊社の過去のブログをご参照いただき、事前にご準備をお願い致します。
Runnerのインストールに関するGitLab Docs : Install GitLab Runner | GitLab
弊社の技術ブログ : GitとCI/CDに関する知識ゼロのSEが、GitLabでRunner (Docker) を登録するだけの話
また、今回ご紹介する手順はGitLabのコンテナレジストリを有効にする必要があります。
オンプレミス版 (Self-Managed) の場合に限りデフォルトでは有効になっていない場合があります。
その場合はGitLab Docs もしくは 弊社の技術ブログをご参照いただき、コンテナレジストリを有効にしてください。
コンテナレジストリに関するGitLab Docs : GitLab Container Registry | GitLab
弊社の技術ブログ : GitとCI/CDに関する知識ゼロのSEが、GitLabでCI/CDパイプラインを使ってコンテナレジストリにイメージを登録する話
コンテナスキャンの実装
Step1 : CI/CDパイプラインを使って任意のイメージをビルドする
まずはスキャン対象となるイメージを、CI/CDパイプラインを使ってビルドする処理を作成します。
このブログでは例として簡易なイメージをビルドしてみます。
既にお手元のGitLabで、スキャンしたいイメージをCI/CDパイプラインでビルドしていらっしゃる場合は、イメージ名とタグの設定だけこの章の設定値に変更してください。
(Auto DevOpsのコンテナスキャンではデフォルトだとスキャン対象のイメージ名とタグが変数を利用した固定値です。カスタムのイメージ名とタグを使用すると、このブログに書いた手順だとスキャンが失敗してしまいます。)
まず、今回の検証のために空のプロジェクト (Blank Project) を作成します。
空のプロジェクト (Blank Project) の作成方法についてはこちらのブログをご参照ください。
作成した空のプロジェクト (Blank Project) のmainのリポジトリのルートに以下2つのファイルを作成します。
- Dockerfile
- .gitlab-ci.yml
Dockerfile
の内容はご自由に設定なさってください。
以下に (超シンプルな) サンプルを載せますので、こちらをコピーしていただいても大丈夫です。
FROM ubuntu:18.04 RUN apt-get install
.gitlab-ci.yml
の内容のサンプルは以下の通りです。
そのままコピーしていただいても、アレンジしていただいても、どちらでも大丈夫です。
ただし、アレンジなさる場合でも、ビルド時のイメージ名とタグの設定は以下のサンプルの設定値を用いてください。
stages: - build Build-SmapleJob: stage: build image: docker:20.10.17 services: - docker:20.10.17-dind variables: # ビルドイメージの変数作成 IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA script: # ビルド - docker build --tag $IMAGE .
変更をコミットし、mainブランチにDockerfile
と.gitlab-ci.yml
をマージしてください。
なおこの際、マージリクエストの作成は任意です。
この時点でパイプラインが成功しているかどうかを確認します。
対象プロジェクトで [CI/CD] > [パイプライン] を開きます。
最新のパイプラインのステータスが緑色で [成功] と表示されていることを確認します。
以上がスキャン対象となるイメージのビルド処理の作成でした。
Step2 : ビルドしたイメージをAuto DevOpsを使ってスキャンする
前の章では、CI/CDパイプラインでイメージをビルドする処理を作成しました。
この章では、そのイメージに対してGitLabのAuto DevOpsを使ってコンテナスキャンを実行します。
リポジトリに追加した.gitlab-ci.yml
ファイルを使って、コンテナスキャンを有効にします。
既存の.gitlab-ci.yml
に、testステージを追加します。
(以下のサンプルの場合は3行目を追加しています。)
stages: - build - test Build-SmapleJob: stage: build image: docker:20.10.17 services: - docker:20.10.17-dind variables: # ビルドイメージの変数作成 IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA script: # ビルド - docker build --tag $IMAGE .
次に同じく.gitlab-ci.yml
に対して、キーワードinclude
を使ってコンテナスキャンのテンプレートを指定します。
(以下のサンプルの場合は最後の2行を追加しています。)
stages: - build - test Build-SmapleJob: stage: build image: docker:20.10.17 services: - docker:20.10.17-dind variables: # ビルドイメージの変数作成 IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA script: # ビルド - docker build --tag $IMAGE . include: - template: Security/Container-Scanning.gitlab-ci.yml
変更をコミットし、mainブランチに.gitlab-ci.yml
をマージしてください。
なおこの際、マージリクエストの作成は任意です。
実はコミットの時点でスキャンは実行されています。
対象プロジェクトで [CI/CD] > [パイプライン] を開きます。
最新のパイプラインのステータスが緑色で [成功] となっていることを確認しつつ、その [成功] ボタンをクリックします。
Build
とTest
の2つのステージがあります。
Test
ステージにあるcontainer_scanning
ジョブが正常終了していること (緑色のチェックマークが表示されていること) を確認します 。
同ページの [セキュリティ] タブが存在することを確認します。
container_scanning
ジョブ名をクリックし、ログをご確認ください。
以上がビルドしたイメージをAuto DevOpsを使ってスキャンする手順でした。
コンテナスキャンの結果確認
コンテナスキャンの結果はいくつかのメニューから確認することができます。
CI/CDパイプラインの結果から
CI/CDパイプラインの結果から簡単にコンテナスキャンの結果を確認することができます。
まず、CI/CDパイプラインの結果一覧において、コンテナスキャンを実行したパイプラインの行の右側の点が3つ連なっているボタンから、スキャン結果のアーティファクトをjson形式でダウンロードすることができます。
また、スキャンのジョブが実行されたCI/CDパイプラインの詳細画面から [セキュリティ] タブを開くことでも確認ができます。
他にも、実際のスキャンジョブのログから検知結果を確認することができます。
CI/CDパイプラインの詳細画面でcontainer_scanning
ジョブをクリックすると、下図のようにジョブのログが確認できます。この中にコンテナスキャンのログも載っています。
脆弱性レポートから
対象のプロジェクトの [セキュリティとコンプライアンス] > [Vulnerability report] から、今回のスキャン結果を確認することができます。
この画面では、今回のコンテナスキャン (及び 依存関係のスキャン) の結果だけでなく、SASTやDASTなど他のAuto DevOpsを用いて検出した脆弱性を一括で閲覧することができます。
コンテナスキャンの結果だけを表示したい場合は、下図の通り [Tool] > [コンテナ―スキャン] を選択します。
他、この画面では検知した脆弱性のステータスを変更することができます。
マージリクエスト画面から
マージリクエストを作成している場合は、その画面の履歴からも確認できます。
下図のように、マージリクエストの履歴内にスキャン結果が自動で表示され、[展開] をクリックするとその画面上で一覧を確認することができます。
また、マージリクエストの画面からコンテナスキャン結果のアーティファクトをjson形式でダウンロードできます。
【余談】筆者のトライアンドエラー
ブログを書くにあたり筆者が遭遇したエラーの回避策について記載致します。
同じエラーが出た際の参考になれば幸いです。
変数CI_REGISTRY_IMAGE
が参照できないよエラー
GitLabのコンテナレジストリが無効のまま、CI/CDパイプラインでコンテナスキャンを実行しようとして出たエラーです。
[ERROR] [2022-07-21 01:34:03 +0000] [] ▶ Environment variable `CI_REGISTRY_IMAGE` was not found and is required for execution
Auto DevOpsのコンテナスキャンは、デフォルトではスキャン対象のイメージを変数CI_REGISTRY_IMAGE
を使って特定しているのですが、コンテナレジストリを有効にしないとそもそもこの変数自体が使えない仕様なので出たエラーです。
コンテナレジストリを有効にするとこのエラーは解消されました。
Dockerのソケットファイルにアクセスできないよエラー
このエラーはコンテナスキャンを実装したCI/CDパイプラインをコンテナで起動しているRunnerで実行した際に出たエラーです。
[ERROR] [2022-07-20 08:51:33 +0000] [] ▶ 2022-07-20T08:51:33.989Z FATAL scan error: unable to initialize a scanner: unable to initialize a docker scanner: <エラー件数> errors occurred: unable to inspect the image (<コンテナレジストリURL>:<ポート番号>/<GroupとPJのID>/<ブランチ名>:<変数で指定された40文字>): Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Runnerでdocker
コマンドを使うにあたり、いくつかの方法があります。
参考 : Use Docker to build Docker images | GitLab Docs
当方の検証環境は上記の参考サイトのうち、Runner (エクゼキューターdocker
) をコンテナで起動させて、ソケットファイルをバインドする方法を設定・・・しているつもりだったのですが、実はソケットファイルのバインドを忘れていたために発生したエラーです。
そのため、Runnerの設定ファイルconfig.toml
のvolumes
に以下を追記したところ、解消致しました。
volumes = ["/var/run/docker.sock:/var/run/docker.sock"]
以下に設定例の画面を載せますのでご参考までに。
Dockerのソケットファイルのパーミッションが足りないよエラー
このエラーは、先述したエラーの対応後にCI/CDパイプラインを試行した際に出たエラーです。
[ERROR] [2022-07-20 08:13:15 +0000] [] ▶ 2022-07-20T08:13:15.363Z FATAL scan error: unable to initialize a scanner: unable to initialize a docker scanner: <エラー個数> errors occurred: unable to inspect the image (<コンテナレジストリURL>:<ポート番号>/<GroupとPJのID>/<ブランチ名>:<変数で指定された40文字>): Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/<コンテナレジストリURL>:<ポート番号>/<GroupとPJのID>/<ブランチ名>:<変数で指定された40文字>/json": dial unix /var/run/docker.sock: connect: permission denied
当方の検証環境はRunner (エクゼキューターdocker
) をコンテナで起動させていて、CI/CDのジョブでdocker
コマンドを実行するためにDockerホストのソケットファイルをバインドする方法 (Docker in Dockerじゃない方法) を使っているのですが、どうもこのケースでコンテナスキャンのアナライザーを使おうとすると出るエラーっぽいです。。。
一応回避策として、以下いずれかが挙げられる模様です。
- ユーザー
gitlab-runner
をグループdocker
に入れる。 /var/run/docker.sock
のパーミッションを666に変更する。
ただ、上記の回避策のうち、当方の環境では1つ目では回避できなかったので、2つ目の方法で回避致しました。
最後に
この度はGitもCI/CDもよくわかっていないど素人SEによるGitLab検証ブログをお読みいただき、誠にありがとうございます。
このブログの目標は以下のとおりでしたが、皆さまはいかがでしたでしょうか。
- GitLabのAuto DevOpsを使ってコンテナスキャンを実装する。
以前Auto DevOpsを使ったSASTの実装方法を記載致しましたが、今回のコンテナスキャンも実装がとても容易です。
また、マージリクエストにおいてコミットと同時にCI/CDパイプラインでコンテナスキャンを実行することで、ターゲットブランチにマージする前に脆弱性の有無を確認することができます。
もしCI/CDパイプラインでイメージをビルドする処理を入れていらっしゃる方は、Auto DevOpsのコンテナスキャンもお試しいただければと存じます。
GitLabに関するお問い合わせは、以下のフォームからお願い致します。
GitLab製品 お問い合わせ
GitLab操作デモ動画 (基本編) を作ってみました。(音声の録音は自宅でiPhoneのボイスメモ使うという超低クオリティですが…。)
つたない内容ではありますが、ご興味がおありでしたら是非ご視聴いただければと存じます。
www.youtube.com