Amazon InspectorでSBOMを始めよう

# はじめに
Amazon InspectorでSBOMを出力する機能があることは存知でしょうか。今年の8月に、経産省から[ソフトウェア管理に向けたSBOM（Software Bill of Materials）の導入に関する手引ver2.0](https://www.meti.go.jp/press/2024/08/20240829001/20240829001.html)が策定されるなど、SBOMへの注目度も非常に高まっていますので、Amazon Inspector SBOM Exportについて理解を深めていきましょう。

# SBOM概要
SBOM（Software Bill of Materials）とは、「ソフトウェア部品表」のことです。ソフトウェアには様々なコンポーネント（ライブラリ等）が利用されています。特定のコンポーネントでは、他のコンポーネントと依存関係を持っており、普段利用者が認識している以上に深い階層構造となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/8f5530b6-cca8-030d-9a32-7ac0da847a51.png)
[ソフトウェア管理に向けたSBOM（Software Bill of Materials）の導入に関する手引ver2.0](https://www.meti.go.jp/press/2024/08/20240829001/20240829001-1r.pdf)より抜粋

上記のように特定のソフトウェアに含まれるコンポーネントは階層構造になっており、利用者がすべてを把握するのは現実的ではありません。そのため、コンポーネントを部品表として管理しようというのがSBOMの考え方になります。例えば、Amazon Inspectorで出力したSBOMは、下記のような形になります。

```sample.json
{
	"name": "409870544328/EC2/i-022fba820db137c64/ami-074ea14c08effb2d8",
	"spdxVersion": "SPDX-2.3",
	"creationInfo": {
		"created": "2023-06-02T21:19:22Z",
		"creators": [
			"Organization: 409870544328",
			"Tool: Amazon Inspector SBOM Generator"
		]
	},
	"documentNamespace": "EC2://i-022fba820db137c64/AMAZON_LINUX_2/null/x86_64",
	"comment": "",
	"packages": [{
			"name": "elfutils-libelf",
			"versionInfo": "0.176-2.amzn2",
			"downloadLocation": "NOASSERTION",
			"sourceInfo": "/var/lib/rpm/Packages",
			"filesAnalyzed": false,
			"externalRefs": [{
				"referenceCategory": "PACKAGE-MANAGER",
				"referenceType": "purl",
				"referenceLocator": "pkg:rpm/elfutils-libelf@0.176-2.amzn2?arch=X86_64&epoch=0&upstream=elfutils-libelf-0.176-2.amzn2.src.rpm"
			}],
			"SPDXID": "SPDXRef-Package-rpm-elfutils-libelf-ddf56a513c0e76ab2ae3246d9a91c463"
		},
		{
			"name": "libcurl",
			"versionInfo": "7.79.1-1.amzn2.0.1",
			"downloadLocation": "NOASSERTION",
			"sourceInfo": "/var/lib/rpm/Packages",
			"filesAnalyzed": false,
			"externalRefs": [{
					"referenceCategory": "PACKAGE-MANAGER",
					"referenceType": "purl",
					"referenceLocator": "pkg:rpm/libcurl@7.79.1-1.amzn2.0.1?arch=X86_64&epoch=0&upstream=libcurl-7.79.1-1.amzn2.0.1.src.rpm"
				},
				{
					"referenceCategory": "SECURITY",
					"referenceType": "vulnerability",
					"referenceLocator": "CVE-2022-32205"
				}
			],
			"SPDXID": "SPDXRef-Package-rpm-libcurl-710fb33829bc5106559bcd380cddb7d5"
		},
		{
			"name": "hunspell-en-US",
			"versionInfo": "0.20121024-6.amzn2.0.1",
			"downloadLocation": "NOASSERTION",
			"sourceInfo": "/var/lib/rpm/Packages",
			"filesAnalyzed": false,
			"externalRefs": [{
				"referenceCategory": "PACKAGE-MANAGER",
				"referenceType": "purl",
				"referenceLocator": "pkg:rpm/hunspell-en-US@0.20121024-6.amzn2.0.1?arch=NOARCH&epoch=0&upstream=hunspell-en-US-0.20121024-6.amzn2.0.1.src.rpm"
			}],
			"SPDXID": "SPDXRef-Package-rpm-hunspell-en-US-de19ae0883973d6cea5e7e079d544fe5"
		},
		{
			"name": "grub2-tools-minimal",
			"versionInfo": "2.06-2.amzn2.0.6",
			"downloadLocation": "NOASSERTION",
			"sourceInfo": "/var/lib/rpm/Packages",
			"filesAnalyzed": false,
			"externalRefs": [{
					"referenceCategory": "PACKAGE-MANAGER",
					"referenceType": "purl",
					"referenceLocator": "pkg:rpm/grub2-tools-minimal@2.06-2.amzn2.0.6?arch=X86_64&epoch=1&upstream=grub2-tools-minimal-2.06-2.amzn2.0.6.src.rpm"
				},
				{
					"referenceCategory": "SECURITY",
					"referenceType": "vulnerability",
					"referenceLocator": "CVE-2021-3981"
				}
			],
			"SPDXID": "SPDXRef-Package-rpm-grub2-tools-minimal-c56b7ea76e5a28ab8f232ef6d7564636"
		},
		{
			"name": "unixODBC-devel",
			"versionInfo": "2.3.1-14.amzn2",
			"downloadLocation": "NOASSERTION",
			"sourceInfo": "/var/lib/rpm/Packages",
			"filesAnalyzed": false,
			"externalRefs": [{
				"referenceCategory": "PACKAGE-MANAGER",
				"referenceType": "purl",
				"referenceLocator": "pkg:rpm/unixODBC-devel@2.3.1-14.amzn2?arch=X86_64&epoch=0&upstream=unixODBC-devel-2.3.1-14.amzn2.src.rpm"
			}],
			"SPDXID": "SPDXRef-Package-rpm-unixODBC-devel-1bb35add92978df021a13fc9f81237d2"
		}
	],
	"relationships": [{
			"spdxElementId": "SPDXRef-DOCUMENT",
			"relatedSpdxElement": "SPDXRef-Package-rpm-elfutils-libelf-ddf56a513c0e76ab2ae3246d9a91c463",
			"relationshipType": "DESCRIBES"
		},
		{
			"spdxElementId": "SPDXRef-DOCUMENT",
			"relatedSpdxElement": "SPDXRef-Package-rpm-yajl-8476ce2db98b28cfab2b4484f84f1903",
			"relationshipType": "DESCRIBES"
		},
		{
			"spdxElementId": "SPDXRef-DOCUMENT",
			"relatedSpdxElement": "SPDXRef-Package-rpm-unixODBC-devel-1bb35add92978df021a13fc9f81237d2",
			"relationshipType": "DESCRIBES"
		}
	],
	"SPDXID": "SPDXRef-DOCUMENT"
}
                
```

## SBOMフォーマット
SBOMの主要なフォーマットには、下記の2つがあります。実務においては、SPDXとCycloneDXを利用する場合が多く、デファクトスタンダードとなっています。
| 項目 | SPDX | CycloneDX |
|:-|:-|:-|
| 正式名称  | Software Package Data Exchange | CycloneDX specification |
| サポート団体  | The Linux Foundation SPDX Group | OWASP Foundation |
| 起源 | 2010年 | 2017年 |
| ファイル形式 | Tag-Value(txt)、RDF、xls、JSON、YAML、XML  | JSON、XML、Protocol Buffers(protobuf)  |
| 特徴 |OSSのライセンスコンプライアンスに関する情報を効果的に扱うためのフォーマット。ファイルレベルまで構造化して詳細な情報を記載できる。|セキュリティ管理を念頭に置いたフォーマット。サードパーティソフトウェアやOSSの脆弱性と、悪用可能性を記述できる。   |


## SBOMを利用することによるメリット
SBOMを導入することで、下記のメリットが期待できます。特にAmazon Inspector（一般的な脆弱性管理）と比べ、脆弱性が特定されていないコンポーネントも含めて網羅的に管理できるところが大きなメリットかと思います。

* 脆弱性管理：脆弱性情報とSBOMの情報を突合することで脆弱性を特定できる
* ライセンス管理：OSSの特定漏れによるライセンス違反のリスクを低減できる
* 開発生産性向上：コンポーネントに関連する問題を早期に特定できる

# Amazon Inspector SBOM Export
Amazon Inspector SBOM Exportは、その名の通り**SBOMをS3に出力する機能**です。Amazon Inspectorで監視しているリソースのSBOMを出力することができます。なお、前提条件として、SBOMの出力対象がAmazon Inspectorで監視されているリソースである必要があるため、Amazon Inspectorを有効にせず、本機能だけを利用することはできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/00cf407d-e4e1-7d29-f3f2-ff57b16a2634.png)


