Safeguard
Cloud Security

Automating Security Controls on Google Cloud

Binary Authorization can block every unsigned container from reaching GKE or Cloud Run — but only if your pipeline is wired to sign images the moment they pass scanning.

Safeguard Research Team
Research
7 min read

Binary Authorization, Google Cloud's deploy-time policy engine for GKE and Cloud Run, works on a single hard rule: an image without a valid cryptographic attestation from a designated attestor is refused admission, full stop, no exceptions unless you explicitly configure one. That single control point is the anchor for a much bigger idea — that security policy on Google Cloud doesn't have to live in a wiki page or a Slack reminder to "run the scanner before you deploy." It can live in code, evaluated automatically, on every build, using tooling GCP ships natively. Cloud Build auto-creates a built-in attestor at projects/PROJECT_ID/attestors/built-by-cloud-build the first time you run it, meaning a pipeline can sign an image immediately after it clears build, test, and scan stages, and Binary Authorization checks that signature at the cluster boundary before a single pod schedules. Layer in Artifact Registry's integrated Container Analysis vulnerability scanning, Organization Policy Service constraints applied hierarchically across projects and folders, and Google's own packaged offering — Software Delivery Shield — and you have most of the ingredients for a dev-to-prod policy-as-code chain without installing a third-party admission controller. This post walks through how those pieces actually connect, and where they still leave gaps a platform team has to fill.

What does Binary Authorization actually block, and where?

Binary Authorization enforces policy at exactly one moment: image admission into GKE or Cloud Run, not at build time and not at push time. A policy is attached to a project (or a cluster, for GKE) and specifies a default admission rule — typically "require attestations from attestor X" — plus optional per-cluster overrides. When the Kubernetes API server or Cloud Run tries to schedule a container, Binary Authorization intercepts the request, resolves the image to its digest, checks whether an attestation matching a required attestor exists for that digest, and denies the deployment if it doesn't, according to Google's own documentation. Because the check runs against the immutable digest rather than a mutable tag, an attacker who overwrites a :latest tag after the attestation was issued still gets blocked — the signature no longer matches. The rule is coarse by design: it answers "was this exact image approved," not "does this image meet policy today," which is why teams pair it with vulnerability data gathered earlier in the pipeline rather than relying on it as a scanning tool in its own right.

How does a Cloud Build attestor turn a scan result into an enforceable gate?

The mechanism is a private/public key pair (a "note" and "attestor" pair in Container Analysis terms) that Cloud Build uses to sign an image's digest once a build step succeeds. In the reference pattern documented by Google, a Cloud Build pipeline runs its normal build and test stages, calls a vulnerability scanning step against Artifact Registry's Container Analysis results, and only then invokes gcloud container binauthz attestations sign-and-create against the built-in built-by-cloud-build attestor (or a custom one you register) if the scan passed your threshold. Binary Authorization's admission check later verifies that signature cryptographically against the attestor's registered public key — it does not re-run the scan. That split matters operationally: the gate is enforced twice, once as a build-time decision ("should we sign this") and once as a deploy-time decision ("was this signed"), and an image that never went through the pipeline — pulled straight from a registry and deployed by hand — fails the second check even if nobody ever explicitly re-scanned it.

What role does Artifact Registry's vulnerability scanning play upstream of that gate?

Artifact Registry's Container Analysis integration scans container images on push and on a recurring basis afterward, storing CVE findings as metadata occurrences tied to the image digest — the same digest Binary Authorization later checks. This is the layer that actually produces the "should we sign this" answer for the attestor step: a Cloud Build pipeline can query the Container Analysis API for occurrences above a severity threshold and fail the build (skipping the sign-and-create step entirely) before Binary Authorization is ever consulted. Google surfaces this scanning as part of Software Delivery Shield, its packaged supply-chain security offering spanning the developer, supply, CI/CD, and production stages plus a policy layer that ties them together — the closest single-product analog Google Cloud offers to an end-to-end policy-as-code framework, according to Google's own product announcement. The scanning coverage itself is limited to what's declared in the OS package manager and language-ecosystem manifests baked into the image, which is why teams generating a full SBOM separately still get a more complete transitive-dependency picture than registry scanning alone provides.

Can policy reach further upstream, to the dependencies themselves?

Yes — Google's Assured Open Source Software (Assured OSS) service lets a team consume pre-vetted versions of popular OSS packages instead of pulling directly from public registries like PyPI or npm, at three increasing assurance levels: packages Google builds and signs itself, packages securely built from vetted source with attestation to their transitive dependencies, and packages that add continuous scanning and fuzzing across the full transitive-dependency closure, per Google's published service description. Wiring Assured OSS into a pipeline as the default package source — rather than a public registry — moves the policy gate from "did this dependency pass a scan after we already pulled it" to "was this dependency provenance-checked before it ever entered our build." That's a meaningfully different security posture: a typosquat or a compromised maintainer account on a public registry never reaches the build in the first place, rather than being caught (or missed) by a downstream scanner. It's also narrower in scope than general SCA — Assured OSS only covers the specific package set Google curates, so it complements rather than replaces dependency scanning across your full manifest.

Where does Organization Policy Service fit relative to pipeline-level gates?

Organization Policy Service is the layer beneath all of the above — it enforces constraints hierarchically across an entire organization, folders, and projects, independent of any single pipeline's configuration. Constraints like restricting external IP allocation on VMs or enforcing domain-restricted sharing on resources apply even if a given team's Cloud Build configuration never mentions them, and they can't be overridden by a project-level IAM grant unless an org admin explicitly carves out an exception, per Google's org-policy constraint reference. This is the difference between a guardrail a developer can accidentally bypass by editing a YAML file and one enforced by the platform regardless of what any individual pipeline does. In practice, mature Google Cloud security programs use Organization Policy Service for the constraints that must never vary by team — network exposure, resource location for data residency, service account key creation — and reserve pipeline-level gates like Binary Authorization for the checks that need build-specific context, like a specific CVE severity threshold for a specific application.

Where do native GCP controls stop, and where does a platform like Safeguard fit?

The native chain above is real and it works, but it stops at binary admission decisions per image — it doesn't give a security team one queryable view across every image, every policy, and every exception across a multi-cluster, multi-project estate, and it has no native concept of reachability (whether a flagged vulnerability is in code your image actually executes). Safeguard's guardrail model extends the same policy-as-code pattern — YAML-defined rules with BLOCK, WARN, or AUTO_FIX effects — across six enforcement points from IDE through CI, registry, admission, and runtime, and connects to Artifact Registry and GCR directly via a service account scoped to roles/artifactregistry.reader (Artifact Registry) or roles/storage.objectViewer (GCR) for SBOM generation and scanning, so the same image Binary Authorization gates gets a full CycloneDX SBOM and CVE reachability verdict rather than just a pass/fail scan result. The safeguard gate CLI step slots into the same Cloud Build pipeline that signs the Binary Authorization attestation, evaluating rules like "block if any KEV-listed critical CVE" or "require an SBOM attestation signed in the last 90 days" before that signature step ever runs — giving teams the audit trail and exception workflow that a bare attestor pair doesn't provide on its own.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.