はじめに
本記事はApacheHop Meetup用に作成したものです。個人の活動に起因するものであり、私の所属する組織を代表する知見、考え方ではありません。
目的
Log4Shell、Sprint4Shell、Text4Shell ... 最近何かとお騒がせな4Shell系の脆弱性。そしてLog4Shellをきっかけに注目されているSBOM。SBOMはそれ単体ではあまり意味をなさないので、SBOMで定義されているソフトウェア情報をちゃんと構成管理するCMDBとセットで考えなければなりません。お金のある企業であれば、BlackDuckを買ったり、yamoryを使えばいいでしょう。本記事では、お金をかけずにOSSのみ、しかもノーコードでシステムのSBOMを生成し、それを管理・可視化する仕組みを考えます。こんな方法もあるよっていう1手段の紹介です。
※お金のある企業はケチらずにBlackDuck、yamoryなどのちゃんとしたものを使いましょう!!
SBOMとは
私が説明するよりもこういうところを読んだ方が絶対に分かりやすいので割愛します。
用意するもの
本記事では、Microsoft社がOSS公開したsbom-toolを用いて、NuxtJS(init状態)、NextJS(init状態)のSBOMを生成し、出力されたSBOM(JSON)をApacheHopで読み込んでNeo4jにデータ投入してみます。
- Neo4j (https://neo4j.com/)
グラフDBです。説明は割愛します。 - ApacheHop (https://hop.apache.org/)
ETLツールです。説明は割愛します。 - sbom-tool (https://github.com/microsoft/sbom-tool)
Microsoft社が提供しいているSBOM生成ツールです。説明は割愛します。 - NuxtJS v2 (https://nuxtjs.org/)
React系フレームワーク。説明は割愛します。 - NextJS (https://nextjs.org/)
Vue系フレームワーク。説明は割愛します。
すべて無料です。
アウトプット
先にどういうことをやろうとしているかというと、こういうグラフを作成します。
フォルダ構成
手順
Nuxt.js、Next.jsの初期化
ここは割愛します。それぞれHPのget startのやり方を参考にしてください。initした状態でよいです。
sbom-tool実行
下記のコマンドを実行。
上のフォルダ構成で、sbomフォルダ配下で実行することを前提にしています。
md sbom-output\NextJSApp
md sbom-output\NuxtJSApp
.\sbom-tool\sbom-tool-win-x64.exe generate -b sbom-output\NextJSApp -bc apps\NextJSApp -pn NextJSApp -pv 1.0.0 -nsb http://example.com
.\sbom-tool\sbom-tool-win-x64.exe generate -b sbom-output\NuxtJSApp -bc apps\NuxtJSApp -pn NuxtJSApp -pv 1.0.0 -nsb http://example.com
copy sbom-output\NextJSApp\_manifest\spdx_2.2\manifest.spdx.json sbom-output\nextjsapp.json
copy sbom-output\NuxtJSApp\_manifest\spdx_2.2\manifest.spdx.json sbom-output\nuxtjsapp.json
ApacheHop Pipeline作成
Start
Pipelineの開始点を作成します。これはお約束みたいなもの。startという部品がないので、"generate row"で1行実行(1回実行)を作成します。
get SBOM file
"Get file names"でsbomを生成したフォルダ配下の*.jsonを指定します。
JSON input
JSONファイルを読み込む設定をします。
SBOM(JSON)配列の各種値をname、versioninfo、SPDXIDという項目でリストアップする設定です。
Switch / case
SPDXIDの内容に応じて処理を分岐させます。値が"SPDXRef-RootPackage"の場合"Add App Column"へ遷移。そうでない場合、"Add OSS Column"へ遷移させます。
なぜこのような分岐を行いたいかというと、生成したSBOM(SPDXフォーマット)がこのような配列構造になっているからです。
Add OSS Column
oss_nameとoss_versionをカラムとして追加します。
Set OSS Value
Add App Column
OSSと同様にapp_nameとapp_versionをカラムとして追加します。
Set App Value
Merge join
AppとOSSに分岐した処理をマージします。ここでは、両方とも同じファイルから分岐しているので、一意のキーとしてfilenameを使用します。
最終的にこのようなテーブルを作成し、そのテーブルを元にApplication -> OSSというグラフを作成したいためです。
Neo4j Output
最後にNeo4jへの出力を行います。まずFromノードとしてApplicationを定義し、プロパティとしてapp_nameとapp_versionを指定します。
次にToノードとしてOSSを定義し、プロパティとしてoss_nameを指定します。
最後にリレーションとしてoss_versionを指定します。
Pipeline実行
パイプラインを実行するとNeo4jにNuxt.jsとNext.jsのSBOM情報が取り込まれます。
いろいろ
この状態でNeo4jでグラフを見てみると、ノードが多すぎて普通のPCだと描画が重たいです。そこでBloomを使ってみます。Bloomを利用するとノードが多くても描画はサクサクです。※それなりのスペックは必要ですが。
例えば、NuxtJSとNextJSで同じOSSだけど、バージョンが異なるものが無いかを見てみます。
Cypherは
match (nuxt:Application{name:"NuxtJSApp"})-[l1]->(oss:OSS)<-[l2]-(next:Application{name:"NextJSApp"}) where l1.version <> l2.version return nuxt,next,oss,l1,l2
結構多いです。Nuxtの方が古いものを使ってるかと思いきや、必ずしもそうではない様子。
次に、同様の手順でNuxt3のSBOMを作ってNeo4jに取り込んでみました。
ApacheHopのpipelineは変更する必要はありません。sbom-toolでNuxt3のSBOMを生成して、同じoutputフォルダにjsonを置いてpipelineを実行するだけでNeo4jに上書き更新するので簡単に追加でデータを取り込めます。
可視化すると面白いことがわかりました。Nuxt2とNuxt3、Nextでそれぞれ共通して利用しているOSSはあるものの、Nuxt3とNextだけが共通で利用しているものは無い事が分ります。
まとめ
ApacheHopを利用することで、結構簡単にSBOMをNeo4jに取り込めました。
あとは脆弱性通知と連携する部分をちゃちゃっと作ってあげれば、脆弱性のあるバージョンのOSSを利用しているシステムを簡単にリストアップすることが可能です。SBOMなので、直接間接に関わらず、影響のある可能性があるシステムはすべてリスト化できます。また、今回はNode.jsからSBOMを生成しましたが、sbom-toolは色々なパッケージ管理に対応しているので、利用可能な幅は広そうです。
何度も言いますが、お金のある企業はちゃんとしたものを利用しましょう。それがソフトウェア業界を成長させる事にも繋がるのでw