JFrog Japan Blog

DevOpsを加速する、JFrog日本法人メンバーによるブログです。

JFrog ArtifactoryやXrayといった自社ツールはもちろん、CI/CDやコンテナ技術(DockerやKubernetes)などDevOpsの一般的な内容も扱います。その他、日本でのDevOps事例紹介やお楽しみコンテンツも掲載予定です。 JFrogならではの面白くて役に立つブログを目指しますので、お楽しみに!

アーティファクトを管理する、ということ

こんにちは!JFrog Developer AdvocateのよしQ(よしきゅー)です。

前回のブログでは「JFrog Xrayを利用したオープンソースソフトウェア(OSS)脆弱性スキャン」と題して、OSS脆弱性がスキャンする姿をお見せしつつ、システムの現場でどのようなメリットがあるかについて挙げました。

ただ、私は気になっています。

  • 「それってソースコードでもやってくれるサービスってあるよね?」
  • 「なんでビルドした後にできるアーティファクトでチェックすんの?」

こんなことを思った方もいるのではないでしょうか。

今回のブログでは、なぜアーティファクトを対象にすべきなのか、アーティファクト管理がなぜ重要なのかについてお伝えしたいと思います。

「アーティファクト」とは?

この記事の中には、「アーティファクト」というキーワードが非常に多く登場します。
よくわからん!という方は、以下の記事を先にご確認ください。(弊社 よこなが非常にわかりやすくまとめています!) blog.jfrog.co.jp

これをもとに、この記事では以下のようなものとして扱います。

  • アーティファクトとは、「ソースコードをビルドした結果得られるバイナリファイル」を指します。
  • アーティファクトは、その特徴を示す情報*1として「メタデータ」を持っている。

アーティファクトを「なぜ」管理するべきなのか

ここからが本題です。なぜアーティファクトを管理するべきなのか。
それを語るために、アーティファクトがどういった特徴をもっているのかを考えながら、整理してみたいと思います。

*1:ビルドした人の名前、ビルドしたサービスの名前、リリースバージョン、ビルド実行時刻、ビルド実行環境等

続きを読む

JFrog Xrayを利用したオープンソースソフトウェア(OSS)脆弱性スキャン

はじめまして!2022年6月にDeveloper AdvocateとしてJFrogに入社しました、佐藤です。
「よしQ(よしきゅー)」として覚えていただければうれしいです。

日本ではまだまだ進んでいないと感じるDevOpsに関する発信を通して、
日本のエンジニアの皆さんが今よりもハッピーになれるような環境ができればいいなと思っています。
DevOpsを支えるJFrogのプロダクト共々、どうぞよろしくお願いします!

JFrog Xrayの脆弱性スキャン

このブログでは、「JFrog Xray」の機能である脆弱性スキャンを取り上げます。
JFrog Xrayの脆弱性スキャンは、簡単にいうと、

  • JFrog Artifactoryに保存されたアーティファクト(バイナリファイル)から
  • それに含まれるオープンソースソフトウェア(OSS)の脆弱性の有無
  • 一般に広く公開されている脆弱性情報(+JFrog独自の情報)に基づいて解析・診断をし
  • 検知結果を表示してくれる

といったものです。

また、JFrogの製品はユニバーサル性を意識しており、Xrayもさまざまな言語・パッケージマネージャに対応しています。
ユニバーサル性を含めたXrayの詳細は以下をご覧ください。 www.jfrog.com

この脆弱性スキャンの機能はJFrog Platform の無料版を用いて誰でも利用できます。
本記事では無料クラウド版を用いて、実際にどのように行われるのかをご覧いただきたいと思います。

サンプルコードを使ったシナリオ

2021年末、Java開発でよく用いられるOSSのロギングライブラリ「Apache Log4j」の脆弱性は非常に話題になりました。
現在はすでに脆弱性に対応されたものが配布されていますが、当時Java開発に関わられていた方の中にはこの対応に追われた方もいるのではないでしょうか。

この脆弱性に関して、今回の以下のシナリオでXrayを使ってみました。

  • Apache Log4j の脆弱性が含むライブラリ(2.14.1)を用いた状態で脆弱性を確認する
  • Apache Log4j の脆弱性対応が済んだ最新のライブラリを用いた状態で脆弱性を確認する

環境は以下の通りです。

  • Java 17.0.3
  • Maven 3.8.5
  • Spring Boot 2.7.0
  • JFrog CLI 2.18.2

JFrog CLIは、JFrog ArtifactoryやJFrog XrayといったJFrog製品に対して、
コマンドライン(jfコマンド)を用いて操作する際に使います。
インストール方法は以下を参照ください。 (お使いの環境に合わせた方法で、簡単に導入いただけます。) www.jfrog.com

なお、サンプルコードとして、以下を用いています。 github.com

