課題提起:モダンな依存関係に潜む見えない脅威
現代のアプリケーションは、その大半が「借りてきたコード」の上で稼働しています。Sonatypeの最新サプライチェーンレポートによると、一般的なエンタープライズのコードベースにおいて、オープンソースコンポーネントが占める割合は日常的に80%〜90%に達します。自社チームが書くプロプライエタリなコードは、まさに氷山の一角にすぎません。水面下には、ベースイメージ、ランタイムエンジン、共有ライブラリ、推移的依存パッケージなどの複雑なネットワークが広がっています。
デリバリーするソフトウェア自体がすでに侵入されている場合、ファイアウォールやSSHポートのセキュリティ強化では防ぎきれません。SolarWindsやLog4Shell(CVE-2021-44228)の侵害事例が示したように、攻撃者は境界防御ではなくビルドフェーズを標的にしています。もし深夜2時に深刻な脆弱性が公開された場合、あなたのチームはその脆弱なライブラリを含むすべてのコンテナイメージを即座に特定できるでしょうか? 多くのエンジニアリングチームにとって、この単純な問いに答えるだけで、数日間にわたる必死の調査が必要になります。
Tip 1: ロックファイルだけでは全体像を把握できません。 package-lock.json や Pipfile.lock のようなファイルは、アプリケーションレベルの依存関係しか追跡しません。ベースコンテナイメージによって取り込まれる glibc や curl、動的システムライブラリなどのOSレベルのパッケージについては何も教えてくれません。実際にリリース・配布される成果物そのものの監査が必要です。
コアコンセプト:SBOM、Syft、Grypeを理解する
この可視性の死角を解消するために、多くのチームが SBOM(Software Bill of Materials:ソフトウェア部品表) を活用しています。
SBOMとは?
SBOMとは、アプリケーションにパッケージングされたすべてのコンポーネント、ライブラリ、推移的依存関係、ライセンス情報を網羅した、構造化された機械可読なインベントリです。スーパーに並ぶ食料品の原材料表示をイメージしてください。食品のリコールが発生した際、消費者はラベルを見るだけで即座に確認できます。料理を化学分析ラボに持ち込んで検査する必要はありません。
現在、エコシステムでは主に2つの標準フォーマットが普及しています。
- CycloneDX: OWASPによって策定・管理。アプリケーションセキュリティ、脆弱性分析、高速なCI/CDパイプライン向けに特化して設計されています。
- SPDX(Software Package Data Exchange): Linux Foundationが支援するISO/IEC 5962国際標準規格。オープンソースのライセンスコンプライアンスや出所(Provenance)の検証で広く利用されています。
Syftの役割
Syftは、Anchore社が開発した軽量CLIツールであり、コンテナイメージ、ファイルシステム、tarアーカイブを検査します。Alpine APK、Debian APTパッケージ、RPM、NPM、PyPI、Goモジュール、Cargoクレートなどの各種パッケージエコシステムをスキャンし、わずか数秒で標準化されたCycloneDXやSPDX形式のファイルとしてカタログ化します。
Grypeの役割
Grypeは脆弱性スキャンを担当するツールです。巨大なコンテナレイヤーを何度もプルする代わりに、Grypeは既存のSBOMファイルを直接解析します。パッケージのバージョンを、National Vulnerability Database(NVD)、GitHub Security Advisories(GHSA)、各ディストリビューション固有のセキュリティトラッカーなどの最新フィードと照合します。
Tip 2: インベントリ生成と脆弱性スキャンを分離する。 ビルドステップでSBOMを1回生成し、恒久的なアーティファクトとして保存しておきます。半年後にゼロデイ脆弱性が発見された場合でも、過去のコンテナイメージをリビルドしたり再ダウンロードしたりすることなく、保存済みのJSONファイルを3秒スキャンするだけで影響有無を確認できます。
実践ハンズオン:SyftとGrypeによる生成とスキャン
ここでは、バイナリのインストール、最小限のNode.jsイメージからのSBOM生成、脆弱性の検査、そしてワークフロー全体をGitHub Actionsパイプラインへ組み込む手順を解説します。
ステップ1:SyftとGrypeをローカルにインストールする
どちらのユーティリティも、Linux、macOS、Windows向けの静的バイナリとして提供されており、外部ランタイムへの依存関係は一切ありません。
# Syftを/usr/local/binにインストール
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# Grypeを/usr/local/binにインストール
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# 両方のバイナリが実行可能か確認
syft --version
grype --version
ステップ2:SyftでSBOMを生成する
Docker Hubから直接ターゲットイメージを指定してSyftを実行します。この例では node:18-alpine を対象にし、インベントリを標準のCycloneDX JSON形式で出力します。
# 人間が読める形式の簡易サマリーを標準出力に表示
syft node:18-alpine
# 完全なCycloneDX JSONをファイルに出力
syft node:18-alpine -o cyclonedx-json=./sbom-node.json
生成された sbom-node.json を開いてみましょう。Alpineシステムパッケージ(busybox や ssl_client など)とグローバルNodeモジュールの両方について、詳細なパッケージ名、暗号化ハッシュ値、Package URL(PURL)、アップストリームライセンスが記録されていることが確認できます。
Tip 3: 機械処理には常にCycloneDX JSONを標準として採用する。 ターミナル上で見るCLIテーブル表示は分かりやすいですが、コンプライアンスプラットフォーム、ポリシーエンジン、後続のスキャナーなどで扱うには構造化されたJSONが不可欠です。
ステップ3:GrypeでSBOMの脆弱性をスキャンする
コンテナイメージを再プルすることなく、生成した sbom-node.json を直接Grypeに渡します。
# SBOMファイルを直接スキャン
grype sbom:./sbom-node.json
# ベンダーから修正パッチが提供されている脆弱性のみを表示
grype sbom:./sbom-node.json --only-fixed
# HighまたはCriticalのCVEが検出された場合はゼロ以外の終了コードで終了
grype sbom:./sbom-node.json --fail-on high
Tip 4: PRをブロックする際は未修正の脆弱性を除外する。 アップストリームのCVEに対してまだパッチがリリースされていない場合、パイプラインを失敗させてもエンジニアに対処法がなく開発が滞ってしまいます。--only-fixed と --fail-on high を組み合わせることで、パッケージのバージョンアップによって実際にリスクを解消できる場合のみビルドを失敗させる運用が可能です。
ステップ4:SyftとGrypeをGitHub Actionsに統合する
マージごとにこのプロセスを自動化します。以下のワークフローでは、ローカルDockerコンテナをビルドし、SBOMを生成し、深刻なCVEを検出し、そのインベントリをビルドアーティファクトとして90日間保存します。
この設定を .github/workflows/security-scan.yml として保存します。
name: サプライチェーンセキュリティスキャン
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- name: リポジトリをチェックアウト
uses: actions/checkout@v4
- name: Docker Buildxのセットアップ
uses: docker/setup-buildx-action@v3
- name: ローカルコンテナイメージのビルド
uses: docker/build-push-action@v5
with:
context: .
load: true
tags: my-app:latest
- name: SyftによるSBOMの生成
uses: anchore/sbom-action@v0
with:
image: my-app:latest
format: cyclonedx-json
output-file: ./sbom.cyclonedx.json
- name: GrypeによるSBOMのスキャン
uses: anchore/scan-action@v3
with:
sbom: ./sbom.cyclonedx.json
fail-build: true
severity-cutoff: high
only-fixed: true
- name: SBOMアーティファクトの保存
uses: actions/upload-artifact@v4
if: always()
with:
name: software-bill-of-materials
path: ./sbom.cyclonedx.json
retention-days: 90
Tip 5: デプロイレコードとともにSBOMを保存・保持する。 監査やインシデント対応は過去を遡る作業です。リリースから数カ月後に特定ライブラリの脆弱性エクスプロイトが判明した場合でも、ビルド#142当時のアーカイブ済みSBOMがあれば、影響を受けているかを即座に検証できます。
まとめ:本番環境のセキュリティはパイプラインから始まる
サプライチェーンの安全確保とは、開発プロセスに摩擦を生じさせることではなく、当て推量を排除することです。SyftとGrypeを組み合わせることで、本番環境に投入されるすべての依存関係を追跡し、デプロイクラスターへ到達する前に重大なCVEをゲートで食い止めることができます。セットアップは15分未満で完了し、実行時間はわずか数秒。すべてのビルドにおいて完全なインベントリの透明性をチームにもたらします。

