Skip to content

Bảo vệ tài nguyên: Khóa & ngăn xóa

Vì sao cần Resource Protection

Xóa hoặc sửa nhầm là một trong các nguyên nhân lớn gây sự cố production:

Kịch bản 1: Engineer vô tình xóa database production
Kết quả: Mất dữ liệu, downtime, vi phạm quy định

Kịch bản 2: Script terraform destroy bị lỗi
Kết quả: Hạ tầng quan trọng bị phá hủy

Kịch bản 3: Kẻ xấu có quyền chỉnh sửa
Kết quả: Phá hoại dịch vụ

Kịch bản 4: Service account quá nhiều quyền
Kết quả: Lỗi tự động hóa lan rộng

Các cơ chế bảo vệ tài nguyên của GCP:

  1. Resource locks (billing accounts, projects)
  2. Deletion protection (cài đặt riêng cho từng resource)
  3. Soft-delete windows (projects, backups)
  4. Audit logging (theo dõi ai xóa cái gì)
  5. IAM controls (hạn chế ai được xóa)

Bảo vệ ở cấp Project

Delete Protection

Projects có cơ chế soft-delete tích hợp sẵn:

T+0: gcloud projects delete my-project
     → Trạng thái: DELETE_REQUESTED
     → Project vẫn tồn tại, vẫn hiển thị, vẫn có thể dùng

T+0 đến T+30 ngày: Cửa sổ soft-delete
     → Có thể undelete project
     → Vẫn tính vào quota project
     → Billing dừng

T+30 ngày: Xóa vĩnh viễn
     → Project biến mất hoàn toàn
     → Có thể tái sử dụng Project ID (sau 30 ngày)
     → Quota được giải phóng

Ưu điểm:

  • Có thể phục hồi nếu xóa nhầm
  • Có 30 ngày để khôi phục
  • Không mất dữ liệu vĩnh viễn nếu phát hiện sớm

Khôi phục project đã xóa:

bash
# Liệt kê project đã xóa
gcloud projects list --filter="lifecycleState:DELETE_REQUESTED"

# Khôi phục project đã xóa
gcloud projects undelete my-project

# Khôi phục với parent mới (nếu di chuyển folder)
gcloud projects move my-project \
  --folder-id=NEW_FOLDER_ID

Quota project khi xóa

Project đã xóa vẫn tính vào quota trong thời gian ân hạn:

Quota organization: 10 projects

Tình huống:
- Project 1-9: Active
- Project 10: Active
- Quota: 10/10 (đạt giới hạn)

Xóa Project 10:
- T+0 đến T+30d: Project 10 ở soft-delete (vẫn tính)
- Không thể tạo Project 11 → sẽ thành 11/10
- Phải đợi 30 ngày HOẶC khôi phục rồi xóa đúng cách

Giải pháp: Xóa và đợi 30 ngày trước khi tính lại quota

Bảo vệ ở cấp Resource

Các resource khác nhau có cơ chế bảo vệ khác nhau:

Cloud Storage Buckets

bash
# Versioning: cho phép khôi phục object
gsutil versioning set on gs://my-bucket

# Bảo vệ xóa: ngăn xóa bucket
gsutil retention set 1w gs://my-bucket  # giữ 1 tuần

# Lifecycle policies: tự động xóa phiên bản cũ
gsutil lifecycle set policy.json gs://my-bucket

Persistent Disks (Compute Engine)

bash
# Tạo snapshot trước khi xóa disk
gcloud compute disks snapshot my-disk \
  --snapshot-names=my-disk-backup

# Snapshot có thể khôi phục disk nếu cần (phục hồi dữ liệu)

Cloud SQL Databases

bash
# Backup tự động: bật mặc định
gcloud sql instances patch my-instance \
  --backup-start-time=03:00 \
  --retained-backups-count=7

# Point-in-time recovery: khôi phục về bất kỳ thời điểm nào
gcloud sql backups restore BACKUP_ID \
  --backup-instance=my-instance

