サプライチェーン セキュリティ

SSoT: 本書は Parky のサプライチェーン (依存 / build / artifact / 配信) に対する セキュリティ多層防御の SSoT。SLSA Level 3 達成を目標に、SBOM / provenance attestation / dependency review / secret scanning の 4 層で守る。

関連: incident-response.html(CVE 緊急対応)/ github-environments.html(required reviewer / protected secret)/ deployment-rollback.html(攻撃検知後のロールバック)。

採用している層 (4 層 + α)

ツール対象状態workflow
1. SBOM 生成 CycloneDX (@cyclonedx/cyclonedx-npm) api / web/packages / portal-{admin,owner,marketing} / web-home 運用中 sbom.yml
2. SLSA Provenance actions/attest-build-provenance + Sigstore (Fulcio + Rekor) api/dist/**/*.js (Worker bundle) 運用中 (loose pin) provenance-attest.yml + 各 deploy-api-*.yml
3. Dependency Review actions/dependency-review-action 全 PR の package-lock.json 差分 運用中 dependency-review.yml
4. Secret Scanning GitHub Push Protection + (将来) TruffleHog 全 commit / push Push Protection のみ TODO: trufflehog.yml 追加予定
+α. Dependabot GitHub Native npm / GitHub Actions / Dart 運用中 dependabot.yml
+α. npm audit npm CLI local + CI (api-ci.yml) 運用中
+α. CodeQL GitHub Native JS/TS 未導入 follow-up

SLSA Level 達成度(自己評価)

SLSA = Supply-chain Levels for Software Artifacts。公式 v1.0 LevelsBuild track を基準に、Parky の達成度を Worker bundle (api/dist/) について評価する。

Level要件Parky の状態判定
L1 Provenance が存在する (中身は信用しなくてよい) build は GitHub Actions で完結し、commit SHA + workflow run 単位で artifact が紐づく 達成
L2 Provenance が build platform 側で署名される actions/attest-build-provenance が GitHub OIDC + Sigstore Fulcio で署名済 達成
L3 Provenance が build platform 側で 非偽造可能に署名される (developer 側から偽造不可) Sigstore Rekor transparency log に記録 + Fulcio が GitHub OIDC token 経由で X.509 証明書を発行。 developer 個人の credential では署名不可。 build runner は GitHub-hosted ubuntu-22.04 (self-hosted runner 不使用) で OS / toolchain が GitHub による管理下にある。 達成 (Worker bundle)
L4(草案) Source 監査 + Hermetic build + 2 人 review 必須 main branch protection は dev/stg → main フローで検討中。hermetic は npm registry 依存のため未達。 対象外 (1 人開発期)

結論: Worker bundle (api/dist/) について SLSA L3 達成。 Pages 配信 artifact (portal-*, web-home) は CF 側 build のため L0〜L1 相当に留まる (詳細は §既知の限界)。

検証手順 (consumer 側)

GitHub CLI で attestation を verify (推奨)

Worker bundle が「正しい repo + commit + workflow から作られたか」を検証する。CI 内で生成された attestation を直接 GitHub から引いてくるので、ローカルに artifact があれば即実行可能。

# 1. deploy 済 worker bundle を取得 (例: dev)
gh run download --name api-dist-dev-<sha> -D /tmp/parky-dist
# 2. attestation verify (issuer / repo / commit を check)
gh attestation verify /tmp/parky-dist/index.js \
  --owner high-field \
  --repo high-field/parky
# 期待出力 (抜粋):
#   ✓ Verification succeeded!
#     - subject:     /tmp/parky-dist/index.js
#     - workflow:    https://github.com/high-field/parky/.github/workflows/deploy-api-prod.yml@refs/heads/main
#     - signer:      https://token.actions.githubusercontent.com
#     - cert issuer: https://fulcio.sigstore.dev

cosign で Sigstore transparency log を直接 verify

gh attestation verify が GitHub Native API 経由なのに対し、こちらは Sigstore (Rekor) を 直接叩く。GitHub の rate limit / API 障害時の代替手段。

# cosign 1.x 系 (https://github.com/sigstore/cosign)
COSIGN_EXPERIMENTAL=1 cosign verify-attestation \
  --type slsaprovenance1 \
  --certificate-identity-regexp 'https://github.com/high-field/parky/.+' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  --bundle attestation.bundle \
  /tmp/parky-dist/index.js

