脆弱性を一覧管理できる「Octovy」

水谷正慶氏(以下、水谷):ということで作ったのが「Octovy」というツールで、今社内で運用しています。(スライドを指して)この画面自体は自分のリポジトリから取ってきたもので、社内向けではありません。どういったリポジトリにどういったソースがあって、どういったパッケージがあって、どういった脆弱性があるかが一覧で管理できるようになっています。

最初のタイトルであったので丸わかりですが、名前のとおり、基本的には、GitHub Appを使って、ソースコードがプッシュされた瞬間にTrivyを使ってスキャンしています。

Trivyでスキャンすること自体は、GitHub Actionsなどでももちろんできますが、Trivyで検出したものを全部データベースに状態を保存しておいて、それで対応状況を管理できるようになっています。先ほど言った、「これはすぐに対応しない」「これは少し寝かせる」というところを管理できるような仕組みが備わっています。

ほかには、リポジトリや脆弱性に対して任意のラベルをつけられるようにしています。例えば、あるリポジトリに対しては、「これは外部に公開しているプロダクトなので、すぐに対応しないといけない」という判断基準に使うとか、あるいは、脆弱性ごとに別の自前のSeverityをつけたくなったときには、それに対して、自由にラベルづけをできるようにしています。

極めつきに、自由に表現したいという話に関しては、OPAとRegoを使うことによって、CIの結果を制御する仕組みになっています。

Trivyについて

Trivyの話に馴染みがない方もいると思うので、簡単に説明します。Trivy自体は脆弱性スキャナーとして使われているもので、もともとコンテナイメージの中に含まれている、いわゆるソースコードのパッケージや、OSのパッケージをスキャンするものでした。

最近はいろいろな機能が増えていて、今ではファイルシステム上でパッケージのスキャンをできるようになり、ほかにはTerraformとの設定をスキャンする機能なども出てきています。

日本人の福田さんが作られ、Aqua Securityに買収されたという逸話があるツールですが、これを活用させてもらっています。

OPA/Regoとリポジトリごとの設定

もう1つはOPA/Regoに関してで、汎用的なポリシーエンジンとして使うものです。「ポリシーエンジンとは何ぞや」という感じかもしれないので、すごくざっくり説明をすると、JSONを入れるとあるJSONを返すように、ポリシーに従ってJSONを変換したり、あとは、入力されたJSONの条件に応じて、ある特定の値を吐き出したりします。

OPA/Regoが単純にOKかNGかを判定するだけではなく、例えばSeverityを自分の好きな段階を設定して、ある条件だったらどの段階でも好きに出力できるように、けっこう自由度高く入力と出力を決めることもできます。

判定部分に関しても部分的な項目だけではなく、いろいろな組み合わせをして判定をできるようにする、汎用的なエンジンとして社内で使っています。

(スライドを示して)各リポジトリに関しても、脆弱性の状態やリポジトリごとの文脈の情報も付け加えられるようにしています。上のほうは、GoでJWT(JSON Web Token)か何かの脆弱性でしたが、ツール自体はJWTの機能を扱っておらず、依存しているパッケージがその先で使っている感じのものなで、「使っていないから特に問題がありません、unaffectedです」というような判定をしています。

あとはラベルとして、ネットワーク的に外部から分断されているとか、社外向けではなくて社内向けであるという情報を残しておけるようになっています。

具体的にどういうアーキテクチャで動いているか

具体的にどういうアーキテクチャで動いているかですが、今は基本的にCloud Runを使って動かしています。弊社の場合はGCPがメインになるので、そのGCP上でOctovyとTrivyを1つのコンテナに入れて動かしつつ、OPAサーバーを別のCloud Runに立てて運用しています。

GitHub Appで動いているので、GitHubにプッシュしたソースコードの情報などがwebhookで飛んできて、webhookを受けた時にソースコードを取り、Trivyでスキャンした結果をOPAサーバーに投げつけています。

ここでけっこう便利なのが、検出した脆弱性の情報だけではなく、けっこういろいろな情報が取れて、リポジトリがどのようなリポジトリであったかという情報もとれます。

最近だと、脆弱性がないパッケージの情報もTrivyで取れるようになったので、情報を全て一度にOPAサーバーに投げつけた時に、例えば「この脆弱性があったら落とす」ということももちろんできるし、「このリポジトリでこの脆弱性があったら、このリポジトリでこのパッケージがあったら落とす」ということもけっこう自由に制御できるようになる感じです。

