ApacheHopとNeo4jを利用したSBOMの可視化

![スライド1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/90654457-6489-cd41-2c36-8620395d98cd.png)

## はじめに
本記事はApacheHop Meetup用に作成したものです。個人の活動に起因するものであり、私の所属する組織を代表する知見、考え方ではありません。

## 目的
Log4Shell、Sprint4Shell、Text4Shell ... 最近何かとお騒がせな4Shell系の脆弱性。そしてLog4Shellをきっかけに注目されているSBOM。SBOMはそれ単体ではあまり意味をなさないので、SBOMで定義されているソフトウェア情報をちゃんと構成管理するCMDBとセットで考えなければなりません。お金のある企業であれば、BlackDuckを買ったり、yamoryを使えばいいでしょう。本記事では、お金をかけずにOSSのみ、しかもノーコードでシステムのSBOMを生成し、それを管理・可視化する仕組みを考えます。こんな方法もあるよっていう１手段の紹介です。  
※お金のある企業はケチらずにBlackDuck、yamoryなどのちゃんとしたものを使いましょう！！

## SBOMとは
私が説明するよりもこういうところを読んだ方が絶対に分かりやすいので割愛します。
* [SBOM導入に際して参照すべき資料とそのポイント (PwC)](https://www.pwc.com/jp/ja/knowledge/column/awareness-cyber-security/vulnerability-management-sbom6.html)
* [SBOM（ソフトウェア部品表）の重要性と効率的な対応方法～オンラインセミナー開催レポート～ (yamory)](https://yamory.io/blog/sbom-seminar-report/)

## 用意するもの
本記事では、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系フレームワーク。説明は割愛します。

すべて無料です。

## アウトプット
先にどういうことをやろうとしているかというと、こういうグラフを作成します。
![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/a02f722f-50e0-b915-f7b0-6074ad9b135f.png)


## フォルダ構成
本記事では、このようなフォルダ構成で作業してます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/d9134bb8-0e2c-6f3b-6d1a-a6176275d528.png" width=600 />


## 手順
### 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回実行）を作成します。
![スライド17.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/26bf9393-7c85-35ba-d750-1e08eb23f8c0.png)


#### get SBOM file
"Get file names"でsbomを生成したフォルダ配下の*.jsonを指定します。
![スライド18.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/348dcc0e-fa7c-8163-2117-f2491fd4bf6e.png)

#### JSON input
JSONファイルを読み込む設定をします。
![スライド19.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/30f19dc5-4556-151a-639e-fbd2fc83c13f.png)
SBOM(JSON)配列の各種値をname、versioninfo、SPDXIDという項目でリストアップする設定です。
![スライド20.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/e50517bd-4759-d23e-fce8-c9f1160d229e.png)

#### Switch / case
SPDXIDの内容に応じて処理を分岐させます。値が"SPDXRef-RootPackage"の場合"Add App Column"へ遷移。そうでない場合、"Add OSS Column"へ遷移させます。
![スライド21.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/7c287b28-b29c-7ef9-7056-40affd17af6a.png)

なぜこのような分岐を行いたいかというと、生成したSBOM(SPDXフォーマット）がこのような配列構造になっているからです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/00ffa48c-e154-805c-0076-3f99cb756d4e.png" width=600/>

#### Add OSS Column
oss_nameとoss_versionをカラムとして追加します。
![スライド23.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/e858eb4f-06db-8a4b-5752-f8c407175a4d.png)

#### Set OSS Value
追加したカラムに値をセットします。
![スライド24.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/0884fb3b-10b4-d48a-3485-48d0e0f13459.png)

#### Add App Column
OSSと同様にapp_nameとapp_versionをカラムとして追加します。
![スライド25.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/b309bb7f-1cba-0119-2bbe-90684a699916.png)

#### Set App Value
追加したカラムに値をセットします。
![スライド26.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/759563d4-317a-5caa-0804-f9121b949df6.png)

#### Merge join
AppとOSSに分岐した処理をマージします。ここでは、両方とも同じファイルから分岐しているので、一意のキーとしてfilenameを使用します。
![スライド27.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/8dca772f-4fcb-f1ce-b91c-f45653abf88a.png)

最終的にこのようなテーブルを作成し、そのテーブルを元にApplication -> OSSというグラフを作成したいためです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/c2659f83-7454-386a-6737-b76eb4f1c81b.png" width=600 />

#### Neo4j Output
最後にNeo4jへの出力を行います。まずFromノードとしてApplicationを定義し、プロパティとしてapp_nameとapp_versionを指定します。
![スライド29.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/12100fa7-2161-490e-9a57-6a21f87ce518.png)

次にToノードとしてOSSを定義し、プロパティとしてoss_nameを指定します。
![スライド30.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/5ee6a45f-1464-4f07-b5f9-f707eddaa847.png)

最後にリレーションとしてoss_versionを指定します。
![スライド31.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/0d7991af-2aa4-592d-5738-d173226bfad8.png)

### Pipeline実行
パイプラインを実行するとNeo4jにNuxt.jsとNext.jsのSBOM情報が取り込まれます。

### いろいろ
この状態でNeo4jでグラフを見てみると、ノードが多すぎて普通のPCだと描画が重たいです。そこでBloomを使ってみます。Bloomを利用するとノードが多くても描画はサクサクです。※それなりのスペックは必要ですが。
![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/a02f722f-50e0-b915-f7b0-6074ad9b135f.png)

例えば、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
```

![graph1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/2e0b2f80-a0df-e9e9-a725-396cc18bbc2a.png)

結構多いです。Nuxtの方が古いものを使ってるかと思いきや、必ずしもそうではない様子。

次に、同様の手順でNuxt3のSBOMを作ってNeo4jに取り込んでみました。
ApacheHopのpipelineは変更する必要はありません。sbom-toolでNuxt3のSBOMを生成して、同じoutputフォルダにjsonを置いてpipelineを実行するだけでNeo4jに上書き更新するので簡単に追加でデータを取り込めます。
可視化すると面白いことがわかりました。Nuxt2とNuxt3、Nextでそれぞれ共通して利用しているOSSはあるものの、Nuxt3とNextだけが共通で利用しているものは無い事が分ります。

![graph2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82651/8ae0a803-c158-9227-e0a1-363a8dd1f96f.png)

## まとめ
ApacheHopを利用することで、結構簡単にSBOMをNeo4jに取り込めました。
あとは脆弱性通知と連携する部分をちゃちゃっと作ってあげれば、脆弱性のあるバージョンのOSSを利用しているシステムを簡単にリストアップすることが可能です。SBOMなので、直接間接に関わらず、影響のある可能性があるシステムはすべてリスト化できます。また、今回はNode.jsからSBOMを生成しましたが、sbom-toolは色々なパッケージ管理に対応しているので、利用可能な幅は広そうです。
何度も言いますが、お金のある企業はちゃんとしたものを利用しましょう。それがソフトウェア業界を成長させる事にも繋がるのでｗ