Skip to content

Organization Policies: Ép buộc ràng buộc & tuân thủ

Tổng quan về Organization Policies

Organization Policies ép buộc các ràng buộc lên resources: "Developer không được xóa VM", "Storage phải được mã hóa"

Organization Policy:
"Developer cannot delete Compute Engine instances"

Áp dụng cho: Org → Folder → Project

Thực thi: Không developer nào được xóa instance (ngoại lệ: một số service account cụ thể)

Các loại constraint

1. Managed Constraints

Được Google xây sẵn, dùng ngay:

Các managed constraints phổ biến:
- compute.skipDefaultNetworkCreation
- compute.requireOsLogin
- compute.requireShieldedVm
- storage.uniformBucketLevelAccess
- iam.disableServiceAccountCreation

2. Custom Constraints

Do người dùng định nghĩa bằng CEL (Common Expression Language):

yaml
# Ví dụ: bắt buộc labels trên mọi resource
constraint:
  name: "require-resource-labels"
  display_name: "Require resource labels"
  description: "Tất cả resource phải có labels 'environment' và 'team'"
  condition: |
    resource.labels.environment != null
    AND resource.labels.team != null
  action_type: deny

3. Legacy Constraints (đã lỗi thời)

Định dạng cũ, đang được loại bỏ dần. Hãy dùng managed/custom thay thế.

Thiết lập Organization Policies

bash
# 1. Liệt kê managed constraints có sẵn
gcloud resource-manager org-policies list-constraints

# 2. Xem chi tiết constraint
gcloud resource-manager org-policies describe \
  constraints/compute.requireOsLogin

# 3. Tạo policy (ép constraint)
gcloud resource-manager org-policies create \
  --constraint=constraints/compute.requireOsLogin \
  --enforce \
  --location=projects/PROJECT_ID

# 4. Đặt ngoại lệ (cho phép service account cụ thể)
gcloud resource-manager org-policies create \
  --constraint=constraints/compute.requireOsLogin \
  --enforce \
  --exemptions=serviceAccount:sa@project.iam.gserviceaccount.com \
  --location=projects/PROJECT_ID

Kế thừa policy

Organization
├── Policy: "Require OS Login"
│   ├── Được kế thừa bởi tất cả folders
│   └── Được kế thừa bởi tất cả projects

├── Folder: "Production"
│   ├── Kế thừa: "Require OS Login"
│   ├── Policy: "Require CMEK"
│   │   ├── Được kế thừa bởi child projects
│   │   └── Ngoại lệ: backup-sa@...
│   │
│   └── Project: "prod-api"
│       ├── Kế thừa: "Require OS Login"
│       ├── Kế thừa: "Require CMEK"
│       └── Policy: "Disable SSH keys"

Giải quyết xung đột

Nếu policy xung đột thì sao?

Organization: "Enforce CMEK"  (phải đúng)
Folder: Override "Allow unencrypted"  (phải sai)

Kết quả: CMEK được thực thi
(không thể nới lỏng policy kế thừa ở tầng thấp hơn)

Policy có điều kiện với Tags

yaml
# Ép CMEK chỉ cho resource production

policy:
  name: "encrypt-production"
  constraint: "compute.cmekResources"
  rules:
    - enforce: true
      condition:
        expression: "resource.matchTag('environment', 'production')"
        description: "Bắt buộc CMEK cho production"
    
    - enforce: false
      condition:
        expression: "resource.matchTag('environment', 'dev')"
        description: "Dev được dùng encryption mặc định"

Chế độ Dry-Run

Kiểm thử policy trước khi ép buộc:

bash
# Tạo policy ở chế độ dry-run
gcloud resource-manager org-policies create \
  --constraint=constraints/compute.requireOsLogin \
  --dry-run \
  --location=projects/PROJECT_ID

# Theo dõi audit logs để biết gì sẽ bị chặn
gcloud logging read \
  'protoPayload.status.code=7' \  # Permission denied
  --format=json

# Khi đã chắc chắn, chuyển sang enforcement
gcloud resource-manager org-policies update \
  --constraint=constraints/compute.requireOsLogin \
  --enforce \
  --location=projects/PROJECT_ID

Custom Constraints với CEL

python
from google.cloud import resource_manager_v3

