A GCP organization baseline as code: org-wide guardrails, a project factory that vends secure-by-default projects, and a zero-trust workload driving on the paved road — IAP-protected, deployed via a keyless WIF pipeline. Prevention half of CloudCanary.
At a glance: org policies that make insecure states unrepresentable · a project factory vending secure-by-default projects · zero exported keys anywhere (keyless WIF/OIDC end-to-end) · a zero-trust workload (IAP) as living proof · extended into agentic AI: an ai-guardrails module, AI-workload detection in its sister project, and a published MCP trust-boundary threat model (v1.1 — STRIDE × OWASP LLM Top 10 2025, multi-agent extension) with a two-part applied security runbook. Detection half: CloudCanary.
Most organizations bolt security onto projects after they exist — a scanner here, a review checklist there, a policy document nobody reads. paved-org makes the organization itself the security boundary. Org policy constraints are enforced at the root and inherited by everything below; the project factory vends projects that are hardened before their first API call. Insecure states aren't forbidden by policy documents — they're unrepresentable in the platform.
Everything here is Terraform, deployed through a GitOps pipeline (plan-on-PR, apply-on-merge) that authenticates to GCP with zero exported service-account keys.
Act 1: THE PAVEMENT (org layer)
GCP Organization
├── Org policies (Terraform): the secure-by-default constraint set
├── Folder hierarchy: /workloads, /sandbox
└── Project factory module: vends pre-hardened projects
(baseline APIs, logging sink, no default network,
no default-SA editor grant, labels, budget guard)
Act 2: THE KEYLESS ROAD (deployment identity)
GitHub Actions ──OIDC──> Workload Identity Federation pool
└── deploys everything with ZERO exported service-account keys
plan-on-PR · apply-on-merge · state in a versioned GCS bucket
Act 3: THE WORKLOAD (zero trust in action)
A vended project runs a tiny demo app (Cloud Run)
└── fronted by Identity-Aware Proxy (IAP — Google's ZTNA,
BeyondCorp lineage): no VPN, no public ingress,
every request identity-checked
The paved road — and a workload driving on it.
Seven organization policy constraints, each closing a class of misconfiguration (org/policies.tf, one-line threat model on each):
| Constraint | What it kills |
|---|---|
iam.disableServiceAccountKeyCreation |
The #1 GCP credential-theft vector: exported keys that never expire |
iam.automaticIamGrantsForDefaultServiceAccounts |
Default service accounts born with project Editor |
iam.allowedPolicyMemberDomains |
IAM grants to identities outside the org's directory |
compute.skipDefaultNetworkCreation |
The permissive default VPC in every new project |
compute.vmExternalIpAccess |
Internet-scannable VMs |
storage.uniformBucketLevelAccess |
Per-object ACL sprawl — the root cause of public-bucket incidents |
sql.restrictPublicIp |
Databases on the public internet |
A note on identity governance: modern GCP organizations are born with several of these pre-enforced by Google. paved-org imports those defaults into Terraform state rather than leaving them unmanaged — an unmanaged default is drift waiting to happen, and one of these constraints is tightened beyond Google's default. The full story is in docs/bootstrap.md.
The pipeline that enforces iam.disableServiceAccountKeyCreation authenticates without any key itself: GitHub's OIDC issuer vouches for each workflow run, and Workload Identity Federation exchanges that short-lived token for federated credentials. Trust is pinned to exactly one repository via an attribute condition; the deployer service account carries least-privilege org roles (org policy + folder administration — deliberately not organizationAdmin).
A governance layer that violated its own policies would be theater.
paved-org prevents what CloudCanary detects. Run both: prevention for the known, detection for the drift. The key-creation constraint above prevents the exact event CloudCanary's identity-drift canary alerts on.
Extending the prevention/detection thesis to AI workloads:
- MCP trust-boundary threat model — five boundaries (B1–B5), STRIDE × OWASP LLM Top 10 (2025), with an IAM lens and a multi-agent (agent ↔ agent) extension (v1.1).
- MCP security runbook — a two-part applied audit: a managed-connector host and a self-hosted agent gateway, with host hardening, a fail-closed exec-approval gate, and a staging-validated container.
modules/ai-guardrails— org-policy guardrails for AI workloads (verified canned constraints), the prevention half of what CloudCanary detects.
Built end-to-end on GCP free-trial credits. The org layer (policies, folders, WIF, state) is control-plane configuration and costs $0 to keep alive. The workload layer (Act 3) carries the one real cost — a global external HTTPS load balancer for IAP, ~$18/month — so it lives for roughly 48 hours: built, evidenced, then terraform destroyed.
The destroy/apply round trip is documented and repeatable. Reproducibility is the point — the repo's value is the code plus evidence, not a running demo. To rebuild from a bare domain, follow docs/bootstrap.md.
Tracked with status in docs/evidence/:
- ✅ Converged plan:
No changes. Your infrastructure matches the configuration. - ✅ Plan-on-PR and apply-on-merge: proposals rendered, merges becoming infrastructure — keyless throughout
- ✅ The platform refusing violations: an SA key request denied by org policy; the default compute SA born with zero privilege
- ✅ The vending machine: a hardened project created by a pull request
- ✅ Zero trust, proven both ways: IAP identity challenge and asserted identity on the allow path; 403 for an authenticated-but-unauthorized account
- ✅ Reproducibility: the paid layer destroyed through the same pipeline that built it
This is a demo-scale organization, and says so:
- No multi-environment promotion. One org, one state, one pipeline lane. Production would add dev/nonprod/prod folders with per-environment state and promotion gates.
- No Security Command Center integration. Production would wire SCC Premium for posture management and threat findings on top of these preventive controls.
- No VPC Service Controls. Data-exfiltration perimeters are the next layer of a real deployment; nothing here conflicts with adding them.
- Single-person directory. Group-based IAM (admin groups, breakglass procedures) is stubbed by design; the folder layout leaves room for it.
The full threat model, including accepted risks, is in SECURITY.md.
org/ Act 1 + 2: policies, folders, WIF, org logging — live
modules/project-factory/ Act 1: the vending machine — landing in Act 3
workloads/demo/ Act 3: vended project + Cloud Run + IAP — landing in Act 3
docs/ architecture, bootstrap guide, evidence
.github/workflows/ plan-on-PR, apply-on-merge, lint
Multi-env promotion · SCC integration · VPC-SC perimeter · group-based IAM & breakglass · budget guard as a factory default · Terraform tests (terraform test) for the factory module.
MIT