:::note warn
執筆時点（2024年10月時点）では、Windows EC2インスタンスはサポートされていません
:::
## 対応フォーマット
Amazon Inspectorでは、CycloneDX1.4(JSON)とSPDX2.3(JSON)形式のSBOM出力に対応しています。

## サポートされているパッケージタイプ
サポートされているパッケージタイプは、以下の通りです。

* Alpine APK
* Debian/Ubuntu DPKG
* Red Hat RPM
* C#
* Go
* Java
* Node.js
* PHP
* Python
* Ruby
* Rust
## 料金
Amazon Inspector SBOM Exportは無料で利用することが可能です。（ドキュメント上は明確な記載がありませんが、[AWSの公式がだしているyoutube](https://www.youtube.com/watch?v=Tj51gqKts3g)で無料と記載があります。）

# Amazon InspetorでSBOMを出力してみる
## KMSキーの作成
SBOM Exportでは、KMSキーの暗号化が必須のため、暗号化に利用するKMSキーを事前に作成しておきます。

## S3バケットポリシー設定
SBOMをS3に出力するため、出力先のバケットでバケットポリシーを編集する必要があります。バケットポリシーは、下記のように設定します。

```bucketpolicy.json
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "allow-inspector",
			"Effect": "Allow",
			"Principal": {
				"Service": "inspector2.amazonaws.com"
			},
			"Action": [
				"s3:PutObject",
				"s3:PutObjectAcl",
				"s3:AbortMultipartUpload"
			],
			"Resource": "arn:aws:s3:::<bucket-name>/*",
			"Condition": {
				"StringEquals": {
					"aws:SourceAccount": "<accountID>"
				},
				"ArnLike": {
					"aws:SourceArn": "arn:aws:inspector2:<Region>:<accountID>:report/*"
				}
			}
		}
	]
}
                
```
## SBOMの出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/4ece73d1-9608-67b6-1cd4-924616901d9a.png)

「Amazon Inspector」>「Export SBOMs」の画面から、SBOMの出力を実行することができます。設定項目は、下記の4つとなります。

* Add filter：SBOMを出力するリソースをタグやリソースタイプ等でフィルターすることができます。設定をしない場合は、サポートされるすべてのリソースでSBOMが出力されます。
* ファイルタイプをエクスポート：SBOMのフォーマットを指定します。
* S3 URI：出力先のS3を指定します。
* KMS key：暗号化に使用するKMSキーを指定します。

「Export」を実行すると、指定したS3にSBOMが出力されます。各リソースのプレフィックス配下に、SBOMファイルが出力される形になります。SBOMファイルはリソースごとに作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/4b2c34c7-517d-4223-5b08-ace37d29d4db.png)