SBOM の中身 inspect

# 直近の SBOM artifact を取得
gh run download --name sbom-api-<sha> -D /tmp/parky-sbom
# CycloneDX JSON の component 数 / license 一覧
jq '.components | length' /tmp/parky-sbom/sbom-api.cdx.json
jq -r '.components[] | "\(.name)@\(.version)\t\(.licenses[0].license.id // "?")"' \
  /tmp/parky-sbom/sbom-api.cdx.json | sort -u | head -50
# CVE スキャン (grype を使う場合)
grype sbom:/tmp/parky-sbom/sbom-api.cdx.json --fail-on high

SHA pin 状態

actionpin 形式備考
actions/checkout@93cb6efe... (v5.0.1)commit SHArepo 全体で統一済
1password/load-secrets-action@92467eb2... (v4.0.0)commit SHA
actions/attest-build-provenance@v1looseTODO(supply-chain): 公式 release SHA に pin。releases 確認後置換
actions/dependency-review-action@v4looseTODO(supply-chain): 公式 release SHA に pin。releases 確認後置換
actions/setup-node@v4looserepo 横断 cleanup (別 PR)

既知の限界

1. Cloudflare Pages 配信は attestation 非対応

Parky の portal-{admin,owner,marketing} と web-home は Cloudflare Pages で配信している。 Pages は CF 側で build を実行するため、GitHub Actions runner の OIDC token 経由で attestation を発行できない (build artifact が GHA から見えない)。

代替策:

  • Pages の deploy log + commit SHA を「監査ログ」として扱う (CF dashboard > Deployments > Build log を保管 90 日)。
  • SBOM は repo 視点 (source code dependencies) で取得済 (sbom-web-portal-*)。 build time の transitive までは追えないが CVE 監査の一次フィルタとしては十分。
  • 将来 Pages を Cloudflare Workers Sites or 自前 build → wrangler deploy に切替えれば attestation 化可能。 現状は予定なし。

2. Mobile (Flutter) artifact は対象外

Flutter アプリ (mobileapp/) は App Store / Play Store の signing chain が別系統 (Apple / Google の key chain) なので、SLSA provenance とは別レイヤーの保証になる。本書のスコープ外。

3. wrangler bundle は npm registry に hermetic 依存していない

SLSA L4 の hermetic 要件 (build inputs が完全に固定 / 外部 fetch 禁止) は、 wrangler deploy が npm registry / esbuild / wrangler binary を CI 内で fetch する以上 未達。npm cache + lockfile pin で実用上の固定性は確保しているが、L4 認定には別途 sandboxed builder への移行が必要。優先度低。

運用

新規 deploy 対象を追加するとき

  1. sbom.ymlmatrix.target に追加。 label / workspace / out 3 フィールドだけ書けば SBOM artifact が自動生成される。
  2. 新 deploy workflow に
    • job レベル permissions:id-token: write + attestations: write
    • build step の後に actions/attest-build-provenance@v1 with subject-path
    を追加 (deploy-api-*.yml がリファレンス実装)。
  3. 本書の §SLSA Level 達成度 / §SHA pin 状態 を更新。

CVE が出たとき (緊急対応)

  1. Dependabot Alerts で影響範囲を確認。
  2. 直近の SBOM artifact (90 日保管)gh run download --name sbom-bundle-<sha> で取得し、 grype sbom:... で本番 build に乗っているか scan。
  3. 該当する場合、Dependabot PR を merge → deployment-rollback.html の hotfix 経路で deploy。
  4. 事後: postmortem template に従い AI を起こす。

許可 license の追加

dependency-review.ymlallow-licenses リストを編集。GPL/AGPL/SSPL 等の copyleft は 個別 PR で議論 してから追加すること。「うっかり混入」を防ぐため、CI fail を一次フィルタとして必ず通す。

follow-up

  • TODO attest-build-provenance / dependency-review-action の SHA pin 確定 (loose pin 解消)
  • TODO TruffleHog workflow 追加 (commit history full scan / 週次)
  • TODO CodeQL 有効化 (JS/TS の SAST)
  • TODO SBOM の release tag attach(GH Release 作成時に sbom-bundle を release asset として上げる)
  • TODO cosign verify-attestation の検証手順を scripts/audit/verify-attestation.sh として用意
View source on GitHub