def create_custom_constraint():
    """Tạo custom constraint: yêu cầu labels"""
    
    client = resource_manager_v3.OrgPolicyClient()
    
    # Định nghĩa constraint bằng CEL expression
    constraint = resource_manager_v3.CustomConstraint(
        display_name="Require environment label",
        description="Tất cả resource phải có environment label",
        condition="resource.labels.environment != null",
        action_type=resource_manager_v3.CustomConstraint.ActionType.DENY,
        resource_types=["compute.googleapis.com/Instance"]
    )
    
    # Tạo constraint
    operation = client.create_custom_constraint(
        parent=f"organizations/ORG_ID",
        custom_constraint=constraint
    )
    
    return operation.result()

Ví dụ CEL

yaml
# Ví dụ 1: Bắt buộc machine type cụ thể
resource.type == "compute.googleapis.com/Instance"
AND resource.machineType NOT IN ["n1-standard-1", "n1-standard-2"]

# Ví dụ 2: Bắt buộc labels
resource.labels.environment == null OR resource.labels.team == null

# Ví dụ 3: Giới hạn theo zone
resource.zone NOT IN ["us-central1-a", "us-central1-b"]

# Ví dụ 4: Ép mã hóa
resource.encryptionKey == null

# Ví dụ 5: Điều kiện phức tạp với tags
resource.matchTag("environment", "production")
AND resource.labels.encryption != "cmek"

Organization Policies bằng Terraform

hcl
# Ép policy qua Terraform

resource "google_org_policy_policy" "require_os_login" {
  name   = "organizations/ORG_ID/policies/compute.requireOsLogin"
  parent = "organizations/ORG_ID"

  rules {
    enforce = true
  }
}

# Policy có ngoại lệ
resource "google_org_policy_policy" "require_cmek" {
  name   = "projects/PROJECT_ID/policies/compute.cmekResources"
  parent = "projects/PROJECT_ID"

  rules {
    enforce = true
    
    # Ngoại lệ cho service account
    condition {
      expression = "resource.matchTag('backup', 'true')"
    }
  }
}

# Custom constraint
resource "google_org_policy_custom_constraint" "require_labels" {
  name               = "organizations/ORG_ID/customConstraints/require.labels"
  display_name       = "Require labels"
  description        = "Tất cả resource phải có labels"
  action_type        = "DENY"
  condition          = "resource.labels.environment != null"
  resource_types    = ["compute.googleapis.com/Instance"]
}

Khắc phục sự cố

Policy không được thực thi

bash
# Kiểm tra policy có thực sự được áp dụng không
gcloud resource-manager org-policies list \
  --location=projects/PROJECT_ID

# Kiểm tra audit logs
gcloud logging read \
  'protoPayload.resourceName="projects/PROJECT_ID"' \
  --limit=50 \
  --format=json

# Thử thực hiện hành động bị chặn
# Nếu bị chặn → Policy đang được thực thi
# Nếu vẫn được phép → Có thể policy cấu hình sai

Giải quyết xung đột policy

bash
# Nếu nhiều policy cùng áp dụng, policy chặt nhất sẽ thắng

# Ví dụ:
Organization: Allow
Folder: Deny
Project: Allow

Kết quả: Deny (chặt nhất)

# Giải pháp: Kiểm tra hierarchy để tìm policy xung đột
gcloud resource-manager org-policies list --recursive

Best practices

yaml
1. Bắt đầu bằng dry-run
   - Hiểu tác động trước khi enforcement
   - Theo dõi logs xem điều gì sẽ bị chặn

2. Dùng tags cho policy có điều kiện
   - Áp dụng quy tắc khác nhau theo environment
   - Sạch hơn nhiều policy rời rạc

3. Ghi tài liệu ngoại lệ
   - Vì sao service account này được miễn?
   - Giữ audit trail

4. Rà soát định kỳ
   - Policy có thể trở nên lỗi thời
   - Công nghệ thay đổi (ví dụ: phương thức mã hóa mới)

5. Kiểm thử quy trình khôi phục
   - Có thể tạm tắt policy nếu cần không?
   - Quy trình phê duyệt là gì?

Anti-pattern

Anti-patternVấn đềGiải pháp
Policy quá rộngChặn cả use case hợp lệDùng điều kiện, ngoại lệ
Quá nhiều ngoại lệPolicy trở nên vô dụngXem lại ai thật sự cần ngoại lệ
Không dry-runLàm hỏng workflow productionTest trước khi enforcement
Không tài liệuTeam không hiểu policyGhi rõ mục đích, ngoại lệ
Không review policyRàng buộc lỗi thờiLên lịch review hàng quý

Tham khảo