# Quan trọng: mặc định backup retention là 7 ngày
# Nếu xóa ngay sau khi lịch backup chưa chạy, có thể không có backup

BigQuery Datasets

bash
# Thời gian hết hạn mặc định của table: giúp tránh mất dữ liệu do nhầm
bq update \
  --default_table_expiration=7776000 \  # 90 ngày
  project_id:dataset_id

# Nhưng có thể bị ghi đè ở cấp table/job
# Khuyến nghị: bỏ default expiration cho dataset quan trọng

Bảo vệ dựa trên IAM

Ngăn xóa qua IAM

bash
# Không cho service account xóa resource
gcloud iam deny-policies create deny-deletions \
  --location=projects/PROJECT_ID \
  --rules='
    deny {
      permissions: [
        "compute.instances.delete",
        "compute.disks.delete",
        "storage.buckets.delete",
        "sqladmin.instances.delete"
      ]
      principals: ["principalSet://goog/public:all"]
      deny_rule {
        deny_condition {
          expression: "resource.matchTag(\"environment\", \"production\")"
        }
      }
    }
  '

Kiểm soát truy cập theo role

bash
# Giới hạn quyền xóa cho role cụ thể

# Tạo custom role: Có thể quản lý nhưng không thể xóa
gcloud iam roles create projects/PROJECT_ID/roles/resourceManager \
  --title="Resource Manager" \
  --description="Có thể tạo/cập nhật nhưng không thể xóa resource" \
  --permissions=\
compute.instances.create,\
compute.instances.get,\
compute.instances.setMetadata

# Gán role thay vì Owner/Editor
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member=group:developers@company.com \
  --role=projects/PROJECT_ID/roles/resourceManager

Audit logging cho thao tác xóa

Theo dõi ai đã xóa gì

bash
# Truy vấn audit logs cho các thao tác xóa
gcloud logging read \
  'protoPayload.methodName="compute.instances.delete" AND severity=WARNING' \
  --limit=20 \
  --format=json

# Lọc theo resource và thời gian
gcloud logging read \
  'protoPayload.resourceName="projects/my-project/zones/us-central1-a/instances/my-vm" AND 
   protoPayload.methodName="compute.instances.delete"' \
  --format=json

Cảnh báo khi có xóa

python
from google.cloud import monitoring_v3

def create_deletion_alert(project_id):
    """Cảnh báo khi resource production bị xóa"""
    
    client = monitoring_v3.AlertPolicyServiceClient()
    
    # Điều kiện: bất kỳ thao tác delete nào trên resource prod
    condition = monitoring_v3.AlertPolicy.Condition(
        display_name="Production resource deleted",
        condition_threshold=monitoring_v3.AlertPolicy.Condition.MetricThreshold(
            filter='''
            resource.type="gce_instance"
            AND metric.type="logging.googleapis.com/user/resource_deletion"
            AND resource.labels.environment="production"
            ''',
            comparison=monitoring_v3.ComparisonType.COMPARISON_GT,
            threshold_value=0,
            duration={"seconds": 60}
        )
    )
    
    # Tạo alert
    policy = monitoring_v3.AlertPolicy(
        display_name="Production resource deletion alert",
        conditions=[condition],
        notification_channels=[create_notification_channel()]
    )
    
    client.create_alert_policy(
        name=f"projects/{project_id}",
        alert_policy=policy
    )

Chiến lược backup

Quy tắc 3-2-1

Với dữ liệu quan trọng:

