概要
Circle CIの「circleci/docker」というOrbを使って、以下を実践してみました!ʕ◔ϖ◔ʔ
- コンテナのビルド
-
DockleとTrivyを使って、ビルドしたコンテナイメージをチェック
- OSや依存パッケージが脆弱性を含んでいないかをチェック
- ベストプラクティスに準拠したセキュアなコンテナになっているかをチェック
- 上記チェック結果が
Pass
なら、docker hub
にコンテナイメージを登録
上述のサンプルを紹介しつつ、設定ファイル.circleci/config.yml
を書く際のポイントなどを説明します。この記事を読み終わった時に、あなたにとってセキュアなコンテナのビルドがより身近なものになっていたら嬉しいなぁと思います!
ゆっくり見ていってね!(o´・з・)o
読んでほしい人
-
Dockle
やTrivy
といったコンテナチェックツールに興味がある方 - CIでのコンテナチェックに興味がある方
- CircleCIのOrbという仕組みに興味がある方
- CircleCIを含むCI/CDに知見がある方(マサカリ、お願いします!m(_ _)m)
etc..
作ったもの
まずは、実践した内容の雰囲気を掴んでいただくため、実際に作ったサンプルをごらんください。٩(ˊᗜˋ*)و
Dockle on CircleCI
- GitHubリポジトリ
- CircleCIでのビルド結果
- Docker Hubに登録したコンテナイメージ
Trivy on CircleCI
- GitHubリポジトリ
- CircleCIビルド結果
- try-trivy - Pipelines
- - CircleCIのジョブでTrivyを実行したサンプル画像です。脆弱性無いよ!
- Docker Hubに登録したコンテナイメージ
準備
ログイン
まずはCircleCI
やdocker hub
にログインできるようにしましょう。
リントツールを使って手元でチェック
ケモケモ「よっしゃ出来た!CircleCIさん、がっつりビルド頼むわ!!」
CircleCI「記法がinvalidやで。Failやで。」
ケモケモ「Oh... (´・ω・`)」
せっかく書いた.circleci/config.yml
が、記法の間違いなどビルドできないと辛いですね。そういった問題を未然に防ぐため、コミットする前にcircleci
ツールでチェックしちゃいましょうヽ(=´▽`=)ノ。
まずはインストール!
以下のコマンドで.circleci/config.yml
が動きそうかチェックします。
circleci config validate
詳しくは「CircleCI のコンフィグのバリデーション」をご覧ください。
Dockle
をインストール
CIで継続的に実行するのが本記事の目的ではありますが、便利なツールですし手元でコミット前にチェックするのは良い習慣ですのでインストールしましょう。
公式の Installation で各種プラットフォーム向けのインストール方法が書かれているので、好きな方法でインストールします。
使い方も簡単で、チェックしたいコンテナイメージの名前を指定して実行するだけです。めちゃシンプル!
$ dockle {YOUR_IMAGE_NAME}
チェックしてくれるポイントは Checkpoint Summary にまとまってます。
Trivy
をインストール
こちらもやはり手元で実行できるようにインストールしましょう。先のDockle
同様にGo言語製のツールですので、非常に多くのプラットフォームで実行可能です。
公式の Installation を見ながらインストールします。
簡単に使えます。シンプルです。
$ trivy {YOUR_IMAGE_NAME}
実行結果のサンプルが Examples に多数掲載されているのでチェキです。
Orb
選び
この記事のサブテーマとしてCircle CIのOrbを積極的に使います。まずは、目的にあったOrbを CircleCI Orb Registry で探してみましょう。
今回はコンテナのビルドとプッシュをしたいのでdocker
で検索してみました(上図)。CERTIFIED
マークのcircleci/docker
を使ってみましょう。
Orb: circleci/docker
https://circleci.com/orbs/registry/orb/circleci/docker
Orbの説明ページでは、Orbの機能を呼び出すための方法について以下の情報が記載されています。
- 冒頭のクイックスタートガイドで、
.circleci/config.yml
にどう書けば使い始められるか説明してる - 左のカラムに並ぶ
Usage Examples
で、需要が高そうな使い方に対してjobやworkflowの書き方を実例と共に説明してる - 左のカラムに並ぶ
Jobs
で、job名やパラメータの指定方法を説明してる - 左のカラムに並ぶ
Commands
で、command名やパラメータの指定方法を説明してる
クイックスタートガイド
以下を書くだけでOrbの力を使えるようになります。パネェ₍₍ (ง ˙ω˙)ว ⁾⁾
version: 2.1
orbs:
docker: circleci/docker@0.5.20
Usage Examples
比較的シンプルな、以下のサンプルが参考になります。
-
standard-build-and-push
- Orbの定義済みのjobである
publish
を使ったサンプル。 - コンテナのbuildとpushをまとめて実施してくれる。便利。
- Orbの定義済みのjobである
-
build-push-digest
- Orbの定義済みのcommandである
check
やbuild
を使ったサンプル。 -
docker.hub
へのログインチェックや、build、pushなど、順を追って実施したい時に参考になる。
- Orbの定義済みのcommandである
今回は、上記build-push-digest
をベースに作っていきます。
Executor
Orbの実態は、CI/CDにすぐ組み込んで便利に使えるようCircleCIやパートナー企業が作ってくれたカスタムコンテナイメージです。
では、このcircleci/docker
のベースイメージはどんなものなのでしょう?今回のサンプルで使う「Executor - docker」でSourceを確認することでわかります。
「 circleci/python 」を使っているようです。このイメージを作るDockerfile
は「 CircleCI-Public / circleci-dockerfiles 」にあります。追加で依存パッケージなどを使いたい場合、コンテナの素性が関係してくる場合があるので心の片隅に置いておきます。
書き始めよう
かなり入念に、CircleCIの設定を書くための準備とOrbの機能を確認しました。そろそろ実際にconfig.yml
を書き始めましょう。
まずはOrb
だけで書いてみる
まずはOrb
の機能だけでCIの骨子を組み立てましょう。Orb
の各種機能を呼び出す方法を整理すると、以下のような感じです。
-
executor
: {Orb名}/{OrbのExecutor名}- ex)
docker/docker
- circleci/dockerのExecutors
- ex)
-
command
: {Orb名}/{OrbのCommand名}- ex)
docker/build
- circleci/dockerのCommands
- ex)
-
job
: {Orb名}/{OrbのJob名}- ex)
docker/publish
- circleci/dockerのJobs
- ex)
上述のサンプルなどをベースにザクッと書いてみたのが以下です。
version: 2.1
orbs:
docker: circleci/docker@0.5.20
jobs:
# ビルドしたりテストしたりするジョブ。
build-and-test:
executor: docker/docker
steps:
- setup_remote_docker
- checkout
# コンテナレジストリにログイン可能かチェックします。
- docker/check
# コンテナをビルドします。
- docker/build:
image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
# ! DockleとTrivyを使ったコンテナのtestを書く予定地です。
workflows:
# ビルドしたりテストしたり、masterにマージされたらlatestコンテナを更新するワークフロー。
build-and-deploy:
jobs:
# masterを含む全てのブランチで実行するジョブ。
- build-and-test
# masterでだけ実行されるジョブ。latestのコンテナイメージをレジストリに登録、更新する。
- docker/publish:
image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
tag: 'latest'
requires:
- build-and-test
filters:
branches:
only: master
# gitのタグがついたらビルドとテストをして、タグ付きのコンテナをレジストリに登録するワークフロー。
deploy-tags:
jobs:
- build-and-test:
filters:
branches:
ignore: /.*/
tags:
only: /^v.*/
- docker/publish:
image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
tag: ${CIRCLE_TAG}
# 「build-and-test」のジョブが成功した時だけ、このジョブを実行するよ。
requires:
- build-and-test
filters:
branches:
ignore: /.*/
tags:
only: /^v.*/
なお、commandのdocker/check
は、イメージをpushするコンテナレジストリ(標準でdocker hub)にログイン可能かをチェックしてくれます。ログイン情報は、あらかじめ環境変数としてCircle CIに登録しておきます。ジョブの実行結果のログでは、ちゃんと伏せ字になりますので安心です。詳しくは プロジェクト内で環境変数を設定する を参照してください。
Dockle
とTrivy
をCIに組み込む
実はDockle
もTrivy
も、どちらも公式でCircleCIの実行サンプルを公開しています。
これらのサンプルを上述のOrbベースのCI設定に組み込みます。その際、ツールのインストールを行う箇所がそのままでは使えません。circleci/docker
のOrbとは、executor
として使っているコンテナイメージのOSが異なるためです。それらの違いも踏まえて実際に動作することを確認した設定内容が以下です。
version: 2.1
orbs:
docker: circleci/docker@0.5.20
jobs:
build-and-test:
executor: docker/docker
steps:
- setup_remote_docker
- checkout
- docker/check
- docker/build:
image: ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
# (追加)Dockleをインストールしてスキャン実行!
- run:
name: Install dockle
command: |
VERSION=$(
curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/'
)
wget https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz
tar zxvf dockle_${VERSION}_Linux-64bit.tar.gz
sudo mv dockle /usr/local/bin
- run:
name: Scan the image with dockle
command: dockle --exit-code 1 ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_SHA1}
# (追加)Trivyをインストールしてスキャン実行!
- run:
name: Install trivy
command: |
VERSION=$(
curl --silent "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/'
)
wget https://github.com/aquasecurity/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
sudo mv trivy /usr/local/bin
- run:
name: Scan the image with trivy
command: trivy --exit-code 0 --no-progress ${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_SHA1}
workflows:
build-and-deploy:
jobs:
- build-and-test
(後略)
実際に動かしてみるとこんな感じになります。
良いですね、バッチリチェックできています。
Dockle
とTrivy
両方を使ったconfig.yml
の完成形は こちら を御覧ください。
まとめ
CIを使ったコンテナの作成とレジストリへの登録は、Kubernetesクラスタへのデプロイを想定したGitOpsなどで必須となる重要なポイントだと感じています。これらの技術をProduction環境へ適用することを考えるならば、使用するコンテナ自体の脆弱性チェックはもはや避けては通れない課題です。
今回は、極力余計なものは省いて「いかに楽して脆弱性チェックの機構をCIに取り込むか」という点を意識して実践したつもりです。本記事はCircle CIを使った例でしたが、Dockle
とTrivy
の公式ドキュメントにもあるように Travis CI など多数のCI環境で同様の「コンテナ脆弱性チェック」の仕組みを実現することが可能です。
この記事が、コンテナのセキュリティを意識し始めた私のような方にとって、少しでも役立つものになっていることを願っていますʕ◔ϖ◔ʔ
おまけ
Circle CI関連の資料ばかりなのですが、有益だなぁと思ったリンクを載っけときます(ΦωΦ)