Skip to main content

強化したSBOMでできること:parlayクイックスタートガイド

blog feature parlay announcement

2023年6月7日

0 分で読めます

新しいオープンソースツールのparlayをリリースしました。SBOMに追加情報を付加できます。詳しくは発表ブログ記事をご覧ください。この記事では、SBOMデータに基づく意思決定においてなぜ重要なのかを簡単に説明しましたが、いくつかの手軽な使用例も役立つのではないかと思い、ご紹介します。

parlayを使うと、SBOMにさまざまな情報を追加できます。その情報を使えば、より強力なポリシーを作成できます。JSONの行数は完全な指標ではありませんが、この例ではSBOMが400%を超えて増加していることがわかります。これにより、多くのユースケースが広がります。

$ snyk sbom --format cyclonedx1.4+json | jq | wc -l
    262
$ snyk sbom --format cyclonedx1.4+json | parlay e enrich - | jq | wc -l
    1169

ライセンスポリシー

最小限の要素だけを含むSBOMには、含まれるパッケージに適用されるライセンス情報がありません。ParlayとEcosyste.msのデータを使って、その情報を追加してみましょう。

snyk sbom --format cyclonedx1.4+json | parlay e enrich -

情報を充実させたSBOMができたので、より強力なポリシーを作成できます。この例では、Open Policy Agentと、その強力なRegoプログラミング言語を使います。ここでは、拒否するポリシーと警告を出すポリシーの2つのリストを作成します。

package main

name = input.metadata.component.name

licenses_to_deny = [
  "LGPL",
]

licenses_to_warn = [
  "MIT"
]

deny[msg] {
  component := input.components[_]
  expression := component.licenses[_].expression
  startswith(expression, licenses_to_deny[_])
  msg := sprintf("%s is using %s which is licensed with an %s license", [name, component.name, expression])
}

warn[msg] {
    component := input.components[_]
    expression := component.licenses[_].expression
    startswith(expression, licenses_to_warn[_])
    msg := sprintf("%s is using %s which is licensed with an %s license", [name, component.name, expression])
}

Unixパイプへの愛を引き続き発揮して、Conftestで強化したSBOMにこのポリシーを適用してみましょう。

snyk sbom --format cyclonedx1.4+json | parlay e enrich - | conftest test -

サンプルプロジェクトでは、指定されたライセンスを使用している一部のパッケージについて、一連の警告が出力されました。

WARN - - main - snykit is using diff-lcs which is licensed with an MIT license
WARN - - main - snykit is using mustermann which is licensed with an MIT license
WARN - - main - snykit is using nio4r which is licensed with an MIT license
WARN - - main - snykit is using puma-metrics which is licensed with an MIT license
WARN - - main - snykit is using rack which is licensed with an MIT license
WARN - - main - snykit is using rack-protection which is licensed with an MIT license
WARN - - main - snykit is using rack-test which is licensed with an MIT license
WARN - - main - snykit is using rake which is licensed with an MIT license
WARN - - main - snykit is using rspec which is licensed with an MIT license
WARN - - main - snykit is using rspec-core which is licensed with an MIT license
WARN - - main - snykit is using rspec-expectations which is licensed with an MIT license
WARN - - main - snykit is using rspec-mocks which is licensed with an MIT license
WARN - - main - snykit is using rspec-support which is licensed with an MIT license
WARN - - main - snykit is using sinatra which is licensed with an MIT license
WARN - - main - snykit is using tilt which is licensed with an MIT license

16 tests, 1 passed, 15 warnings, 0 failures, 0 exceptions

脆弱性ポリシー

もう少し複雑なことを試してみましょう。直接依存関係にあるパッケージのうち、CVSSスコアが特定の値を超える脆弱性にフラグを立てるポリシーを作成します。パッケージデータ、依存関係データ、脆弱性データが必要となる好例です。

deny[msg] {
  vulnerability := input.vulnerabilities[_]
  rating := vulnerability.ratings[_]
  rating.source.name == "Snyk"
  rating.score > max_cvss_score
  component := input.components[_]
  bom_ref = vulnerability["bom-ref"]
  component["bom-ref"] == bom_ref

  root = input.metadata.component["bom-ref"]

  dependency := input.dependencies[_]
  dependency.ref == root

  direct := dependency.dependsOn[_]
  direct == bom_ref

  msg := sprintf("%s version %s has a vulnerability with a CVSS score of %s", [component.name, component.version, round(rating.score)])
}

round(n) = f {
  f := sprintf("%.2f", [n])
  contains(f, ".") # Ensure that it was a float
}

round(n) = f {
  not contains(sprintf("%.2f", [n]), ".") # Test if it wasn't a float
  f := sprintf("%v.00", [n]) # Fudge the decimals for integer values
}

次に、SBOMを生成するか既存のものを使い、Snykの脆弱性データで強化したうえで、Conftestを使ってポリシーを適用します。

snyk sbom --format cyclonedx1.4+json | parlay s enrich - | conftest test -
FAIL - - main - puma version 4.2.1 has a vulnerability with a CVSS score of 9.10

3 tests, 2 passed, 0 warnings, 1 failure, 0 exceptions

ここでは、条件に一致する脆弱性が1件報告されています。

これはあくまで一例です。Open Policy Agentで使われるRego言語を使えば、必要に応じて複雑なロジックを記述できます。別のポリシーツールを使いたい場合も、同様に利用できるはずです。

このソフトウェアの作者は誰?

最後にもう1つ、簡単な例をご紹介します。次の例では、parlayでSBOMを強化した後、jqとawkを使って役立つ情報を出力します。ここでは、各パッケージの作者名を取り出しています。繰り返しになりますが、この情報は最小限の要素だけを含むSBOMには記載されていないことがよくあります。

$ snyk sbom --format cyclonedx1.4+json | parlay e enrich - | jq -r '(.components[] | [.name, .author]) | @tsv' | awk '{print $1; $1=""; print}'
nio4r
 Socketry
puma
 Puma
prometheus-client
 Prometheus
puma-metrics

rack
 Official Rack repositories
rack-test
 Official Rack repositories
rake
 The Ruby Programming Language
rspec-support
 RSpec
rspec-core
 RSpec
diff-lcs
 Austin Ziegler
rspec-expectations
 RSpec
rspec-mocks
 RSpec
rspec
 RSpec
ruby2_keywords
 The Ruby Programming Language
mustermann
 Sinatra
rack-protection
 Sinatra
tilt
 Jeremy Evans
sinatra
 Sinatra

情報を充実させたSBOMデータでできることはほかにもたくさんありますし、SBOMに追加すると役立つデータもまだまだあります。どんな情報があればよいか、ぜひお聞かせください。また、parlayを使った実験例もぜひ共有してください。