実際にJFrog Xrayで脆弱性スキャンを行う

スキャンを行う前に

ローカル環境にサンプルコードをダウンロードし、 ArtifactoryとXray の設定をもろもろ行います。
Xrayを使うためには、ビルドで生成されたアーティファクト(この場合はJarファイル)をArtifactoryに登録する必要があり、
Xrayのスキャンにも、スキャンの対象や通知の対象とする「脆弱性のレベル」の設定があったりします。

詳細な設定方法は別のブログで紹介したいと思いますが、
ここでは 「脆弱性のレベルがMedium以上」 を表示するよう設定し、結果を確認します。

Xray設定(Policy設定)

脆弱性を含む場合

以下のコマンドを実行し、Artifactoryにアーティファクトを登録します。

# 1. targetディレクトリを削除
jf mvn clean

# 2. jarの生成&Artifactoryへ登録
jf mvn package --build-name=xraytest-build --build-number=sample1-001

# 3. Artifactoryに登録するbuild info(アーティファクトの詳細や依存関係、環境変数などの情報)を収集する
jf rt bce xraytest-build sample1-001 

# 4. Artifactoryにbuild infoを登録
jf rt bp xraytest-build sample1-001

上記の1.、2.はjfコマンドを使っているものの、その後に続くmvn cleanmvn packageは、
Mavenを利用している人には馴染みのあるコマンドが続いているかと思います。
(Mavenに関しては、普段使っているものをコマンドの形式で利用できるものが多くあります。)
特に2.ではbuild-namebuild-numberとオプションが続いていますが、
どのタイミングでのビルドかを記録しておくことができます。
この場合は、Xrayを行う対象をあらかじめ設定したビルドの名称(xraytest-build)をbuild-nameとして設定し、
ビルドタイミングの識別子としてbuild-numberを使っています。

3., 4.はArtifactoryに関するコマンドで、3. では、ビルドした際の環境の状況を収集し、4. でその情報をArtifactoryに送付します。
スキャンは4.が行われて後に実行されます。

スキャンが完了後、Build情報で以下のようにXrayのスキャン結果が確認できます。

脆弱性を含む場合のXray結果

"Violations"タブにルールに基づいて検知された脆弱性が一覧されます。
公開されている脆弱性のID(「CVE」から始まるコード)、脆弱性のレベルなどが表示されていることがわかります。
1〜4行目は今回意図した Apache Log4j の脆弱性が表示されており、IDをクリックするとその詳細を確認することができます。

脆弱性の詳細の確認

例えば、詳細に表示されている"Fix version"は、この脆弱性に対する対応が行われているバージョンが示されており、
脆弱性に対する参考情報も得ることができます。

脆弱性対応済みの場合

以下のように、pom.xml内で Log4j のバージョンをしているしている箇所をコメントアウトし、
最新の脆弱性対応が完了されているものを利用するよう変更します。

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <!-- <version>2.14.1</version> -->
</dependency>

その後、再度ビルドします。(build-numberは前回のビルドと異なることを示すsample1-002に変更しています。)

# 1. targetディレクトリを削除
jf mvn clean

# 2. jarの生成
jf mvn package --build-name=xraytest-build --build-number=sample1-002

# 3. Artifactoryに登録するbuild info(アーティファクトの詳細や依存関係、環境変数などの情報)を収集する
jf rt bce xraytest-build sample1-002

# 4. Artifactoryにbuild infoを登録
jf rt bp xraytest-build sample1-002

Xrayのスキャン結果は以下のようになり、Log4jの脆弱性は表示されなくなりました。

脆弱性対応済みの場合のXray結果

脆弱性スキャンから特定のものを無視する

上記のいずれのパターンでも検知されている脆弱性(CVE-2016-1000027)が残っています。
これはSpring Frameworkの脆弱性であり、今回利用したSpring Bootを利用したことで表示されています。

上記の脆弱性は今回のコードでは影響がないと判断した場合、
Xrayの設定により、異常と扱われないように「無視ルール(Ignore Rule)」を以下のように追加することで、除外することも可能です。

Xray無視ルールの設定

ルールを追加した上で、スキャンを再実行してみます。

Xrayで再度実行

再スキャン結果では、「Violations」タブから脆弱性が削除されました。

無視ルール追加後のXrayスキャン結果

異常とは扱われませんが、スキャンの結果として「Security」タブには、 脆弱性が存在することを確認することができます。

無視ルール(Ignore Rule)で除外してもスキャン結果で出る

脆弱性スキャンを利用するメリット

ここまで、スキャンができること、どのように確認できるかを挙げてきましたが、
この脆弱性スキャンを利用することで、どんなメリットがあるでしょうか。

開発途中で発見するメリット

開発者は普段、効率よく開発を行うために外部リソースを活用します。
今回のシナリオで利用した Log4j は利用者が非常に多いものであったため、大きく報道されましたが、
全てのOSSの脆弱性が大きく取り上げられるかというと、そうではありません。

