以前、別の記事にて紹介したSBOM生成ツールの一つsyftのcatalogerに関する機能に少しアップデートがあったので、紹介したいと思います。
syftでは、catalogerという言語ごとに、どのファイルからパッケージのメタ情報を抽出するかに応じて、それぞれ異なるアルゴリズムが裏で動いています。
例えば、pythonのrequirements.txtからパッケージのメタ情報を抽出する場合は、python-package-catalogerというcatalogerが動きます。
今回のアップデートで、
- syftのcatalogerの選択方法について仕様が変更された
- syftがcatalogerのリストを出力できるようになった
ため、本記事ではその詳細について解説をしていきます。
Catalogerについて
catalogerのdefault機能では、スキャン対象がコンテナイメージ、ディレクトリ、またはその両方で動くかでcatalogerが分類されています。
コンテナイメージスキャン用のcatalogerはすでにパッケージがインストールされていることを前提として使用されます。
例えば、Pythonのパッケージを特定するために、syftはsite-packagesディレクトリ下に存在するeggやwheelのメタデータをスキャンするために起動します。ここで、イメージ用のcatalogerではrequirements.txtなどからパッケージ情報は抽出できません。
ディレクトリスキャン用のcatalogerではすでにインストールされているパッケージ情報だけでなく、依存関係を宣言したファイル(requirements.txtやpom.xml)などもスキャン対象にしています。そのため、インストールしていないパッケージ情報についても検出を行います。
Catalogerとそれに対応するtagの一覧
以下は、syftが動かしているすべてのcatalogerとそれが対応するtagの一覧です。こちらの一覧はcataloger listというコマンドで出力を行いました。こちらのコマンドについては後で解説を行います。このリストのtagを確認すれば、使用したいcatalogerがコンテナイメージ用かディレクトリ用か、それとも両方に対応しているかを確認することができます。
| CATALOGER | TAGS |
|---|---|
| alpm-db-cataloger | alpm, archlinux, directory, image, installed, linux, os, package |
| apk-db-cataloger | alpine, apk, directory, image, installed, linux, os, package |
| binary-cataloger | binary, declared, directory, image, installed, package |
| cargo-auditable-binary-cataloger | binary, image, installed, language, package, rust |
| cocoapods-cataloger | cocoapods, declared, directory, language, package, swift |
| conan-cataloger | conan, cpp, declared, directory, language, package |
| conan-info-cataloger | conan, cpp, image, installed, language, package |
| dart-pubspec-lock-cataloger | dart, declared, directory, language, package |
| dotnet-deps-cataloger | c#, declared, directory, dotnet, language, package |
| dotnet-portable-executable-cataloger | binary, c#, directory, dotnet, image, installed, language, package |
| dpkg-db-cataloger | debian, directory, dpkg, image, installed, linux, os, package |
| elixir-mix-lock-cataloger | declared, directory, elixir, language, package |
| erlang-rebar-lock-cataloger | declared, directory, erlang, language, package |
| github-action-workflow-usage-cataloger | declared, directory, github, github-actions, package |
| github-actions-usage-cataloger | declared, directory, github, github-actions, package |
| go-module-binary-cataloger | binary, directory, go, golang, gomod, image, installed, language, package |
| go-module-file-cataloger | declared, directory, go, golang, gomod, language, package |
| graalvm-native-image-cataloger | directory, image, installed, java, language, package |
| haskell-cataloger | cabal, declared, directory, hackage, haskell, language, package |
| java-archive-cataloger | directory, image, installed, java, language, maven, package |
| java-gradle-lockfile-cataloger | declared, directory, gradle, java, language, package |
| java-pom-cataloger | declared, directory, java, language, maven, package |
| javascript-lock-cataloger | declared, directory, javascript, language, node, npm, package |
| javascript-package-cataloger | image, installed, javascript, language, node, package |
| linux-kernel-cataloger | declared, directory, image, installed, kernel, linux, package |
| nix-store-cataloger | directory, image, installed, language, nix, package |
| php-composer-installed-cataloger | composer, image, installed, language, package, php |
| php-composer-lock-cataloger | composer, declared, directory, language, package, php |
| portage-cataloger | directory, gentoo, image, installed, linux, os, package, portage |
| python-installed-package-cataloger | directory, image, installed, language, package, python |
| python-package-cataloger | declared, directory, language, package, python |
| r-package-cataloger | image, installed, language, package, r |
| rpm-archive-cataloger | declared, directory, linux, os, package, redhat, rpm |
| rpm-db-cataloger | directory, image, installed, linux, os, package, redhat, rpm |
| ruby-gemfile-cataloger | declared, directory, gem, language, package, ruby |
| ruby-gemspec-cataloger | declared, directory, gem, gemspec, language, package, ruby |
| ruby-installed-gemspec-cataloger | gem, gemspec, image, installed, language, package, ruby |
| rust-cargo-lock-cataloger | cargo, declared, directory, language, package, rust |
| sbom-cataloger | package, sbom |
| swift-package-manager-cataloger | declared, directory, language, package, spm, swift |
catalogerの選択について
catalogerを指定する方法は2種類あります。
- cataloger名による指定方法
- cataloger名をフルネームで指定する
- 例:
java-pom-catalogerやjava-archive-cataloger
- catalogerに関係するtagで指定する方法
- catalogerにはそれぞれ関係するtagがついているため、それを指定する
- 例:
java、image
catalogerを明示的に指定する場合はCLI flag --override-default-catalogers を指定します。
また、CLI flag --select-catalogersを使用することで、デフォルトのcatalogerの集合に対して、
- 必要なcatalogerのみを選択する
- 新たにcatalogerを追加する
- 必要ないcatalogerを削除する
ことができます。
必要なcatalogerを選択するためには、単にタグを指定してください(例:--select-catalogers TAG)。
例えば、--select-catalogers java,go とすればdefaultのcatalogerからすべての java と goのcatalogerを選択します。
catalogerを 追加 するには、cataloger名の前に + を付けてください (例 --select-catalogers +NAME)。
catalogerを削除するには、cataloger名またはtagの前に - を付けてください(例:--select-catalogers -NAME_OR_TAG)。
These rules and the dynamic default cataloger sets approximates to the following logic:
image_catalogers = all_catalogers AND catalogers_tagged("image")
directory_catalogers = all_catalogers AND catalogers_tagged("directory")
default_catalogers = image_catalogers OR directory_catalogers
sub_selected_catalogers = default_catalogers INTERSECT catalogers_tagged(TAG) [ UNION sub_selected_catalogers ... ]
base_catalogers = default_catalogers OR sub_selected_catalogers
final_set = (base_catalogers SUBTRACT removed_catalogers) UNION added_catalogers
Examples
コンテナイメージをスキャンし、Pythonパッケージに関するcatalogerを起動させる場合
syft <some container image> --select-catalogers "python"
# この場合、以下のcatalogerのみが起動する
# - python-installed-package-cataloger
同様のコマンドでディレクトリに対してスキャンを実行する場合は、
syft <a directory> --select-catalogers "python"
# この場合、以下のcatalogerが起動
# - python-installed-package-cataloger
# - python-package-cataloger
catalogerを追加、削除する場合は
syft ... --select-catalogers "+sbom-cataloger"
syft ... --select-catalogers "-rpm"
defaultのcatalogerからgoのcatalogerのみを選択し、sbom-catalogerを追加する場合
syft <some container image> --select-catalogers "go,+sbom-cataloger"
# この場合以下のcatalogerが起動する
# - go-module-binary-cataloger
# - sbom-cataloger
--override-default-catalogersを使用すると、コンテナイメージ、ディレクトリをスキャンするかに関係なく、catalogerを指定することができます。
binaryを明示的にスキャンする場合は--override-default-catalogersを用いて
syft ... --override-default-catalogers "binary"
# この場合binary tagに関するcatalogerのみが起動する
# - binary-cataloger
# - cargo-auditable-binary-cataloger
# - dotnet-portable-executable-cataloger
# - go-module-binary-cataloger
syft ... --override-default-catalogers "go-module-binary-cataloger,go-module-file-cataloger"
Catalogerリスト
前節では、catalogerの指定方法について解説しました。ここでは、そのcatalogerのリストをどう見るのか?について解説をします。
syftではv0.101.0でcataloger listコマンドが追加されました。関連するIssueはこちらをご覧ください。
コマンドの使い方
それでは、cataloger listコマンドを利用してみましょう。コマンドのオプションは前節で説明したものと同じものが使用できます。
syft cataloger list --select-catalogers "python, java, go"
すると、以下のように、python, java, goに関連する、catalogerとそれに関連するtagを見ることができます。
Default selections:
- "all"
Selected by expressions:
- "python, java, go"
┌────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────┐
│ CATALOGER │ TAGS │
├────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────┤
│ go-module-binary-cataloger │ binary, directory, go, golang, gomod, image, installed, language, package │
│ go-module-file-cataloger │ declared, directory, go, golang, gomod, language, package │
│ graalvm-native-image-cataloger │ directory, image, installed, java, language, package │
│ java-archive-cataloger │ directory, image, installed, java, language, maven, package │
│ java-gradle-lockfile-cataloger │ declared, directory, gradle, java, language, package │
│ java-pom-cataloger │ declared, directory, java, language, maven, package │
│ python-installed-package-cataloger │ directory, image, installed, language, package, python │
│ python-package-cataloger │ declared, directory, language, package, python │
└────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────┘
また、これらのcatalogerリストは、-oというオプションで、出力をjsonに指定することもできます:
syft cataloger list -o json | jq
ここで、最後にjqコマンドを使用しています。
出力結果:
{
"default": [
"all"
],
"selection": [],
"catalogers": [
{
"name": "alpm-db-cataloger",
"tags": [
"alpm",
"archlinux",
"directory",
"image",
"installed",
"linux",
"os",
"package"
]
},
{
"name": "apk-db-cataloger",
"tags": [
"alpine",
"apk",
"directory",
"image",
"installed",
"linux",
"os",
"package"
]
},
{
"name": "binary-cataloger",
"tags": [
"binary",
"declared",
"directory",
"image",
"package"
]
},
...
}