Skip to content

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 time

Provenance Structure — in-toto Format

Cloud Build sử dụng in-toto Statement format:

json
{
  "_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 developer
  • resolvedDependencies: 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 provenanceSignerGoogle-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

yaml
# 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-attestor

Tạo Attestor từ Cloud Build Provenance

Cloud Build cung cấp built-in attestor cho SLSA provenance verification:

bash
# 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.attestorsVerifier

Verification 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 403

Policy SLSA Level Check

Binary Authorization có thể require SLSA level cụ thể:

yaml
# 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"

bash
# 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
yaml
# 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:

yaml
# 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:

yaml
# 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.

References