Xrayのスキャンのように、一般に公開されている情報をもとに機械的に解析するツールを用いることで、
開発者は意図していなかった脆弱性に対しても早期に認識することができます。
特に、ビルド工程が行われたバイナリファイルを作った後に行われることといえば、QA工程。
XrayのスキャンによってQA前に検知が可能となり、手戻りを最小に抑えることができるでしょう。

本番稼働時に発見するメリット

本番稼働しているということは、すでに開発側から運用側に渡っている状態です。
運用側にはどんなメリットがあるでしょうか。

例として本番稼働しているものを、定期的にスキャンを再実行する場合を考えます。
この際、もし脆弱性が検知された場合は、運用側も画面から確認することができます。
運用側は開発時にどんなOSSを利用しているかまで抑えていない場合も、
開発側に問い合わせずとも脆弱性の有無を早期に確認できます。
また、開発者にとっても同じ画面で課題が確認できるため、対応も素早く開始できるでしょう。 (なお、スキャンの定期実行はWeb UIからは設定はできません。
実際にはCronなどでJFrog CLIをコマンドを定期的に呼び出すことで実現できます。)

まとめ

JFrog Xrayによる脆弱性スキャンについて、サンプルコードを用いた例を含めてご説明しました。
このブログで説明できていない設定については、今後のブログのなかで紹介していきたいと思います。

JFrog Platform は DevOps をサポートするためのプラットフォームであり、今回挙げたのはほんの一部の機能です。
最後にメリットとして挙げたような、開発側・運用側共に負荷軽減になるような仕組みが存在しますので、
是非ご活用いただければと思います。

GradleでJFrog Artifactory越しに依存解決する #MavenCentral #JCenter

1月ももう終わりますが、あけましておめでとうございます。デベロッパーアドボケイトのよこなです。

JFrog Artifactoryは自分たちのアーティファクト(バイナリファイル)を保管する以外に、外部レジストリ(Maven Central, Docker Hubなど)からライブラリのアーティファクトを取得する際の仲介役としても使えます。Artifactoryを経由することで、一度取得したことのあるアーティファクトを保存しキャッシュとして活用できる他、様々なメリットがあります。

このエントリではGradleを使って依存解決する方法を紹介します。
Artifactoryを導入するなら依存解決以外にも活用するのがオススメ(本音)ですが、まずはここから始めてみるパターンも大いにアリだと思う(これもまた本音)ので、依存解決だけにフォーカスして書いていきます。おそらく、JCenterを使い続けたい方にはぴったりの内容かなと思います (参考: Bintray、JCenter、GoCenter、ChartCenterのサービス終了) 。
公式Wikiもあるものの、細かいことまで書かれているので「結局どうしたらいいの」となった方に贈る記事です!

手順

Artifactoryを利用できる状態にする

既にお使いのArtifactoryがあればそちらをお使いいただき、なくて試してみたい場合は無料なのでお気軽に登録してみてください。 jfrog.com

リモートリポジトリを作成する

Artifactoryで使えるリポジトリには種類がある中、依存解決に利用するのは「リモートリポジトリ」です。
今回はリモートリポジトリだけ作りますが、この手順も既にお持ちのものがあればスキップしてください。

リモートリポジトリ作成

右上のメニューからGradle用のリモートリポジトリを作成します。リポジトリの名前は xxx-gradle-maven-remote xxx-gradle-remote (xxxはアプリケーションやプロジェクトの名前) など、パッケージ・リポジトリの種類が分かる形がオススメです。
URLは次の値を入れてください。

使うリポジトリ URL
Maven Central https://repo.maven.apache.org/maven2
Google https://maven.google.com
JCenter https://jcenter.bintray.com

ビルドスクリプト (build.gradle) を更新する

Artifactoryを使っていない場合、次のような記述でリポジトリを指定しますよね。例えば次のような記述だと、基本的にはMaven Central -> Googleの順でアーティファクトを探しにいって依存解決します*1

buildscript {
    repositories {
        mavenCentral()
        google()
    }
}

ここでArtifactoryを使う場合、記述はこうなります。なお、紹介している設定ファイルはArtifactoryからダウンロードできます(後述)。

repositories {
  maven {
    url "${artifactory_url}"
    credentials {
      username = "${artifactory_user}"
      password = "${artifactory_password}"
    }
  }
}

変数は gradle.propertiesなどを使って埋め込んでください。

