Skip to content

Organization Policies & Supply Chain Security

Tại sao quan trọng

Bạn đã learn Cloud Build, Artifact Registry, và deployments. Nhưng ở organization level, bạn cần lock down toàn bộ CI/CD pipeline.

Scenario: Một team member có thể:

bash
# Connect Cloud Build to arbitrary GitHub repo?
# (ngoài org's control)

# Push images without vulnerability scanning?

# Deploy directly without approval?

Nếu không có organization policies, answers có thể "yes" — mở rộng supply chain risk.

Organization policies (từ Chương 33) apply enforcement across projects: không cho phép builds kết nối to unauthorized external systems, enforce security practices, ensure compliance.


allowedIntegrations Policy

Policy Overview

compute.skipDefaultNetworkCreation là tổng quát. Cho CI/CD, critical policy là allowedIntegrations.

Organization Policy: Cloud Build > allowedIntegrations

Controls: Which external systems Cloud Build triggers có thể connect to

Default: All allowed (unrestricted)

Secure: Only allow specific integrations (Cloud Source Repos, approved GitHub orgs)

Cloud Build Integration Points

Cloud Build có thể trigger từ / connect to:

  1. Cloud Source Repositories (internal, controlled by Google)
  2. GitHub (external, managed by third party)
  3. GitLab (external)
  4. Bitbucket (external)
  5. Manual webhook (arbitrary external systems)

Risk per integration:

Cloud Source Repos: ✓ Low risk (Google-managed, inside GCP)

GitHub Public Repos: ⚠ Medium risk
  - Repo visibility may change
  - Collaborators may add malicious code
  
GitHub Private Repos: ⚠ Medium risk (same as public)

GitLab: ⚠ Medium risk (third-party, less control)

Bitbucket: ⚠ Medium risk

Webhooks: ✗ High risk (arbitrary external trigger)
  - Attacker can trigger builds
  - Builds execute with full permissions

Setting allowedIntegrations Policy

yaml
# org-policy.yaml (at organization level)
constraint: compute.allowedIntegrations
listPolicy:
  allowedValues:
    - "cloudsourcerepos.googleapis.com"
    - "github.com:myorg"  # Only this GitHub org

Deployment:

bash
# Apply policy to organization
gcloud resource-manager org-policies set-policy org-policy.yaml \
  --project=my-project

Policy Evaluation

After policy applied:

Scenario 1: Try to connect Cloud Build to myorg/myrepo on GitHub
  ├─ Policy checks: "github.com:myorg" ✓ in allowedIntegrations
  └─ ALLOWED

Scenario 2: Try to connect to externalorg/externalrepo on GitHub
  ├─ Policy checks: "github.com:externalorg" ✗ NOT in allowedIntegrations
  └─ DENIED

Scenario 3: Try to create webhook trigger
  ├─ Policy checks: webhooks not in allowedIntegrations
  └─ DENIED

Identity Verification for External Integrations

Nếu bạn allow GitHub integrations, organization still needs to verify:

Question: "Is commit từ legitimate GitHub account, or forked repo?"

Solution: Branch protection + required status checks

bash
# GitHub repository settings
# Branch: main
# - Require status checks before merging
# - Dismiss stale pull request approvals
# - Require code reviews from code owners
# - Require branches to be up to date

Cloud Build level:

yaml
# cloudbuild.yaml — log who triggered build
steps:
  - name: 'gcr.io/cloud-builders/git'
    args: ['log', '-1', '--format=%an <%ae>']
    # Output: "John Doe <john@example.com>" — verify against allowed committers

Service Account Policies

Beyond allowedIntegrations, lock down service accounts used:

yaml
# Constraint: iam.serviceAccountUser
# Effect: Only specific service accounts có thể be used for builds
constraints:
  - serviceaccount: "cloud-build@my-project.iam.gserviceaccount.com"
    roles:
      - roles/container.developer  # Can deploy to GKE
      - roles/artifactregistry.writer

Supply Chain Security Audit Trail

Để maintain audit trail:

bash
# Log tất cả Cloud Build activities
gcloud logging read "resource.type=cloudbuild" \
  --limit=100 \
  --format=json

Key logs to audit:

  1. Build triggers modified: Who changed trigger configuration?
  2. Service account roles changed: New permissions granted?
  3. Deployments initiated: Who triggered deployment?
  4. Builds that failed: Which builds failed, and why?

Example query:

bash
# Find all builds triggered from external repos
gcloud logging read "resource.type=cloudbuild AND sourceRepo != 'cloud-source-repositories'" \
  --format=json | jq '.[] | {timestamp, sourceRepoUrl, buildId, result}'

