SLSA Attestation & Binary Authorization Integration
Tại sao Supply Chain Security quan trọng
Build pipeline là attack vector nguy hiểm nhất trong modern software deployment. Không phải CVE trong production application — mà là compromise ở CI/CD pipeline cho phép attacker inject malicious code vào artifacts trước khi code đến production.
Vấn đề cụ thể: Nếu ai đó compromise CI/CD system và thay đổi build script để inject backdoor vào Docker image — làm sao bạn biết image production đang chạy là image đã được build từ source code approved, không phải image bị tamper?
SLSA (Supply-chain Levels for Software Artifacts) và Build Provenance giải quyết câu hỏi này bằng cryptographic evidence: "Image này được build bởi Cloud Build, từ source code commit X, tại thời điểm Y, và signature này không thể bị forged bởi build script hay developer bình thường."
SLSA Framework — Bốn Mức Bảo Đảm
SLSA định nghĩa progressive security levels cho software supply chain:
SLSA Level 1: Build process được document. Provenance được generate. Không yêu cầu authenticated hay tamper-proof.
- Giá trị: Traceability cơ bản, biết image được build từ gì
- Limitation: Developer có thể forge provenance
SLSA Level 2: Build chạy trên hosted build service. Provenance được authenticated bởi build service (không phải developer).
- Giá trị: Không thể inject provenance giả vào trusted build service
- Requirement: Build service phải generate và sign provenance
SLSA Level 3: Build service là hardened và isolated. Provenance non-forgeable ngay cả từ build service administrator.
- Giá trị: Attacker với quyền admin trong project không thể tạo provenance cho build không xảy ra thực sự
- Requirement: Isolated build environments, 2-party review cho build infrastructure
SLSA Level 4 (deprecated trong SLSA v1.0): Reproducible builds, hermetic builds.
Cloud Build đạt SLSA Level 3 cho Google-hosted workers. Với private worker pools, đạt L2 (vì pool có thể bị configure bởi customer, giảm isolation guarantee).
Cloud Build Provenance — Cơ Chế Bên Trong
Provenance Generation Flow
Khi build push image lên Artifact Registry:
1. Build hoàn thành và Docker image push thành công
↓
2. Cloud Build gọi internal provenance service
↓
3. Provenance service thu thập metadata:
- Image digest (sha256:...)
- Source repository URL và commit SHA
- Build trigger ID và configuration
- Builder identity
- Build start/end timestamps
- System substitutions
↓
4. Provenance được sign bằng Google-managed key
(key này không accessible bởi customer hay build script)
↓
5. Signed provenance lưu vào Artifact Registry
như Artifact Analysis occurrence
↓
6. Binary Authorization có thể verify signature tại deploy timeProvenance Structure — in-toto Format
Cloud Build sử dụng in-toto Statement format:
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "https://slsa.dev/provenance/v1",
"subject": [
{
"name": "us-central1-docker.pkg.dev/my-project/my-repo/myapp",
"digest": {
"sha256": "abc123def456..."
}
}
],
"predicate": {
"buildDefinition": {
"buildType": "https://cloudbuild.googleapis.com/CloudBuildYaml@v0.1",
"externalParameters": {
"buildConfigSource": {
"path": "cloudbuild.yaml",
"ref": "refs/heads/main",
"repository": "https://github.com/my-org/my-repo"
}
},
"internalParameters": {
"systemSubstitutions": {
"BUILD_ID": "a1b2c3d4-...",
"PROJECT_ID": "my-project",
"COMMIT_SHA": "abc123...",
"BRANCH_NAME": "main"
}
},
"resolvedDependencies": [
{
"uri": "git+https://github.com/my-org/my-repo",
"digest": { "sha1": "abc123..." }
}
]
},
"runDetails": {
"builder": {
"id": "https://cloudbuild.googleapis.com/GoogleHostedWorker@v1"
},
"metadata": {
"invocationId": "projects/my-project/locations/us-central1/builds/a1b2c3d4",
"startedOn": "2025-01-01T00:00:00Z",
"finishedOn": "2025-01-01T00:05:00Z"
}
}
}
}Field quan trọng:
subject.digest.sha256: Image digest. Provenance gắn chặt với digest cụ thể, không phải tag (tag có thể point đến khác digest)builder.id:GoogleHostedWorker— chứng minh build chạy trên Google infrastructure, không phải local machine của developerresolvedDependencies: Source code commit SHA — traceability về code nào được build
DSSE Signing — Tại sao Không Thể Forge
DSSE (Dead Simple Signing Envelope) là format để sign arbitrary payloads. Cloud Build sign provenance theo format:
DSSE Envelope:
{
"payload": base64(provenance JSON),
"payloadType": "application/vnd.in-toto+json",
"signatures": [
{
"keyid": "provenanceSigner",
"sig": base64(ECDSA_P256_signature)
}
]
}Key provenanceSigner là Google-managed key được lưu trong Cloud KMS internal của Google. Customer không có access đến key này. Build script, dockerfile, hay developer không thể tạo valid signature với key này.
Đây là tại sao SLSA L3 được đảm bảo: ngay cả nếu attacker compromise CI/CD configuration, họ không thể tạo forged provenance với valid signature. Binary Authorization verify signature và sẽ reject forged provenance.
Binary Authorization Integration
Binary Authorization là GKE admission webhook verify policies về images trước khi Pod được deploy (xem thêm Chapter 34).
Tích hợp với Cloud Build provenance:
Policy Require Provenance
# binary-authorization-policy.yaml
defaultAdmissionRule:
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
evaluationMode: REQUIRE_ATTESTATION
requireAttestationsBy:
- projects/my-project/attestors/cloud-build-attestor
clusterAdmissionRules:
us-central1.my-prod-cluster:
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
evaluationMode: REQUIRE_ATTESTATION
requireAttestationsBy:
- projects/my-project/attestors/cloud-build-attestorTạo Attestor từ Cloud Build Provenance
Cloud Build cung cấp built-in attestor cho SLSA provenance verification:
# Import Cloud Build public key cho attestor
gcloud container binauthz attestors create cloud-build-attestor \
--attestation-authority-note=projects/my-project/notes/cloud-build \
--attestation-authority-note-public-key-id=//cloudkms.googleapis.com/projects/my-project/locations/global/keyRings/cloud-build/cryptoKeys/attestation-key/cryptoKeyVersions/1
# Hoặc dùng built-in Cloud Build attestor (GCP-managed)
gcloud container binauthz attestors add-iam-policy-binding cloud-build-attestor \
--member=serviceAccount:service-PROJECT_NUMBER@gcp-sa-binaryauthorization.iam.gserviceaccount.com \
--role=roles/binaryauthorization.attestorsVerifierVerification Flow tại Deploy Time
kubectl apply -f deployment.yaml
↓
GKE API Server nhận request
↓
Binary Authorization Admission Webhook triggered
↓
1. Extract image reference từ Pod spec
2. Resolve tag → digest (nếu dùng tag)
↓
3. Lookup attestations trong Artifact Analysis
cho image digest đó
↓
4. Verify signature của provenance attestation
bằng attestor public key
↓
5. Check provenance meets policy:
- builder.id = GoogleHostedWorker?
- Source từ approved repo?
- Build trong approved project?
↓
6a. PASS: Pod được create
6b. FAIL: Pod rejected với 403Policy SLSA Level Check
Binary Authorization có thể require SLSA level cụ thể:
# Chỉ chấp nhận images built tại SLSA L3 bởi Cloud Build
defaultAdmissionRule:
evaluationMode: REQUIRE_ATTESTATION
requireAttestationsBy:
- projects/my-project/attestors/slsa-l3-attestor
# Platform policy (Global policy — không per-project)
checkSetPolicy:
checks:
- sigstoreSignatureCheck:
sigstoreAuthorities:
- displayName: Cloud Build SLSA
publicKeySet:
publicKeys:
- keyData: |
-----BEGIN PUBLIC KEY-----
...Google Cloud Build public key...
-----END PUBLIC KEY-----Custom Attestors — Thêm Verification Gates
Ngoài provenance tự động từ Cloud Build, bạn có thể tạo custom attestors để enforce additional checks:
Ví dụ: Attestation "vulnerability scan passed"
# Tạo attestor
gcloud container binauthz attestors create vuln-scan-passed \
--attestation-authority-note=projects/my-project/notes/vuln-scan
# Tạo KMS key để sign attestation
gcloud kms keyrings create binauthz-keyring --location=us-central1
gcloud kms keys create vuln-scanner-key \
--location=us-central1 \
--keyring=binauthz-keyring \
--purpose=asymmetric-signing \
--default-algorithm=ec-sign-p256-sha256
# Trong CI pipeline: sau vulnerability scan, sign attestation nếu passed
DIGEST=$(gcloud artifacts docker images describe \
us-docker.pkg.dev/my-project/my-repo/myapp:$TAG \
--format='value(image_summary.digest)')
VULN_COUNT=$(gcloud artifacts docker images list-vulnerabilities \
us-docker.pkg.dev/my-project/my-repo/myapp@$DIGEST \
--filter='vulnerability.severity=CRITICAL' \
--format='value(name)' | wc -l)
if [ "$VULN_COUNT" -eq 0 ]; then
gcloud container binauthz attestations sign-and-create \
--attestor=vuln-scan-passed \
--artifact-url=us-docker.pkg.dev/my-project/my-repo/myapp@$DIGEST \
--keyversion=projects/my-project/locations/us-central1/keyRings/binauthz-keyring/cryptoKeys/vuln-scanner-key/cryptoKeyVersions/1
fi# Policy yêu cầu CẢ HAI attestations
defaultAdmissionRule:
evaluationMode: REQUIRE_ATTESTATION
requireAttestationsBy:
- projects/my-project/attestors/cloud-build-attestor # SLSA L3 provenance
- projects/my-project/attestors/vuln-scan-passed # No critical CVEsĐây là separation of duties: Cloud Build signing key (Google-managed) và vulnerability scanner key (customer-managed) là hai keys khác nhau. Attacker phải compromise cả hai để bypass policy.
Attestation Workflow End-to-End
Developer push code
→ PR review → Merge to main
↓
Cloud Build Trigger fires
↓
Build chạy trên Google-hosted worker (SLSA L3)
- npm test / go test / ...
- docker build
- docker push → us-docker.pkg.dev/.../myapp:$COMMIT_SHA
↓
Cloud Build: auto-generate SLSA provenance
- Signed với Google-managed provenanceSigner key
- Lưu vào Artifact Registry as Artifact Analysis note
↓
Artifact Registry: auto vulnerability scan
↓
CI script check scan results:
- No critical vulnerabilities?
↓ YES
Sign vulnerability attestation với custom key
- Lưu vào Artifact Analysis
↓
Notify deploy pipeline: "image $DIGEST ready"
↓
Deploy pipeline runs: kubectl set image deployment/myapp myapp=...@sha256:$DIGEST
↓
GKE Binary Authorization checks:
1. Verify SLSA provenance (Google signature)
2. Verify vuln-scan attestation (custom signature)
3. Check builder.id == GoogleHostedWorker
4. Check source repo == approved repos
↓ ALL PASS
Pod created ✓Limitations và Edge Cases
Provenance chỉ cho Artifact Registry, không phải GCR
Provenance không được generate khi push vào gcr.io. Phải migrate sang REGION-docker.pkg.dev để có provenance.
Docker Push Manual Blocks Provenance
Nếu cloudbuild.yaml dùng explicit docker push step, Cloud Build có thể không generate provenance tự động. Dùng images: field thay:
# Sai: explicit push
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-docker.pkg.dev/my-project/repo/app:$COMMIT_SHA', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-docker.pkg.dev/my-project/repo/app:$COMMIT_SHA']
# Đúng: dùng images field → Cloud Build auto push VÀ generate provenance
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-docker.pkg.dev/my-project/repo/app:$COMMIT_SHA', '.']
images:
- 'us-docker.pkg.dev/my-project/repo/app:$COMMIT_SHA'Private Worker Pool Giảm SLSA Level
Private worker pool mà customer quản lý hardware pool → builder identity là khác với GoogleHostedWorker. Attestation vẫn được generate nhưng SLSA guarantee giảm từ L3 xuống L2 vì infrastructure không được Google kiểm soát hoàn toàn.
Tag vs Digest trong Policy
Binary Authorization verify theo digest, không phải tag. Dùng digest trong deployment manifests:
# Không tốt: tag có thể point đến image khác sau deploy
image: us-docker.pkg.dev/my-project/repo/app:latest
# Tốt: digest là immutable
image: us-docker.pkg.dev/my-project/repo/app@sha256:abc123def456...Với digest pinning, Binary Authorization verify đúng image được attested, không phải image khác được tag với tên đó sau khi attestation được tạo.