GCP for DevOps — Binary Authorization

2 minute read

Binary Authorization

Binary Authorization ensures only trusted container images are deployed to GKE and Cloud Run. It verifies cryptographic attestations created during the CI/CD pipeline before allowing deployment.

How Binary Authorization Works

Binary Authorization Flow:
┌──────────┐    ┌──────────────┐    ┌──────────────┐
│ Cloud      │    │ Attestor      │    │ Binary        │
│ Build      │───▶│               │───▶│ Authorization │
│            │    │ Signs image   │    │               │
│ Build +    │    │ with          │    │ Verify        │
│ Test       │    │ attestation   │    │ attestation   │
│ image      │    │               │    │ before deploy │
└──────────┘    └──────────────┘    └──────────────┘
                                           │
                                     ┌─────┴─────┐
                                     │ ✓ Deploy  │ ✗ Block │
                                     │ (signed)  │ (unsigned)│
                                     └─────┬─────┘
                                           │
                                     ┌─────▼─────┐
                                     │ GKE / Run   │
                                     └───────────┘

Enable Binary Authorization

# Enable the API
$ gcloud services enable binaryauthorization.googleapis.com

# Enable Binary Authorization on a GKE cluster
$ gcloud container clusters update my-cluster \
    --region=us-central1 \
    --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE

# Enable on Cloud Run
$ gcloud run services update my-service \
    --binary-authorization=default \
    --region=us-central1

Create an Attestor

# Create a Container Analysis note
$ cat > note.json << 'EOF'
{
  "attestation": {
    "hint": {
      "humanReadableName": "Build Verification"
    }
  }
}
EOF

$ curl -X POST \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    --data-binary @note.json \
    "https://containeranalysis.googleapis.com/v1/projects/my-project/notes/?noteId=build-note"

# Generate a key pair
$ gpg --batch --gen-key <<EOF
Key-Type: RSA
Key-Length: 4096
Name-Real: build-attestor
Name-Email: build@example.com
%no-protection
%commit
EOF

# Export public key
$ gpg --armor --export build@example.com > public.pgp

# Create the attestor
$ gcloud container binauthz attestors create build-attestor \
    --attestation-authority-note=build-note \
    --attestation-authority-note-project=my-project

# Add the public key
$ gcloud container binauthz attestors public-keys add \
    --attestor=build-attestor \
    --pgp-public-key-file=public.pgp

Create Attestations in CI/CD

# After building and testing, create an attestation
$ IMAGE_DIGEST=$(gcloud container images describe \
    gcr.io/my-project/my-app:v1 \
    --format='get(image_summary.digest)')

$ gcloud container binauthz attestations sign-and-create \
    --artifact-url="gcr.io/my-project/my-app@${IMAGE_DIGEST}" \
    --attestor=build-attestor \
    --attestor-project=my-project \
    --keyversion-project=my-project \
    --keyversion-location=global \
    --keyversion-keyring=my-keyring \
    --keyversion-key=attestor-key \
    --keyversion=1

Configure the Policy

# Export the current policy
$ gcloud container binauthz policy export > policy.yaml
# policy.yaml
admissionWhitelistPatterns:
  - namePattern: "gcr.io/google_containers/*"
  - namePattern: "gcr.io/google-containers/*"
  - namePattern: "k8s.gcr.io/**"
  - namePattern: "gke.gcr.io/**"
defaultAdmissionRule:
  evaluationMode: REQUIRE_ATTESTATION
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
  requireAttestationsBy:
    - projects/my-project/attestors/build-attestor
globalPolicyEvaluationMode: ENABLE
# Import the updated policy
$ gcloud container binauthz policy import policy.yaml

Verify Deployment

# Try to deploy an unsigned image (should be blocked)
$ kubectl run unsigned --image=gcr.io/my-project/unsigned-app:v1
# Error: Denied by Binary Authorization policy

# Deploy a signed image (should succeed)
$ kubectl run signed --image=gcr.io/my-project/my-app@sha256:abc123...
# pod/signed created

Common Mistakes

Mistake Why It’s Wrong Fix
No whitelist for system images GKE system pods blocked Whitelist GKE system images
Using tags instead of digests Tags are mutable Always use image digests
No break-glass procedure Can’t deploy in emergencies Set up dry-run or override policy
Single attestor Single point of trust Use multiple attestors (build + security)
Not logging denials Can’t troubleshoot Enable audit logging

Quick Reference

Command Description
gcloud container binauthz attestors create Create attestor
gcloud container binauthz attestations sign-and-create Create attestation
gcloud container binauthz policy export Export policy
gcloud container binauthz policy import Import policy
gcloud container clusters update --binauthz-evaluation-mode Enable on cluster

Next → KMS & Encryption

Updated: