--- id: devsec-supply-chain title: Supply Chain Security — SBOM / Sigstore / Provenance category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [devsecops, supply-chain, sbom, sigstore, vibe-coding] tech_stack: { language: "OSS / CI", applicable_to: ["DevOps"] } applied_in: [] aliases: [SBOM, Sigstore, cosign, SLSA, provenance, npm audit, dependency confusion] --- # Supply Chain Security > Log4Shell / xz / event-stream — 의존성이 공격 통로. **SBOM (재고) + Sigstore (서명) + SLSA (출처) + 자동 update**. xz 같은 sneak attack 방어. ## 📖 핵심 개념 - SBOM: 모든 의존성 list. - Sigstore: 서명 + transparency log. - SLSA: provenance 표준 (build 환경 attest). - Dependency confusion: public / private 같은 이름 충돌. ## 💻 코드 패턴 ### npm audit (기본) ```bash npm audit # 알려진 CVE npm audit fix # 자동 patch (minor) npm audit --production # prod 만 ``` ### Snyk / Dependabot ```yaml # .github/dependabot.yml version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: { interval: "weekly" } open-pull-requests-limit: 5 groups: production-dependencies: dependency-type: "production" development-dependencies: dependency-type: "development" ``` → 자동 PR + CVE patch. ### SBOM 생성 ```bash # CycloneDX (npm) npx @cyclonedx/cyclonedx-npm --output-format JSON > sbom.json # Syft (any) syft . -o cyclonedx-json > sbom.json syft . -o spdx-json > sbom-spdx.json # Container syft myapp:latest -o cyclonedx-json > sbom.json ``` → Compliance / 사고 시 추적. ### SBOM scan (CVE 검사) ```bash # Grype 가 SBOM 직접 검사 grype sbom:./sbom.json ``` ### Cosign (Sigstore signing) ```bash # Keyless (OIDC, GitHub Actions) cosign sign $REGISTRY/myapp:$TAG --yes # Verify cosign verify $REGISTRY/myapp:$TAG \ --certificate-identity 'https://github.com/myorg/myrepo/.github/workflows/release.yml@refs/heads/main' \ --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' ``` → 누가 / 어떤 commit 으로 build 했는지 검증. ### SLSA provenance (build attestation) ```yaml # .github/workflows/release.yml permissions: id-token: write contents: read attestations: write steps: - uses: docker/build-push-action@v5 with: provenance: mode=max sbom: true - uses: actions/attest-build-provenance@v1 with: subject-name: ghcr.io/myorg/myapp subject-digest: ${{ steps.build.outputs.digest }} ``` → Build 환경 자동 attest. ### npm package — provenance ```yaml # 자동 cosign signing - run: npm publish --provenance env: { NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} } ``` ```bash # 사용자 측 npm install --foreground-scripts=false ``` ### Lockfile 강제 ```yaml # CI - run: npm ci # not npm install — lockfile 정확 - run: yarn install --immutable - run: pnpm install --frozen-lockfile ``` → Lockfile 변경 시 CI 가 fail. ### Postinstall script 차단 (위험) ```bash # Worst case: 악성 postinstall npm install --ignore-scripts # package.json 으로 { "preinstall": "npx only-allow pnpm", // Yarn / npm 차단 } ``` ### Allowlist (private registry) ```bash # .npmrc @mycompany:registry=https://npm.mycompany.com # 그 외 = 외부 registry registry=https://registry.npmjs.org/ ``` → Public 에 같은 이름 (`@mycompany/lib`) 등록 = dependency confusion. ```jsonc // package.json — name 충돌 차단 { "name": "@mycompany/myapp", // public 에 가짜 등록 시 npm 가 우선 lookup → leak // → private registry 만 사용 } ``` ### Verify dependencies ```bash # 인기 도구 npx good-fences # boundary npx knip # unused npx depcheck # unused npx better-npm-audit npx ls-engines # node version compat ``` ### NPM token (CI / publish) ``` - Granular access tokens (특정 package 만) - 짧은 expiry - Repo secret 으로 (env 노출 X) ``` ### License 검사 ```bash license-checker --production --summary license-checker --excludePackages 'mit;apache-2.0' --failOn 'gpl-3.0;agpl-3.0' ``` → AGPL 같은 라이센스 prod 차단 (회사 정책). ### Vulnerability triage ``` 1. CVSS score 검토 (Critical, High) 2. 실제 attack vector 가능? - Local only? Network? Auth required? 3. 사용 경로 — 이 lib 의 vulnerable function 우리가 사용? 4. Patch 가능 여부 - Minor → 자동 - Major → manual review - 없음 → workaround / fork / replace ``` ### xz-style attack (long-term sneak) ``` 2024 xz 백도어 — 긴 시간 contributor build trust. 방어: - 새 contributor 코드 review 강 - Build script 변경 의심 - Reproducible build (다른 환경 같은 hash) - Binary diff vs source - Sigstore + SLSA = build provenance 검증 ``` ### Reproducible build ```dockerfile # 시간 / random 제거 FROM node:20-alpine WORKDIR /app COPY . . RUN SOURCE_DATE_EPOCH=$(date -d "2024-01-01" +%s) npm ci RUN find . -newer /app -exec touch -d "@$SOURCE_DATE_EPOCH" {} + ``` → 같은 source = 같은 binary hash. ### 정책 (CI) ```yaml - name: Audit run: npm audit --audit-level=high - name: License check run: license-checker --excludePackages '...' --failOn 'GPL-3.0;AGPL-3.0' - name: SBOM run: syft . -o cyclonedx-json > sbom.json - uses: actions/upload-artifact@v4 with: { name: sbom, path: sbom.json } ``` ### Compromised package detect ``` Socket.dev / Snyk 가 새 release 자동 분석 (suspicious behavior). - Network call 새로 - File system access 새로 - Postinstall 새로 ``` ## 🤔 의사결정 기준 | 작업 | 추천 | |---|---| | 자동 patch | Dependabot | | CVE 모니터링 | Snyk / GitHub Advanced Security | | SBOM | Syft (open) | | Signing | Cosign (Sigstore) | | Provenance | SLSA via GitHub attest | | Suspicious detect | Socket.dev | ## ❌ 안티패턴 - **Lockfile 무시**: `npm install` prod build. - **Audit ignore high**: 알면서 무시. - **Postinstall 모두 허용**: 임의 코드. - **Latest tag**: 새 release 가 깨짐. - **Private + public 같은 이름**: dependency confusion. - **NPM token long-lived**: leak 시 큰 영향. - **Build attestation 없음**: 출처 검증 X. ## 🤖 LLM 활용 힌트 - Lockfile + Dependabot + npm audit + SBOM. - Cosign + SLSA = supply chain integrity. - Private registry + scoped packages. ## 🔗 관련 문서 - [[DevSec_Container_Scanning]] - [[DevOps_CI_CD_Pipeline_Patterns]] - [[Security_Secrets_Management]]