Skip to content

Organization Policy Framework & Inheritance

Tại sao Organization Policy quan trọng

IAM kiểm soát ai có quyền làm gì. Nhưng ngay cả với IAM chặt chẽ, một developer với quyền Compute Admin hợp lệ vẫn có thể vô tình tạo VM với external IP, tắt shielded boot, hay cho phép public access đến Cloud Storage bucket. Đây không phải lỗi IAM — người dùng đang dùng quyền của họ một cách hợp lệ. Nhưng từ góc nhìn organization security policy, đây là misconfiguration.

Organization Policies giải quyết vấn đề này bằng cách ràng buộc hành vi tạo và cấu hình tài nguyên ở tầng GCP resource management, phía trên IAM. Ngay cả khi một danh tính có quyền IAM đầy đủ, nếu action đó vi phạm org policy, GCP sẽ từ chối operation đó.

Tư duy đúng: Org Policy là guardrail của tổ chức — ràng buộc "what is allowed to be created", không phải "who can create it". IAM ràng buộc "who can do what", còn Org Policy ràng buộc "what kinds of resources/configurations are allowed to exist".

Internal Model: Constraint Framework

Constraint là gì?

Constraint là định nghĩa của một ràng buộc — một quy tắc về configuration cho phép hoặc không cho phép. Constraint xác định:

  • Resource types nó áp dụng lên (VMs, buckets, clusters, ...)
  • What can be controlled (external IP, boot disk encryption, ...)
  • Constraint type: List (danh sách giá trị) hay Boolean (bật/tắt)

Organization Policy là việc enforce một constraint tại một node trong resource hierarchy (organization, folder, project). Nói cách khác:

  • Constraint: "quy tắc" (definition)
  • Organization Policy: constraint đó được apply như thế nào tại một level cụ thể

Hai loại constraint chính

Boolean constraints: On/off switch. Chỉ có hai giá trị: enforced (true) hoặc not enforced (false).

yaml
# Ví dụ boolean constraint
name: projects/my-project/policies/compute.requireOsLogin
spec:
  rules:
    - enforce: true   # Bật OS Login requirement trên project này

List constraints: Định nghĩa một danh sách giá trị được phép hoặc bị cấm.

yaml
# Ví dụ list constraint
name: organizations/123456789/policies/compute.restrictCloudNATUsage
spec:
  rules:
    - denyAll: "TRUE"   # Block tất cả Cloud NAT usage
    # Hoặc:
    # - values:
    #     allowedValues:
    #       - "under:projects/allowed-project"
    #     deniedValues:
    #       - "is:projects/denied-project"

Managed vs Legacy constraints

Google đã giới thiệu thế hệ constraint mới gọi là managed constraints (trước đây gọi là new constraints). Sự khác biệt quan trọng:

Legacy managed constraints: Thế hệ cũ, sử dụng cú pháp constraints/SERVICE.CONSTRAINT_NAME. Inheritance là merge-based: policy từ parent và child được merge lại khi evaluate.

Managed constraints: Thế hệ mới (với prefix compute.managed., container.managed., etc.). Inheritance là override-based: policy tại child resource không được merge với parent — child policy tự nó là effective policy.

Đây là sự khác biệt cực kỳ quan trọng cho inheritance logic:

Organization: Deny all external IPs (legacy constraint)
    └── Folder: Allow external IPs for dev   (legacy)
            └── Project: Deny all external IPs (legacy)

LEGACY MERGE:
Effective policy tại Project = Organization DENY + Folder ALLOW + Project DENY
= Still DENY (DENY takes precedence in merge)

MANAGED CONSTRAINT:
Effective policy tại Project = Project policy only (override, no merge)
= DENY (chỉ xem project policy)

Behavior khác nhau này là nguyên nhân phổ biến gây confusion khi migration từ legacy sang managed constraints.

Policy Inheritance: Cơ Chế Lan Truyền

Hierarchy inheritance flow

