[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
---
|
||||
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 <pkg> --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]]
|
||||
Reference in New Issue
Block a user