ユースケースとしては、例えば急に出てきたパッケージで、まだCVEの番号もついていない時などに、「このパッケージでこのバージョンだったら叩き落とす」というポリシーをすぐに書けたりします。

GitHub上でのポリシー管理

実際どういうふうに管理しているか。部分的なところですが、今はポリシーをGitHub上で全部管理していて、「こういうポリシーを追加します」というものをプルリクで管理しています。

(スライドを示して)これは先ほど言ったOctovy自身のものですが、これもコメントなどでやり合って、github上で「こういうふうにやります」みたいなことを宣言しながらやっている感じです。

「『Log4j』の脆弱性には対処できますか?」ということについては、実は今、微妙に対応できていません。それは、いわゆるJavaのパッケージの脆弱性の情報をTrivyでスキャンしようと思うと、ビルドをしなければいけないためです。

なぜかというと、Trivyはjarのファイルの中身を見てスキャンするので、その中身をきちんと全部検出してくれるのは便利ですが、ビルドをする工程を挟まないといけません。そこに対応できていなくて、今はこのツール上では検出できません。

先ほど話した大混乱があった時は、僕が自分でイメージを全部引っ張ってきて、手元でTrivyを回して、検証したりしていました。

今後は、ビルドしたイメージをスキャンしてJavaの脆弱性を取り込むこともしたいし、クラウド上で展開させた時のプロダクトとしての脆弱性というか、ミスコンフィギュレーションのような情報も、全部1つのプロダクトに集約して使いたいと思っています。

ポリシーの具体例

話に戻ります。ポリシーの例としてOPA/Regoの書き方はけっこう特殊で、宣言的に書くので、普通の手続き型のプログラミング言語をベースに話をすると混乱しがちですが、今日は雰囲気だけ少し見てもらえればと思っています。

(スライドを指して)上側のルールでは、2つのケースでCIを落とすのをやろうとしています。1つがcustom_severity。つまり、自分たちで評価したSeverityがクリティカルのものだったらFailするということで、「== "Critical"」だったらそのままFailさるというルールを書いています。

一方で、下のほうは条件式が2つあって、Highというcustom_severityと、レポジトリのラベルにpublicがついていたらFailするようにしています。

この2つが同時に成り立つ情報が送られてきた場合に、「これはFail」という判定をしていています。これによって、例えば「Criticalはどんなプロダクトでも絶対落とすけれど、Highのものはいったんpublicな公開しているプロダクトに関しては落とす、それ以外に関してはいったん落とさない」というような判定ができるようになっています。

書き方自体もOPA/Regoがわかってないとけっこう難しいので、詳細は割愛しますが、こういったテストも同時に書けます。

先ほど言った、「こういうケースだったら通します、こういうケースだったら落とします」というテストデータを持っていくことができるので、サクセスさせるためのテストデータを用意しておき、それを処理にかけて、successが返ってくる場合とfailureが返ってくる場合がいくつか定義できます。

こういったかたちでテストを書いておくことによって、何か新しいルールを追加した時に、ほかのルールに対してサイドエフェクトを起こすものがないよう、検出するためのテストを動かせるようになっています。

現在の進捗と今後の予定

今回、OPAサーバーをOctovyという脆弱性を検出するためのツールとの組み合わせで紹介しました。将来的にはこのOPAサーバーを、社内のいろいろな認可やセキュリティに関する判定のためのポリシーのエンジンとして使いたいという構想で、今いろいろとやっています。

例えば、セキュリティアラートでGoogle Workspaceやエンドポイントのセキュリティが上がってきた時に、それをどういう判定をするかは、組織ごとのナレッジや判定基準がどうしても出てくると思います。

そういったものを会社としてのポリシーをどうやっていくかを、OPAにポリシーとして記述していき、管理運用していくことを今目指しています。

セキュリティアラートに関しては実はけっこう進んでいて、すでに運用に乗っかっている感じです。社内向けのアプリで、どういうロールの人が何をしていいかは、各サービスやツールごとにハードコードで認可の情報を埋め込みがちです。そういったものをなるべく外に出しておくことで、「この人は何をやっていいか」が、なるべく外部から判定しやすいようにしようとしています。

