Skip to content

Security: ChrisInvictus/paved-org

Security

SECURITY.md

Security

Reporting a vulnerability

This is a demonstration repository, but it manages a real (demo-scale) GCP organization. If you find a vulnerability in the Terraform, the pipeline configuration, or the demo application, please open a GitHub issue — there is no sensitive production data behind any of it, so public disclosure is acceptable and fastest. If you believe you've found something sensitive despite that (e.g., a leaked identifier that shouldn't be here), use GitHub's private vulnerability reporting on this repository instead.

Threat model

Scope: this document models the organization this repo builds — a demo-scale GCP org with a GitOps control plane and one zero-trust workload. It is deliberately honest about scale; controls that only make sense with more workloads, people, or data are listed as accepted gaps, not silently omitted.

Trust boundaries

        ┌────────────────────────────── GitHub ──────────────────────────────┐
        │  PR authors ──> branch ──> [B1: review + plan + lint gates] ──> main │
        └───────────────────────────────────│─────────────────────────────────┘
                                     OIDC token (short-lived)
                                            │
        ┌────────────────────── [B2: WIF trust condition] ────────────────────┐
        │            deployer SA (least-privilege, keyless, no org-IAM write) │
        └───────────────────────────────────│─────────────────────────────────┘
                                            │ terraform apply
        ┌──────────────────────── GCP organization root ──────────────────────┐
        │  org policies (inherited, unremovable from below)                    │
        │  ├── /workloads  [B3: folder boundary]                               │
        │  │     └── vended project ── Cloud Run                               │
        │  └── /sandbox                     ▲                                  │
        │                        [B4: LB + IAP — identity-checked ingress]     │
        └───────────────────────────────────│─────────────────────────────────┘
                                         internet

Assets, in priority order

  1. The organization control plane — org policies and org IAM. Compromise here defeats everything below.
  2. The deployment identity (WIF pool + deployer SA) — the only identity that changes infrastructure.
  3. Terraform state (versioned GCS bucket) — an infrastructure map and a tamper target.
  4. The workload and its ingress — lowest value by design; it holds no data.

Primary threats and their controls

Threat Boundary Control
Stolen long-lived credential used to modify infrastructure B2 No such credential exists: iam.disableServiceAccountKeyCreation org-wide; deployment is OIDC→WIF with minutes-lived tokens
A fork or unrelated repo assuming the deployer identity B2 WIF attribute condition pins the exact owner/repo claim
Compromised pipeline escalating its own privilege B2 Deployer holds no setIamPolicy on the org; its own role bindings are human-granted and imported — self-escalation is structurally absent
Malicious or mistaken change reaching the org B1 plan-on-PR renders every change for review; apply only from main; ruleset requires green checks (enforced on public repos)
Workload misconfiguration (public bucket, public IP, default network, over-privileged default SA) org root The seven policy constraints — violations are unrepresentable, not reviewed
Anonymous or unauthorized access to the workload B4 No public ingress path exists: Cloud Run accepts LB traffic only, IAP authenticates every request, invoker is granted solely to IAP's service agent, access is allow-listed per identity
Cross-project blast radius from a misbehaving workload B3 Factory vends into folders, never the org root; a workload's maximum scope is its own project
Silent tampering / repudiation org root Org-level audit sink (include_children = true) captures every admin action, including the pipeline's own applies; state bucket versioning preserves every state transition

Disclosure policy

Two classes of information appear in this repository's evidence and pipeline output, with two rules:

  • Numeric resource identifiers (organization, billing account, project, folder) are treated as non-secret: they are names, not credentials; a live plan-on-PR pipeline necessarily displays them in public comments and workflow logs, and no identifier grants access absent IAM.
  • Personal-linking artifacts (user emails, personal domains) are redacted from evidence by policy and supplied to the pipeline as masked secrets, never committed.

Accepted risks (deliberate, at this scale)

  • Single human super-admin, no group-based IAM or breakglass. One-person directory; the folder layout leaves room for both.
  • No VPC Service Controls / data-exfiltration perimeter. There is no data to exfiltrate; the perimeter is the next layer in a real deployment and nothing here conflicts with it.
  • No Security Command Center. Preventive controls only; detective posture management is production scope (see the sister repo, CloudCanary, for the detection side of this argument).
  • State bucket uses Google-managed encryption, no CMEK; registry likewise. Key-management lifecycle adds operational surface with no threat-model benefit at demo scale — each is marked in-code with a #checkov:skip and rationale.
  • Pipeline self-manages its identity plumbing (pool, provider, SA) — a documented tradeoff versus leaving those resources as unmanaged drift; the compensating control is that org-IAM write is withheld.
  • Single environment, no promotion gates. One org, one lane; multi-env is roadmap.

The pattern behind every row above: a control was omitted because the asset it protects doesn't exist here yet — not because the control is unknown. Where that changes, the roadmap names the control.

There aren't any published security advisories