* SPDXの場合
```
SPDX_2_3_outputs_xxxxxx/account=<accountID>/resource=AWS_EC2_INSTANCE/<SBOMファイル>
                                            resource=AWS_ECR_CONTAINER_IMAGE/<SBOMファイル>
                                            resource=AWS_LAMBDA_FUNCTION/<SBOMファイル>
```
* CycloneDXの場合

```
CYCLONEDX_1_4_outputs_xxxxxx/account=<accountID>/resource=AWS_EC2_INSTANCE/<SBOMファイル>
                                                 resource=AWS_ECR_CONTAINER_IMAGE/<SBOMファイル>
                                                 resource=AWS_LAMBDA_FUNCTION/<SBOMファイル>  
```

# Amazon Athenaで分析する
Amazon Inspectorで簡単にSBOMをエクスポートできることがわかりましたが、重要なのはこのSBOMをどう活用するかです。そのため、今回はAmazon Athenaを利用した分析を行います。構成のイメージは、下記の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/fccff001-0d29-e4f9-944c-dee53969c950.png)


## Glue Data Crawler設定
事前にGlueのデータベースを作成しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/5bf14f80-1e6b-907d-dcb5-6fa4fc28666e.png)

データベースを作成したら、Glue Data Crawlerを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/5d3d3c3d-5a79-0e7a-c5fb-032bdee3c1b8.png)