- 3 bản sao: Bản gốc + 2 bản backup
- 2 loại media khác nhau: Disk + Cloud Storage
- 1 bản offsite: region/project khác
python
def backup_critical_data(source_disk):
    """Triển khai backup 3-2-1 cho dữ liệu quan trọng"""
    
    # Bản sao 1: Snapshot (định dạng disk)
    snapshot1 = create_snapshot(source_disk, name="backup-snapshot-1")
    
    # Bản sao 2: Snapshot ở region khác
    snapshot2 = create_snapshot_in_region(
        source_disk,
        name="backup-snapshot-2",
        region="us-east1"  # Region khác
    )
    
    # Bản sao 3: Export sang Cloud Storage (offsite)
    export_snapshot_to_storage(
        snapshot1,
        bucket="gs://backups-project",
        path="backups/critical-data/"
    )
    
    return {
        "snapshots": [snapshot1.name, snapshot2.name],
        "storage_export": "gs://backups-project/backups/critical-data/"
    }

Backup bất biến

bash
# Cloud Storage bucket với Object Lock
gsutil bucket-lock set gs://backups-immutable

# Lúc này object không thể bị xóa/sửa
# Ngay cả admin cũng không thể gỡ cho đến khi hết retention

Kiểm thử Disaster Recovery

python
def dr_test():
    """Kiểm thử DR định kỳ: tạo resource từ backup"""
    
    import time
    
    # Tạo project test
    test_project = create_project(f"dr-test-{int(time.time())}")
    
    try:
        # Khôi phục từ backup
        restore_from_snapshot(
            snapshot="snapshots/critical-data-backup",
            destination_project=test_project
        )
        
        # Xác thực dữ liệu khôi phục
        assert validate_data_integrity(test_project)
        print("✓ DR test passed")
        
    finally:
        # Dọn dẹp project test (sau thời gian retention)
        schedule_project_deletion(test_project, delay_days=7)

Bảo vệ khi destroy bằng Terraform

hcl
# Ngăn terraform destroy vô tình

resource "google_compute_instance" "production" {
  name = "production-vm"
  
  # Thêm lifecycle rule để ngăn destruction
  lifecycle {
    prevent_destroy = true
  }
}

# Cách khác: yêu cầu phê duyệt
resource "null_resource" "approval_gate" {
  triggers = {
    production_vm = google_compute_instance.production.id
  }
  
  provisioner "local-exec" {
    command = "echo 'Require manual approval before destroy'; exit 1"
    when    = destroy
  }
}

# Muốn thực sự destroy phải bỏ prevent_destroy
terraform destroy -auto-approve  # Sẽ thất bại nếu prevent_destroy=true

Quy trình khôi phục

bash
#!/bin/bash
# recover-deleted-project.sh

PROJECT_ID=$1

# Bước 1: Kiểm tra project có ở soft-delete không
STATUS=$(gcloud projects describe $PROJECT_ID --format='value(lifecycleState)')

if [ "$STATUS" == "DELETE_REQUESTED" ]; then
    echo "✓ Project đang ở trạng thái soft-delete"
    
    # Bước 2: Undelete project
    gcloud projects undelete $PROJECT_ID
    echo "✓ Project đã được khôi phục"
    
    # Bước 3: Xác minh resources
    RESOURCE_COUNT=$(gcloud compute instances list \
      --project=$PROJECT_ID --format=json | jq 'length')
    echo "✓ Tìm thấy $RESOURCE_COUNT instances"
    
    # Bước 4: Bật lại services
    gcloud services enable compute.googleapis.com \
      --project=$PROJECT_ID
    
    echo "✓ Khôi phục hoàn tất"
else
    echo "✗ Project không ở soft-delete (không thể khôi phục)"
    exit 1
fi

Các anti-pattern cần tránh

Anti-patternVấn đềGiải pháp
Không có backupMất dữ liệu là vĩnh viễnTriển khai backup 3-2-1
Service account quá quyềnCó thể xóa mọi thứGiới hạn IAM theo least privilege
Không audit loggingKhông truy vết được ai xóaBật audit logging
Terraform destroy không có bảo vệPhá hủy nhầmThêm bảo vệ lifecycle
Không cảnh báo khi xóaLỗi âm thầmGiám sát audit log xóa
Backup trong cùng projectBackup bị xóa cùng projectBackup sang project khác

Tham khảo