本記事では、Jenkinsを使って、ビルド > SBOM生成 > 脆弱性検知
を実行するパイプラインを構築するための環境を準備します。今回は自分のマシンにJenkinsサーバーを立てるのではなく、公式が用意しているコンテナイメージを活用して、Jenkins環境を構築していきます。
検証環境
- Ubuntu 22.04.3 LTS (WSL2)
コンポーネント | バージョン | 使用用途 |
---|---|---|
Docker | 24.0.5 | コンテナイメージのビルド, pull |
Jenkins | 2.414.3 | CIツール |
syft | v1.0.1 | SBOM生成ツール |
grype | v0.74.7 | 脆弱性検知ツール |
sbomdiff | v0.5.3 | sbom差分検知ツール |
jq | 1.6 | jsonファイル成形ツール |
環境構成
環境構成図について現在作成中です。
Jenkinsサーバ用コンテナイメージをビルドする
Jenkinsを構築用のコンテナイメージをビルドするための、Dockerfileを作成します。公式がすでにJenkinsサーバーを構築しているコンテナイメージを配布しています。そちらを活用していきます。
以下のDockerfileを使用して、Jenkinsサーバー用コンテナイメージをビルドします。
FROM jenkins/jenkins:2.414.3-jdk17
USER root
RUN curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh && rm get-docker.sh
RUN apt-get update && apt-get install -y --no-install-recommends\
wget \
tree \
jq \
&& rm -rf /var/lib/apt/list/* \
&& curl -kL https://bootstrap.pypa.io/get-pip.py | python \
&& pip install sbomdiff=0.53
ARG syft_version=1.0.1
ARG grype_version=0.74.7
RUN mkdir /tmp/syfttmp && \
mkdir /tmp/grypetmp && \
wget -P /tmp/syfttmp/ https://github.com/anchore/syft/releases/download/v${syft_version}/syft_${syft_version}_linux_amd64.tar.gz && \
wget -P /tmp/grypetmp/ https://github.com/anchore/grype/releases/download/v${grype_version}/grype_${grype_version}_linux_amd64.tar.gz && \
tar xvf /tmp/syfttmp/syft_${syft_version}_linux_amd64.tar.gz -C /tmp/syfttmp && \
tar xvf /tmp/grypetmp/grype_${grype_version}_linux_amd64.tar.gz -C /tmp/grypetmp && \
mv /tmp/syfttmp/syft /usr/local/bin/ && \
mv /tmp/grypetmp/grype /usr/local/bin/
USER jenkins
Dockerfileのあるディレクトリへ移動し、そこでdocker buildを行います。
docker build -t jenkins-test .
ここで、上記のDockerfile作成は、Jenkinsサーバーコンテナにインストールされていないソフトウェアをインストールすることが目的です。
コンテナを起動する
作成したコンテナイメージを使って、コンテナを起動させます。本記事ではコンテナの中でHostのDockerを利用するために、DooD(Docker outside of Docker)を実装しています。こちらの記事を参考にしました。
docker run -d \
--name jenkins-test \
-u $(id -u):$(id -g) \
--group-add $(awk -F: '$1 == "docker" {print $3}' /etc/group) \
--restart=on-failure \
-v $HOME/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 8081:8080 \
-p 50001:50000 \
jenkins-test
ここで、docker run`コマンドの各引数は以下を表します:
-
-d
: デタッチドモードで実行し、バックグラウンドでコンテナを起動させる -
--name jenkins-test
: コンテナにjenkins-testという名前を割り当てる -
-u $(id -u):$(id -g)
: コンテナを現在のユーザーIDとグループIDで実行する -
--group-add $(awk -F: '$1 == "docker" {print $3}' /etc/group)
: コンテナのプロセスにdockerグループを追加し、ホストのDockerデーモンと通信できるようにする -
--restart=on-failure
: コンテナが失敗した場合にのみ再起動する -
-v $HOME/jenkins_home:/var/jenkins_home
: ホストの$HOME/jenkins_home
ディレクトリをコンテナ内の/var/jenkins_home
ディレクトリにマウントする -
-v /var/run/docker.sock:/var/run/docker.sock
: ホストのDockerソケットをコンテナ内にマウントし、コンテナ内からホストのDockerデーモンを制御できるようにする -
-p 8081:8080
: ホストの8081ポートをコンテナの8080ポートにマッピングする -
-p 50001:50000
: ホストの50001ポートをコンテナの50000ポートにマッピングする -
jenkins-test
: 先ほどビルドしたコンテナイメージを指定する
docker logs -f 8ae5248661c61f49204ef3938f3761d3de9c04a02ea7dbcd4f3441f3f6551b55
初期パスワードを入手する
次にJenkinsの初期パスワードを入手します。
Jenkinsの初期パスワードは/var/jenkins_home/secrets/initialAdminPassword
というファイルに記載されています。
この情報を取得するために、以下のコマンドを実行します。
docker exec ${CONTAINER_ID or CONTAINER_NAME} cat /var/jenkins_home/secrets/initialAdminPassword
出力結果がJenkinsにログインするための初期パスワードです。パスワードをコピーしておきます。
Jenkinsにログインする
コンテナの起動とパスワードのチェックが終わったら、
http://localhost:8081/
へアクセスします。
すると、以下のような画面がでるので、先ほどコピーした初期パスワードを[Administaratorpassword]
へ貼り付け、[Continue]
をクリックします。
次に、[ユーザー名]
と[パスワード]
を変更することができます。ここで、このプロセスは[]
をクリックすることでスキップすることが可能です。
そして、JenkinsのURLを自由に決めることができます。今回はhttp://localhost:8081/
のままにしておきます。[Save and Finish]
をクリックすると、Jenkinsがスタートします。
Testしてみる
ここでは、Hello Jenkins
と出力するだけのとても簡単なジョブを作成してみます。
まず、Jenkinsのホームから、[新規ジョブ作成]
をクリックします。
すると、新規ジョブの設定画面が現れます。[ジョブ名]
を決め、[フリースタイルプロジェクトのビルド]
を選択し、[保存]
をクリックします。
ジョブの設定が開始されます。今回は、シェルコマンドを実行するだけなので、[Build Steps] > [ビルド手順の追加] > [シェルの実行]
を選択します。
シェルを記述するためのブロックが作成されるので、ブロック内にシェルコマンドを記述します。今回書いたスクリプトは、
echo "Hello Jenkins"
です。そして、[保存]
をクリックすれば、ジョブHello_Test
が作成されます。ジョブ作成後、[ビルド実行]
をクリックすると、ジョブが実行されます。その結果はビルド履歴
に記載されます。
#1
はジョブHello_Test
におけるジョブの実行回数を表す番号です。#1 > [コンソール出力]
をクリックするとジョブの実行結果を確認することができます。
GitHubとJenkinsを連携する
Jenkinsのセットアップ後、GitHubとJenkinsを連携します。Githubのリポジトリ内のディレクトリに対し、fetchを行うためです。fetch後、Jenkinsを使い、ビルド、SBOM生成、脆弱性検知を連続的に行うことが目的です。
Jenkins側の設定
[ダッシュボード] > [開発者]
を選択し、自分が使っているユーザー名をクリックします。
[ダッシュボード] > [ユーザー名] > [設定]
へ進んでください。そして、[APIトークン] > [現在のトークン]
に行きます。トークン新規追加
をクリックし、トークン名を入力、生成
をクリックします。すると以下のようにトークンが生成されるので、トークンのパスワードをコピーしておきます。最後に、保存を押せば設定完了です。
Github側の設定
まず、privateリポジトリを作成します。作成したリポジトリの[Settings] > [Webhooks]
を選択します。
すると、Webhookの設定ができます。Webhookの設定では、Payload URL
へ以下のURLを設定します。
http://[Jenkinsのユーザー名]:[JenkinsのAPIトークン]@[サーバのIPアドレス:ポート]/job/[Jenkinsのジョブ名]/buildWithParameters?token=[JenkinsのAPIトークンの名前]
ここで、サーバーのIPアドレスは次のコマンド
hostname -I
で検索してください。一番左にあるIPアドレスを設定に使えば大丈夫だと思います。ポート番号はコンテナを起動させるときに使用した。8081ポートを設定します。
それぞれ
- Jenkinsのユーザー名
- JenkinsのAPIトークン
- サーバのIPアドレス:ポート
を表しています。
サーバーのIPアドレスはhostname -Iで検索してください
一番左にあるIPアドレスを設定に使えば大丈夫だと思います。
例として、以下のような設定の場合は、
- Jenkinsのユーザー名 : admin
- JenkinsのAPIトークン : 1234567
- サーバのIPアドレス:ポート : 172.00.00.00:8081
- Jenkinsのジョブ名 : test_job
- JenkinsのAPIトークンの名前 : github
Payload URLは
http://admin:1234567@172.00.00.00:8081/job/test_job/buildWithParameters?token=github
Jenkinsジョブの設定
[ソースコード管理] > [Git]
へ行き、先ほど作成したリポジトリのURLとGithubのユーザー名とパスワードを設定します。Githubのユーザー名とトークンを認証情報として渡すために、追加
をクリックし、Jenkins
を選択します。
その後、以下のような画面が開くので、Githubで使用しているユーザー名
とGithubの認証のために作成したトークン
を設定します。
最後にジョブの設定を保存しビルドを実行してみて、成功していれば、連携は成功です。
お疲れ様でした。初期設定は大変だったと思いますが、次回から、SBOM生成、脆弱性検知を行うパイプラインを実装していきます。
参考文献
Jenkinsについて
- Jenkins公式ドキュメント
- 公式が用意しているコンテナイメージ
- DooD(Docker outside of Docker)環境Jenkinsにおけるjenkins_homeと/var/run/docker.sockのパーミッション