Data SourcesにSBOMをエクスポートしたS3を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/d9d1698f-a101-a43a-9a7e-7a68538e3727.png)

「Create new IAM role」から新規のIAMロールを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/1443749d-5297-5614-23b6-cc5d0bedd4e8.png)

「Target Database」に、先ほど作成したデータベースを指定します。今回は手動でデータをクロールするので、スケジュールは「On-demand」のままとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/c31aadbb-b9bb-21c1-d2b7-00a7126637b6.png)

設定を見直し、問題なければ「Create crawler」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/1ecbb2b7-60cf-963e-1154-f399915c1694.png)

クローラーが作成されます。本来であれば、このままクローラーを実行したいところですが、出力されたSBOMはKMSで暗号化されているので、オブジェクトを復号するための権限を付与してあげる必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/fd470e55-29b9-aa9a-a3eb-2c4dd08d5ca2.png)

クローラーにアタッチされたIAMロールに、下記権限のポリシーを追加します。
```iampolicy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowKMSDecryption",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "<kmsキーのARN>"
        }
    ]
}
```

権限を付与したら、Crawlerの画面から「Run Crawler」を実行しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/16183adf-6c48-41e9-899b-c71e04237aa9.png)

成功していれば、先ほど作成したGlueのデータベースにテーブルが作成されているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/5c38ef17-bec6-cda2-fa38-0c755b897563.png)

## Amazon Athenaクエリ
それでは、Amazon Athenaでクエリを実行してみましょう。今回は、「requestsパッケージのバージョン2.x系を利用しているアプリケーション検索したい」という例を考えます。検索したい情報は、packagesにarray型でネストされているので、UNNESTで変換してあげる必要があります。本環境では、SPDXでSBOMを出力しているので、下記のクエリを実行します。

```
SELECT 
 name AS sbom_image_name,
 package.name AS sbom_package_name,
 package.sourceInfo AS sbom_sourceInfo,
 package.versionInfo AS sbom_version_info
FROM
 "<table_name>"
 CROSS JOIN UNNEST("<table_name>".packages) AS t(package)
 WHERE package.name LIKE 'requests'
 AND package.versionInfo LIKE '2.%'
```

CycloneDXの場合は、下記のようなクエリになります。
```
SELECT 
 resource AS resource_name,
 component.name AS sbom_package_name,
 component.version AS sbom_version_info,
 component.purl AS sbom_metadata
FROM
 "<table_name>"
 CROSS JOIN UNNEST("<table_name>".components) AS t(component)
 WHERE component.name LIKE 'requests'
 AND component.version LIKE '2.%'
```

:::note warn
SPDXとCycloneDXではテーブル（JSONファイル）の構造が異なります。
:::


上記のクエリで、「requestsパッケージのバージョン2.x系を利用しているアプリケーション」を検索することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075801/61ee957f-2cf2-3c5e-a465-acd5c5bf9057.png)

# さいごに
いかがでしょうか。Amazon Inspectorを利用していればすぐに使える機能ですので、皆さんも、是非一度お試しください。（セキュリティは大事！！）