そうすることで、例えば開発者が実装の分離ができたり、監査する時などに、OPAのサーバーを見るだけでルールが全部わかって、監査としていいところと悪いところがすぐ簡単にできるところまで持っていけると非常にいいかなと思い、いろいろやっています。

(スライドを示して)宣伝ですが、先ほど見ていただいたとおり、OPA/Regoはけっこう取っつきにくいところがありますが、そのあたりを今後やっていきたいと思っている方がもしいたら、ぜひAdvent Calenderを見てもらうとよいかなと思います。

ほかの人と一緒にやろうかなと思っていましたが、おもしろいという理由だけで最終的には全部自分1人でさせてもらうことになり、14日目まで来て、あと10日ぐらいやっていく必要があります。

今まで書いてきたもので、Regoに関する文法や書き方はいろいろ網羅できていると思うので、もし興味があればのぞいてみてもらえればと思います。

まとめに入ります。今回、社内プロダクトで利用しているパッケージ情報を、全体を見渡して管理していきたいということと、どういう事情があるかを少し紹介しました。OPA/Regoを使って、Policy as Codeで管理する恩恵を受けられるので、そういったところをやっていきたいと考えています。

最後に、そういったポリシーをちゃんとコードで管理していくエンジニアリングを一緒にやってくれるメンバーを、絶賛募集しています。私がいるのは、ソフトウェアエンジニアのプロダクトセキュリティですが、コーポレートエンジニアとして社内のセキュリティをするところもあるので、そういったところにもし興味があれば、ぜひお声がけください。

以上で私の発表は終わりです。ありがとうございました。

質疑応答

司会者:水谷さん、ありがとうございます。それでは質疑応答に入りたいと思います。まず私から質問です。今回の場合、ルール管理をある程度手動でできるところが強みと言っていましたが、それ自体は、水谷さんの1日の仕事の中でどれぐらいの時間使うものですか? 毎日管理をしなければいけないのか、それとも週1回ぐらい、ちょっとやったらもうそれでOKなのかというと、どんな感じですか?

水谷:そうですね。今はルールをOPAに移す作業をけっこうしないといけないので、毎日ルールと向き合う感じになっています。移す作業が終われば、毎日やることはなくなります。

あと基本的には、私だけで全部管理するのではなく、みんなでこのポリシーを育てていきたいと考えています。コーポレート側でも、認可や「こういう時にどうする」という判定はどうしてもいろいろな場面で出てくるので、プロダクトセキュリティやプロダクトのインフラなども含めてポリシーをみんなで育てていって、そこに行けば全部わかるようにしていければと考えています。

司会者:ありがとうございます。では「Octovyと類似の課題に対応するOSSはありますか? あれば、差分はどのあたりでしょうか?」という質問です。

水谷:OSSは知らないのですが、要件の2つの部分で、プロダクト・脆弱性ごとに状態を管理するところと、組織全体で脆弱性を統制していくところに関しては、SaaSのサービスで「Snyk」というプロダクトがあり、間違いなくそちらのほうがしっかり作られている感じです。

ただ、私の知る限りだと、自由に判定するところ、インテグレーションなどは今のところないので、差分は一応そのあたりかなと思います。逆に言うと、これをばっちりサポートしてくれたら、そちらに乗り換えてもいいかという気持ちはあります。

司会者:なるほど。ありがとうございます。Advent Calenderについてはどうですか?

水谷:Advent Calenderが渋すぎるというのはまさにそのとおりだと思うのですが、「やるとおもしろいんじゃない?」という話になったので、「やるか!」という感じでほとんどノリでやりました(笑)。

司会者:このあたりはまだコミュニティとしても小さかったり、会社としてやっているところはそれほど多くない感じですか?

水谷:そうですね。注目している会社は出てきていて、電通の子会社のテックブログか何かでOPAの紹介をちょうどやっていたので、使い始めているところは、けっこう注目しているかなという印象です。

大手でいうと、メルカリさんもけっこう内部でバリバリ使われているという話で、どちらかというとKubernetesのInfrastructure as Codeの制御で、OPAを活用していると聞いています。

司会者:わかりました。ありがとうございます。これで水谷さんの発表を終了したいと思います。ありがとうございました。

水谷:ありがとうございました。