Policies được áp dụng tại một node trong hierarchy và tự động kế thừa xuống tất cả descendants:

Organization (policies ở level này ảnh hưởng TẤT CẢ)
├── Folder: Engineering
│   ├── Folder: Production
│   │   ├── Project: prod-api        ← Kế thừa từ Engineering + Production + Org
│   │   └── Project: prod-db         ← Kế thừa từ Engineering + Production + Org
│   └── Folder: Staging
│       └── Project: staging-api     ← Kế thừa từ Engineering + Staging + Org
└── Folder: Operations
    └── Project: ops-tooling          ← Kế thừa từ Operations + Org

Merge semantics cho legacy constraints

Đối với legacy managed constraints, khi một resource có policies từ nhiều levels trong hierarchy, chúng được merge theo các quy tắc sau:

List constraints — Merge rules:

PolicyKết quả
Parent: denyAll, Child: không có policyEffective: denyAll (inherit)
Parent: allowAll, Child: denyAllEffective: denyAll (child overrides)
Parent: deny [A, B], Child: allow [C]Effective: deny [A, B] AND restrict to [C]
Parent: allow [A], Child: allow [B]Effective: allow [A OR B] (merge)

Quan trọng: Với legacy constraints, denyAll tại bất kỳ level nào luôn wins — không thể override bằng allowAll tại level thấp hơn (trừ khi dùng exceptions).

Boolean constraints — Merge rules:

Boolean constraints không có merge — boolean enforce tại bất kỳ level nào trong hierarchy đều enforce cho tất cả descendants.

Override vs merge cho managed constraints

Với managed constraints (thế hệ mới), không có merge. Policy tại node gần nhất với resource là effective policy:

Organization: managed constraint — restrict external IPs
└── Folder: managed constraint — allow external IPs for dev projects

Project trong Folder:
Effective policy = Folder's policy (allow external IPs)
Organization's policy bị OVERRIDE bởi Folder's policy

Đây là behavior khác với legacy constraints và phù hợp hơn với expectation của engineers khi setting policy hierarchy.

restoreDefault và inherit_from_parent

Khi muốn một resource không bị restrict bởi organization policy và thay vào đó inherit Google's default behavior:

yaml
# Reset về Google default (không inherit từ parent)
name: projects/my-project/policies/compute.requireOsLogin
spec:
  rules:
    - enforce: false  # Cho boolean
    # Hoặc dùng restoreDefault để không inherit từ parent:
  reset: true

Ngược lại, inheritFromParent: true trong legacy constraints cho phép một resource explicitly inherit từ parent thay vì define policy riêng.

Managed Constraints Quan Trọng Nhất

Compute Engine

ConstraintTypeMục đích
constraints/compute.vmExternalIpAccessListBlock external IPs cho VMs
constraints/compute.restrictCloudNATUsageListKiểm soát Cloud NAT usage
constraints/compute.requireOsLoginBooleanBắt buộc OS Login
constraints/compute.requireShieldedVmBooleanYêu cầu Shielded VM
constraints/compute.restrictLoadBalancerCreationForTypesListGiới hạn LB types
constraints/compute.restrictProtocolForwardingCreationForTypesListGiới hạn forwarding types
constraints/compute.skipDefaultNetworkCreationBooleanKhông tạo default network trong project mới
constraints/compute.restrictVpcPeeringListKiểm soát VPC peering partners

Google Kubernetes Engine

ConstraintTypeMục đích
constraints/container.restrictNfsFileVolumesBooleanBlock NFS volumes trong GKE
constraints/container.requireBinaryAuthorizationBooleanBắt buộc Binary Authorization
constraints/container.restrictClusterAdminBindingBooleanNgăn cluster-admin binding
constraints/container.restrictPrivateClustersBooleanBắt buộc private clusters
constraints/container.allowedContainerImagesListChỉ cho phép images từ trusted registries

Cloud Storage