Real-World: Hardened CI/CD Organization Policy

Scenario

  • Organization: MyCorp
  • Security requirement: All deployments must be auditable, no unauthorized external triggers
  • Integrations: Only internal Cloud Source Repos + approved GitHub org

Policy Setup

1. Organization-level constraints:

yaml
# org-policies.yaml
constraints:
  - name: "compute.allowedIntegrations"
    listPolicy:
      allowedValues:
        - "cloudsourcerepos.googleapis.com"  # Internal
        - "github.com:mycorp"                # Only mycorp org
  
  - name: "iam.disableServiceAccountCreation"
    # Prevent creation of uncontrolled service accounts
    denyRule:
      deny: []
    allowRule:
      allow: []

2. Cloud Build service account with least privilege:

bash
# Create dedicated service accounts
gcloud iam service-accounts create cloud-build-ci \
  --display-name="Cloud Build CI Service Account"

# Grant only necessary permissions
gcloud projects add-iam-policy-binding my-project \
  --member=serviceAccount:cloud-build-ci@my-project.iam.gserviceaccount.com \
  --role=roles/artifactregistry.writer

gcloud projects add-iam-policy-binding my-project \
  --member=serviceAccount:cloud-build-ci@my-project.iam.gserviceaccount.com \
  --role=roles/container.developer

# Explicitly DENY dangerous roles
gcloud projects add-iam-policy-binding my-project \
  --member=serviceAccount:cloud-build-ci@my-project.iam.gserviceaccount.com \
  --role=roles/editor \
  --condition='resource.name != projects/my-project'

3. Build trigger configuration:

bash
gcloud builds triggers create github \
  --repo-owner=mycorp \
  --repo-name=myapp \
  --branch-pattern="^main$" \
  --build-config=cloudbuild.yaml \
  --service-account=cloud-build-ci@my-project.iam.gserviceaccount.com

4. Audit logging:

bash
# Enable Cloud Audit Logs
gcloud logging write audit-log '
{
  "event": "cloudbuild-deployment",
  "triggeredBy": "github.com:mycorp/myapp",
  "timestamp": "'$(date -u +'%Y-%m-%dT%H:%M:%SZ')'",
  "buildId": "'${BUILD_ID}'"
}' --severity=INFO

# Query audit trail
gcloud logging read "logName=projects/my-project/logs/audit-log" \
  --format=json --limit=50

Supply Chain Security Checklist

Before marking CI/CD as production-ready:

✓ Trigger sources validated
  └─ allowedIntegrations policy enforced
  └─ GitHub branch protection enabled
  └─ Cloud Source Repos used for sensitive code

✓ Build provenance enabled
  └─ requestedVerifyOption: VERIFIED ở cloudbuild.yaml

✓ Service account least privilege
  └─ Custom service accounts per build step
  └─ No default service account usage
  └─ Minimum IAM roles granted

✓ Artifact scanning enabled
  └─ Vulnerability scanning active
  └─ SBOM generated
  └─ No deployment of CRITICAL vulnerabilities

✓ Deployment gates implemented
  └─ Cloud Deploy approval gates
  └─ Binary Authorization enabled
  └─ Canary deployments for prod

✓ Audit trail enabled
  └─ Cloud Audit Logs capturing all CI/CD events
  └─ Retention policy set (e.g., 1 year)
  └─ Monitoring alerts for suspicious activity

✓ Organization policies enforced
  └─ allowedIntegrations configured
  └─ Service account creation restricted
  └─ Dangerous roles denied at org level

Common Misconfigurations

Misconfiguration 1: No allowedIntegrations Policy

Risk: Teams connect builds to random external GitHub repos

Mitigation: Enforce policy org-wide
gcloud resource-manager org-policies set-policy org-policy.yaml \
  --project=ORG_ID \
  --update-enforced-policy

Misconfiguration 2: Default Service Account Used

yaml
# cloudbuild.yaml — BAD
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', '...']
    # Uses default service account (too permissive)

Fix: Use explicit custom service account

yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    serviceAccount: 'projects/PROJECT/serviceAccounts/pusher@PROJECT.iam.gserviceaccount.com'
    args: ['push', '...']

Misconfiguration 3: No Approval Gates for Prod

bash
# Deploy automatically to production
gcloud deploy delivery-pipelines create app-pipeline \
  --config=deploy.yaml
  # Missing: requireApproval: true for prod stage

Fix:

yaml
serialPipeline:
  stages:
    - targetId: prod
      deployParameters:
        - requireApproval: true  # Explicit gate

References