変数
artifactory_url https://yyy.jfrog.io/artifactory/xxx-gradle-maven-remote形式のURL
(https://【ArtifactoryのURL※ご自身で設定したサーバーIDを含むもの】/artifactory/【リモートリポジトリ名】)
artifactory_user Artifactoryのユーザー
artifactory_password ArtifactoryのパスワードまたはAPI Key

設定はこれだけ!あとはいつものとおり依存解決 (gradle buildとかgradle assemble) すればArtifactoryを経由するようになります。ということで最低限必要なのはここまでで、残りは補足やお役立ち情報です。

Artifactoryから設定ファイル (build.gradlegradle.properties) をダウンロードする

上記の設定ファイルは自分で記述しなくてもダウンロード可能ですが、現状だと依存解決以外に必要な設定もまとめて入ってくる形になっています。記述量はさほど多くないので、必要なものだけ取り入れてシンプルさを保つために自分で書いてしまうのも手だと思います。

「Artifacts」ビューで右上の「Set Me Up」を選択する

リモートリポジトリを選択する + ダウンロードする設定ファイルにクレデンシャル情報を含めたい場合はパスワードを入力する

「Generate Settings」をクリックする

ファイルのダウンロードまたはテキストのコピーをして使う

不要な設定に要注意

Artifactoryからダウンロードされるファイル、またウェブ上にある古い記事には artifactory.resolve.repotitories という設定が含まれている場合があります。実は冗長な設定で不要なので削除していただいても動作します。

複数の外部リポジトリを使う

1つのリモートリポジトリに設定できる外部リポジトリは1つです。しかし、依存解決にMaven CentralもGoogleもJCenterも使いたいケースも多々あるでしょう。その場合は必要な数だけリモートリポジトリを作って、「バーチャルリポジトリ」でまとめます *2
バーチャルリポジトリは複数のリポジトリを束ねて仮想的に1つのリポジトリに見せる機能です。要はインタフェースの役割を果たしてくれ、ユーザーはその裏側にあるリポジトリの構成を意識せずに使うことができます。

こちらは右上のメニューでバーチャルリポジトリ作成を選べます。名前は xxxxxx-virtual とし、まとめたいリポジトリをすべて選択すればOKです。このとき、UI上でリポジトリが並ぶ順番に応じて依存解決先が決まります。

  • example-gradle-remote-mavencentral (Maven Centralにアクセスするリモートリポジトリ)
  • example-gradle-remote-google (GoogleのMavenリポジトリにアクセスするリモートリポジトリ)
    の2つを用いた次の例ではMaven Central -> Googleの順に優先されるというわけです (リポジトリ名長くて切れちゃってますが)。

バーチャルリポジトリを使って複数のリモートリポジトリをまとねる

以上です〜!これで取得したライブラリのアーティファクトがArtifactoryにたまっていきます。冒頭で説明したとおりキャッシュの役割を果たすので時間短縮が期待できたり、JFrog Xrayを使ってセキュリティスキャンができたり、便利なことも多いのでぜひ試してみてください!

*1:参考: Declaring repositories, 第60章 ビルドロジックの体系化など

*2:ビルドスクリプトに全リモートリポジトリを羅列することも可能ですが、リポジトリに変更があったときのメンテナンスが楽なのでバーチャルリポジトリの利用がオススメです

JFrog 製品と Apache Log4j 2 の脆弱性に関して

(このブログは GENERAL: JFrog Services Are Not Affected by Vulnerability CVE-2021-44228 の日本語訳および補足です)

On 10 December 2021, a RCE (remote code execution) exploit was exposed on several versions of the Apache Log4j 2 utility. Affected code exists in log4j core libraries: log4j-core-*.jar, versions 2.0 to 2.14.1.

2021年12月10日 Apache Log4j 2 ユーティリティのいくつかのバージョンで、RCE(リモートコード実行)の脆弱性が公開されました。 影響を受けるコードは log4j コアライブラリ: log4j-core-*.jar のバージョン2.0~2.14.1 です。

Following internal research and validation by the JFrog Security and R&D teams, we can confirm that JFrog services are not affected by this vulnerability (CVE-2021-44228). First, we have validated that JFrog services are not configured to implement the log4j-core package. Additionally, we can confirm that the JDK version used in JFrog services (e.g. Artifactory) contains default protection against remote class loading via JNDI objects. Therefore, no action is required by JFrog customers regarding this issue for JFrog solutions.

JFrog セキュリティチームと R&D チームによる内部調査と検証の結果、JFrog のサービスがこの脆弱性(CVE-2021-44228)の影響を受けていないことが確認できました。まず、JFrog のサービスが log4j-core パッケージを利用するように設定されていないことを確認しました。さらに JFrog サービス(Artifactory など)で使用されている JDK のバージョンには JNDI オブジェクトを介したリモートでのクラス読み込みに対するデフォルトの保護機能が含まれていることを確認しています。したがって、この問題に関して JFrog のお客様が特別に何か対処する必要はありません。

JFrog Security and Xray product teams have updated the Xray database with CVE information regarding this vulnerability, and this information will be available for Xray customers to assist in detection and remediation across customer portfolios.

JFrog Security と JFrog Xray製品チームは、この脆弱性に関する CVE 情報をすでに Xray データベースに更新済みです。つまり JFrog Xray をご利用のお客様は、すぐにアプリケーション全体でこの脆弱性の検出および修正の支援を受けることが可能です。

※ JFrog Xray に関して詳細を知りたい方は下記ウェビナー及びプレゼン資料を参照ください。

www.youtube.com

speakerdeck.com

JFrog has examined and validated that none of the following products reference the vulnerable libraries:

Artifactory 6.x and 7.x, and the accompanying Access service

Distribution

Mission Control

Insights

JFrog は以下の製品が脆弱性のあるライブラリを参照していないことを調査・確認しました。

  • JFrog Artifactory 6.x および 7.x、ならびに付随する Access サービス
  • JFrog Distribution
  • JFrog Mission Control
  • JFrog Insights

(訳注)JFrog Xray がリストにないのは JFrog Xray は Go で実装されているためです!

【Google Cloud Build & JFrog Artifactory + Xray + CLI】Dockerイメージを自動でビルド・保存・セキュリティスキャンする

こんにちは、デベロッパーアドボケイトのよこなです。もう9月ですね。な〜つのお〜わ〜り〜

ソースコードだけじゃなくてアーティファクトを専用リポジトリで保存しましょう!
という話をよくするのですが、最近はもはやおまじないであっという間に「ソースコード→デプロイ」の過程を終えられる便利ツールが増えていますよね。「アーティファクトを取っておくと言っても、コマンド叩いたらサーバーまで行っちゃうんだけど…」と思われる方もいらっしゃるかもしれません。

この記事ではGCPとJFrog Platformを組み合わせた例を使って、アーティファクトの保管・セキュリティスキャンを行います。

☝やりたいこと

  1. Dockerで動くアプリケーションをビルドする
  2. アーティファクトをJFrog Artifactoryに保存する
  3. Artifactory上のアーティファクトにセキュリティスキャンをかけ、問題ない場合のみビルドを正常終了させる

この流れをCloud Build (CI/CDツール) 上で実現します。デプロイするところまで書こうかと思ったのですが、上記だけで超大作になったため割愛します(デプロイにJFrogは登場せず、純粋にCloud Buildの機能なので)。
記事が長いので身構えるかもしれませんが、動かしたいアプリもない、クラウド環境もない、JFrogサーバーもないというゼロからの状態で始めて丁寧に説明しているからなのでご安心を。実際は既存で使っているものをカスタマイズすることになると思うのでもうちょっと気楽にお試し頂けるかと思います。
例えば既にCloud Buildでコンテナイメージのデプロイをしている場合はちょっとステップを追加するだけで脆弱性のスキャンができるようになります!必要に応じ読み飛ばしながらご活用ください🐸

☝Frogに関する前提知識

  • JFrog Artifactory: アーティファクト(今回はDockerイメージ)を保存するためのリポジトリ。
  • JFrog Xray: いわゆるSCAツール。Artifactoryと連携し、アーティファクトが依存するOSSに脆弱性やライセンス違反がないかをスキャンする。

☝コンテナ化されたアプリケーションを用意する

今回デプロイするアプリケーションはこちらです。JavaとSpring bootというフレームワークで作りました。アプリの作り方は詳細割愛しますが、Springの公式ドキュメントを参考にしました。
github.com

実行・アクセスすると Hello Docker World! と返せるだけのシンプル・サンプルアプリケーションです。

☝JFrog Artifactory上にDockerイメージ用のリポジトリを作成する

JFrog SaaS版の利用を開始する

jfrog.com

ここから登録してJFrog Platformが使える状態にしてください。
Name Your Environment*欄はお好きな値を指定していただけばOKです(既存の別のサーバーと重複はNG)。それがURLになり、後々Cloud Build側の設定にも使います。

リポジトリを作成する

アカウント作成して初回ログイン(これ以降、admin権限があるユーザーを使ってください)をしたら、そのままリポジトリも用意しちゃいましょう。

  • リモートリポジトリ
  • ローカルリポジトリ
  • バーチャルリポジトリ

の3つを作成します。以前は別々に作成する必要があったのですが、最近まとめて3つ作れるようになったので結構楽ちんです。

最初のログイン後表示される画面で「Docker」を選択する

プロジェクト名を入れてリポジトリを作成する

今回は雑(サンプルとしては分かりやすいとも言う)ですが、springという名前を指定しました。spring-docker-local, spring-docker-remote, spring-dockerという3つのリポジトリが爆誕します。

リポジトリをXrayでスキャンできるよう設定する

スキャンには時間がかかるので、予めインデックスを追加しておくことでいざスキャンの命令が来たときに素早く結果を返せるようにしておきます。

リポジトリの設定画面からローカル・リモートリポジトリに対してEnable Indexing in Xrayを有効にする設定を入れてあげればOKです。ローカルとリモートを束ねる存在であるバーチャルリポジトリには設定不要です(そもそも設定項目がありません)。

ローカルもリモートも似た画面で設定する

☝Cloud Buildでビルドできるようにする

Google Cloud上にプロジェクトを作成(手順)済みの状態で始めましょう。今回の例では「My First Project」を作りました。

ビルドを定義する設定ファイルcloudbuild.yamlを作成する

さて、ビルドの準備を進めていきますが、基本的には公式ドキュメントが詳しいし分かりやすいです。
cloud.google.com

サンプルアプリケーションのプロジェクトルートにcloudbuild.yaml (Cloud Build上で自動で実行したいことを書き連ねていく設定ファイル)を追加します。完成形はGitHub上のファイルをご確認ください。
では、まずはDockerイメージをビルドしてタグをうつところまで。

steps:
  - name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args:
    - '-c'
    - |-
      docker build --build-arg JAR_FILE==build/libs/*.jar -t gcr.io/$PROJECT_ID/spring-boot-docker .
      docker tag gcr.io/$PROJECT_ID/spring-boot-docker:latest ${_JFROG_PLATFORM_URL}/spring-docker/spring-boot-docker:latest

公式ドキュメントと異なるのはentrypointを指定してbash -cでコマンドをまるごと渡せるようにしているところです。これで、ひとつのステップで2行コマンドを実行できます(参考: bash スクリプトの実行)。
コマンド内の$PROJECT_IDはプロジェクトIDに置換される変数で、Cloud Buildが標準で提供しているものです。一方、${_JFROG_PLATFORM_URL}は独自で設定する環境変数です。値の設定方法は後ほど見せますが、ここではArtifactoryのURLをCI実行時に埋め込むようにしています。

ここまで出来たらgcloudコマンドが使えるようCloud SDKをインストール(手順)して、プロジェクトルートで次のコマンドを実行すればCloud Buildを動かすことができます。

gcloud builds submit

結果はそのままターミナルで確認できますが、Cloud Buildのコンソールにて「履歴」を見ることも可能です。

コンソール上で確認できるビルド履歴

ビルドのトリガーを設定し、自動でビルドが実行されるようにする

先に設定ファイルを書ききってもいいですが、いったん何らかのイベントをきっかけにCloud Build上で自動ビルドが走るように設定しちゃいましょう。ローカルでコマンドを打たなくて良いので動作確認も楽になります。

今回はspring-boot-dockerリポジトリのmainブランチに変更が入ったらビルドするという設定にします。Cloud Buildのコンソールで「トリガー」ページを開きます。

先に最終形をお見せするとこんな感じです。

GitHubと初めて連携する場合、リポジトリを指定するところでGitHubとの行き来が発生します。認証を行い、使うリポジトリにGoogle Cloud Buildのツールを入れましょう。

また、変数をセットするのもポイントですね。今回は次の2つを設定しておいてください(参考: 変換値の置換)。

変数名
_JFROG_PLATFORM_URL JFrog Platform登録時に指定したサーバー名を含むURL(xxx.jfrog.io)
_JFROG_PLATFORM_USER JFrog Platformのログインユーザー(メアド)

☝Cloud BuildからArtifactoryへDockerイメージを保存する

Cloud Build上でさっきビルドしたイメージをArtifactoryへ保存するための設定をしていきます。

JFrog PlatformのAPI KEYをCloud Key Management Serviceで暗号化する

まずはJFrog Platformで認証するためのAPI KEYを発行し、クリップボードにコピーしてローカルで使えるようにします。

右上のメニューからプロフィールページへ行くと発行できる

続いて、今取得したAPI KEYを暗号化します。そうすることで、cloudbuild.ymlに(暗号化した)値を直接書いて安全に使うことができるようになります。

公式ドキュメントを参考にしつつ、暗号化するための鍵を作る2ステップを実施します。

gcloud kms keyrings create [KEYRING-NAME] --location=global
gcloud kms keys create [KEY-NAME] --location=global --keyring=[KEYRING-NAME] --purpose=encryption

[KEYRING-NAME](Keyring = 簡単に言うと鍵のグループ)と[KEY-NAME](Key = 鍵)は自分で決めます。サンプルではそれぞれspring-docker-keyring, key-exampleとしました。これらの値はこの後cloudbuild.yamlでも使います。

これで鍵が作成されたので、それを使って暗号化します。さっきクリップボードにコピーしたAPI_KEYをローカルの環境変数$RT_API_KEYに設定した上で、次のコマンドを実行します。3つ目のコマンドを実行すると返ってくる値こそが暗号化したAPI KEYなので、控えておいてください(まぁ紛失してもまたコマンドを実行すればOKです)。

echo $RT_API_KEY | gcloud kms encrypt --plaintext-file=- --ciphertext-file=- --location=global --keyring=[KEYRING-NAME] --key=[KEY-NAME] | base64

暗号化した値を復号できるよう設定する

暗号化した鍵はビルド実行時に復号したいので、Cloud Buildに復号の許可を与えます。Cloud Buildのコンソールより「設定」画面で変更してください。

おそらくこのときに「APIを有効にしてね」という別画面が立ち上がると思うので、画面に従って設定しましょう。

KMS APIを有効にする

設定ファイルで暗号化したAPI KEYを使えるよう追記する

ようやく準備が整ったので、cloudbuild.yamlに追記します。まずはファイルの末尾に暗号化したAPI KEYを追記しましょう。[]で覆われた値は上の手順にある鍵発行・暗号化時に得たものに差し替えてください。

secrets:
  - kmsKeyName: projects/dark-hall-324609/locations/global/keyRings/[KEYRING-NAME]/cryptoKeys/[KEY-NAME]
    secretEnv:
      APIKEY: '[暗号化されたAPI KEY]'

つまり私のサンプルバージョンだとこんな感じになります。

secrets:
  - kmsKeyName: projects/dark-hall-324609/locations/global/keyRings/spring-docker-keyring/cryptoKeys/key-example
    secretEnv:
      APIKEY: 'CiQAy/L6lVzsfbJqvTbOInV71GDrfUnHFPMbclD7a45xkGgsXlkScwAbTXpQ7gUCXwLhVYLC9BaGcGx7KmaSjuIaErsNQ7CacG/Jetll1xpDc/ITCAr+WrCZqYSktGWyvmE4zSBct9cMWPdVgPnoc1mmOst9iiD1S8G9QeCu8xY9XFYJq/T5K+Cu5lchGtAfWRNB8c1QA58/Qk4='

JFrog CLIを使ってDockerイメージをArtifactoryへ保存する

続いて、ArtifactoryへにDockerイメージを保存するためのステップを追加します。やっとこの記事の肝にたどり着きました…。

ググるとIntegrating Google Cloud Build with JFrog Artifactory | Google Cloud Blogっていう公式の記事もあるんですが、

  • 最新のJFrog CLIのバージョンがv2になっていること
  • かつてCLIのイメージを取得する先であったbintrayはサービス終了していること
    をふまえると、次のような記述が良いでしょう。
  - name: 'releases-docker.jfrog.io/jfrog/jfrog-cli-v2'
    entrypoint: 'bash'
    args:
    - '-c'
    - |-
      apk add docker-cli
      jfrog c add my-jfrog-server --url=https://${_JFROG_PLATFORM_URL}/ --user=${_JFROG_PLATFORM_USER} --password=$$APIKEY
      jfrog rt dp ${_JFROG_PLATFORM_URL}/spring-docker/spring-boot-docker:latest spring-docker --build-name=spring-boot-docker-build --build-number=${BUILD_ID} --server-id=my-jfrog-server
      jfrog rt bce spring-boot-docker-build ${BUILD_ID}
      jfrog rt bp spring-boot-docker-build ${BUILD_ID}

jfrog-cli-v2イメージを使用することでCLIを有効にし、jfrogコマンドが使えるようにします。

CLIの使い方はやりたいことに応じてご確認いただくのが1番ですが、今回使っているコマンドについては説明します。
www.jfrog.com

apk add docker-cli

(当然これはJFrog CLIじゃないですが、準備として必要なので補足します)

  • Cloud Build上ではCLIもコンテナで動いているわけですが、そのコンテナからDockerイメージをプッシュするためにDockerクライアントが必要です。
  • Alpine(CLIのDockerコンテナで動いている軽量のLinux)にapkというパッケージマネージャーでDockerクライアントをインストールしておきます。

jfrog c add

  • cconfigのことです。この記事の上の方で作ったJFrogのサーバーを指定し、認証しておきます。
  • CLIにおいてJFrogのサーバーを一意に識別するため、my-jfrog-serverという名前をここでつけています。

jfrog rt dp

  • rtはArtifactoryを操作するコマンド、dpdocker-pushの略です。直前に設定したmy-jfrog-serverという名前でサーバーを指定し、そこに対してdocker pushしています。
  • この作業でspring-boot-docker-buildという名の「ビルド」という塊を作っているのですが、この後セキュリティスキャンをする際もこのビルドに対して操作を行います。
  • spring-dockerは前半で作成したバーチャルリポジトリの名前で、プッシュ先として指定しています。バーチャルリポジトリに対してプッシュするとアーティファクトはローカルリポジトリに保存されます*1
  • ビルドを識別するためにIDを振る必要があるので、今回はCloud Buildが標準で提供してくれている変数$BUILD_IDを使いました。シーケンシャルな番号を振るとかでも良いです。

jfrog rt bce

  • bcebuild-collect-env の略で、次のステップ (jfrog rt bp) を実行する前の準備としてbuild info (アーティファクトの詳細や依存関係、サーバーの環境変数などビルドの付加情報) を収集します。

jfrog rt bp

  • bpbuild-publishを意味しており、これを実行するとビルド実行時のbuild infoがArtifactory上に一緒に保存されます。

上記の設定を反映してGitHubにプッシュすると、トリガーの設定がうまく行っていればCloud Buildが実行されるはずです。

ArtifactoryのBuildsに行が増えていればイメージの保存成功

build info

ビルドをXrayでスキャンできるよう設定する

作成したビルドにもXrayのインデックスを追加しておきましょう。AdminメニューのXray SettingsでIndexed Resourcesを開き、Buildタブで操作します。

Xray設定画面からスキャンしたいビルドを追加する

Manage Indexをクリック後に開く画面でspring-boot-docker-buildを追加すれば完了です。

☝JFrog Xrayでスキャンする

無事ビルドを作成できたのでXrayを使ってスキャンします。無料版では脆弱性のスキャンのみが使えるので、やっていきましょう。

その前にXray用語をごく簡単に紹介します。

  • ルール: チェックのレベルを定義します。「どの緊急度まで検知するか」「検知したら誰にどうやって通知するか」「検知した場合、そのアーティファクトの利用を許可するか」などを決めます。CVSSのスコアにも対応しています。
  • ポリシー: ルールを束ねてスキャンの方針を示すようなものです。後述のウォッチと紐付けて使います。
  • ウォッチ: ポリシーをどのビルド, リポジトリ*2に適用するかを定義します。

ということでルール, ポリシー, ウォッチを用意します。

adminメニューのXray設定画面を開く

ポリシー・ルールを追加する

ポリシーの作成画面からRuleを作成していく

ルールの作成画面はこのように細かい決まりを定められます。今回は例として

  • 緊急度がHigh以上なら検知する
  • 検知をしたらCIでのビルドを失敗させる(Fail Buildにチェックを入れるとそうなります)
    という設定を入れてみます。

実現したいことをルールで表現する

ルールが追加できたらポリシーを保存しましょう。

ちなみに、なぜ1つのポリシーに複数のルールが設定できるのかについてはユースケースの例を挙げると分かりやすいかもしれません。
例えば「緊急度がHigh以上ならビルドを失敗させたいけど、Medium以下ならとりあえずメールで通知してほしい」場合は、今行った設定に加えて、Mediumならばメール通知するというルールを足してあげればOKです。

ウォッチを作成する

ポリシーを作った画面で隣のWatchesタブから操作できます。

ウォッチはポリシーとビルドを紐付けるものです。どのリポジトリのどのビルドに対しどのポリシーでXrayスキャンを行うかここで指定してください。

それぞれプラスボタンを押して、追加画面でポチポチ選択していきます。

リポジトリ、ビルド、ポリシーを追加する

無事追加できたら設定完了

JFrog CLIを使って保存したDockerイメージにセキュリティスキャンを行う

Xrayが準備万端になったので、cloudbuild.yamlにスキャンするためのコマンドをbpコマンドの後に追記しましょう。

jfrog rt bs spring-boot-docker-build ${BUILD_ID}

bsbinary-scanのことで、これがIDで特定したビルドに対しスキャンを行うための記述です。

結果

ついに全ての設定が完了しました!!!GitHubへ変更を反映させるとまたCloud Buildが走ります。

Xrayをオンにしたらビルドがコケるようになりました(1番上の行)。サンプルで使ったアプリケーションはベースイメージで大量の脆弱性が見つかってしまったんです…。

Cloud Buildの実行結果を見たらJSON形式で詳細が確認できます。

JFrog Platformにアクセスすればよりリッチに詳細を見ることもできます。

☝終わりに

今回はGCP系のツールでやってみましたが、別のプラットフォーム、CI/CDツールでも同様のことが出来ます。オフィシャルにインテグレーションがサポートされている場合は公式ドキュメントが見つかるはずですが、英語しかなかったり最新バージョンを追従できていなかったりすることもあるので、JFrog関連で気になることや不明点があったらぜひご連絡ください〜!ブログのコメント欄でもOKです◎

文中に出てこなかった参考文献

*1:つまり、ここでローカルリポジトリを指定しても同じことが実現できるのですが、基本的にバーチャルリポジトリを使うようにすると便利です。バーチャルリポジトリは複数リポジトリを束ねる機能で、これを指定しておけばプッシュ・プル先を自動で判断してくれるので、ユーザーが操作対象のリポジトリを意識して使い分ける必要がなくなります

*2:「リリースバンドル」にも適用できるのですが、今日は登場していない概念なので割愛しました