ConstraintTypeMục đích
constraints/storage.publicAccessPreventionBooleanBlock public access toàn tổ chức
constraints/storage.uniformBucketLevelAccessBooleanBắt buộc uniform IAM (không ACL)
constraints/storage.retentionPolicySecondsListEnforce minimum retention period

IAM và Identity

ConstraintTypeMục đích
constraints/iam.disableServiceAccountCreationBooleanBlock SA creation trong project
constraints/iam.disableServiceAccountKeyCreationBooleanBlock SA key creation (enforce Workload Identity)
constraints/iam.allowedPolicyMemberDomainsListChỉ cho phép identities từ domain cụ thể
constraints/iam.restrictCrossProjectServiceAccountLivenessBooleanBlock service accounts cross-project

Exceptions với Resource Tags

Org Policy enforcement là uniform — áp dụng đều cho tất cả resources trong scope. Nhưng đôi khi cần exceptions: ví dụ, một project sandbox được phép dùng external IPs trong khi tổ chức cấm.

Resource Tags là cơ chế tạo conditional enforcement — policy chỉ áp dụng khi resource có (hoặc không có) một tag cụ thể:

yaml
# Org Policy với conditional enforcement based on tag
name: organizations/123456789/policies/compute.vmExternalIpAccess
spec:
  rules:
    # Rule 1: Nếu có tag "env=prod" → deny all external IPs
    - condition:
        expression: "resource.matchTag('env', 'prod')"
      denyAll: "TRUE"
    # Rule 2: Nếu có tag "env=dev" → allow external IPs
    - condition:
        expression: "resource.matchTag('env', 'dev')"
      allowAll: "TRUE"
    # Rule 3: Default cho mọi resource khác
    - denyAll: "TRUE"

Quan trọng về tag-based exceptions:

  1. Tags phải được defined ở level phù hợp trong hierarchy (tag keys tại organization level)
  2. Tags gắn vào resource phải được set trước khi policy được evaluate
  3. Tag conditions dùng CEL expression với các functions được support bởi Org Policy (resource.matchTag(), resource.matchTagId())

Khi nào dùng tag-based exceptions vs. folder-based isolation

Cách 1: Folder-based isolation (đơn giản hơn)
Organization
├── Folder: Production  ← Apply strict policies
│   └── Projects: prod-*
└── Folder: Development  ← Relaxed policies
    └── Projects: dev-*

Cách 2: Tag-based exceptions (flexible hơn nhưng phức tạp hơn)
Organization  ← Apply strict policies cho tất cả
├── Projects: prod-* (tag: env=prod) → inherit strict policy
└── Projects: dev-* (tag: env=dev)   → tag exception cho phép external IPs

Folder-based isolation đơn giản hơn để quản lý. Tag-based phù hợp khi project không thể được tổ chức vào folders rõ ràng, hoặc khi cần granular exceptions ở resource level (một VM cụ thể, không phải cả project).

Không-retroactive Enforcement

Một đặc điểm quan trọng của Org Policies: chúng không áp dụng retroactively cho resources đã tồn tại.

Ví dụ: Nếu bạn apply constraint compute.vmExternalIpAccess: denyAll, các VMs đang chạy với external IPs sẽ không bị tự động remove external IPs. Policy chỉ có effect với:

  • Resources mới được tạo (CREATE operations)
  • Thay đổi cấu hình (UPDATE operations) trên resources hiện tại, nhưng chỉ cho trường bị constraint

Điều này có thể tạo ra một trạng thái drift: policy nói "không được có external IPs" nhưng 50 VMs vẫn có external IPs từ trước khi policy được apply.

Để phát hiện drift, dùng Cloud Asset Inventory để query resources đang vi phạm policy:

bash
# Tìm tất cả VMs có external IPs trong organization
gcloud asset search-all-resources \
  --scope=organizations/123456789 \
  --asset-types=compute.googleapis.com/Instance \
  --query="accessConfigs.natIP:*" \
  --format=json

References