Skip to content

Break-glass, Policy Exceptions và Anti-patterns

Tại sao quan trọng trong production

Binary Authorization, khi được cấu hình đúng, blocks deployments không có attestation hợp lệ. Nhưng trong production thực tế, luôn có tình huống cần deploy nhanh mà không có time để đi qua toàn bộ attestation workflow — critical security patch lúc 3 giờ sáng, incident response, hoặc CI pipeline bị broken. Break-glass là tính năng được thiết kế cho những tình huống này.

Vấn đề: break-glass là cơ chế bypass bảo mật. Nếu không được kiểm soát chặt chẽ, nó trở thành backdoor thường xuyên được dùng thay vì exception. Hiểu đúng cơ chế — đặc biệt là audit trail — là điều kiện để thiết kế governance đúng đắn.

Song song đó, allowlist exceptions (admissionWhitelistPatterns) cũng là nguồn gốc của nhiều security gaps. Mỗi entry trong allowlist là một hole trong policy. Hiểu khi nào dùng allowlist và khi nào không là kỹ năng quan trọng.


Break-glass: Emergency Bypass Mechanism

Cơ Chế Bên Trong

Break-glass không phải là một policy mode hay cluster configuration — nó là một Kubernetes annotation được thêm vào Pod spec tại thời điểm deployment:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: emergency-fix
  namespace: production
  annotations:
    alpha.image-policy.k8s.io/break-glass: "true"  # annotation magic
spec:
  containers:
  - name: app
    image: gcr.io/my-project/app@sha256:abc123

Khi Binary Authorization webhook thấy annotation này:

  1. Bỏ qua tất cả policy evaluation: Không check attestors, không check REQUIRE_ATTESTATION, không check evaluation mode — image được allow bất kể
  2. Ghi mandatory audit log: Dù image được allow, một log entry đặc biệt được ghi vào Cloud Audit Logs với severity cao hơn normal enforcement events
  3. Không thể disable audit: Audit logging cho break-glass events là mandatory — không có cách nào bypass annotation mà không tạo audit record

Điều này có nghĩa: break-glass không phải "deploy silently without BinAuthz". Nó là "deploy with explicit bypass và mandatory disclosure".

Annotation Format Và Scope

yaml
# Format đúng
annotations:
  alpha.image-policy.k8s.io/break-glass: "true"

# Không hoạt động (sai annotation name)
annotations:
  binary-authorization/break-glass: "true"

Annotation phải ở level Pod (không phải Deployment, không phải namespace). Khi dùng với Deployment:

yaml
# Annotation phải ở trong spec.template.metadata (Pod template)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    metadata:
      annotations:
        alpha.image-policy.k8s.io/break-glass: "true"  # Đây, không phải ở Deployment metadata
    spec:
      containers:
      - name: app
        image: gcr.io/my-project/app@sha256:abc123

Scope của break-glass: Annotation áp dụng cho tất cả containers trong Pod — không thể break-glass cho một container cụ thể trong Pod.

Audit Log Cho Break-glass Events

Khi break-glass được dùng, Cloud Audit Log entry có structure đặc biệt:

json
{
  "logName": "projects/my-project/logs/cloudaudit.googleapis.com%2Factivity",
  "severity": "WARNING",
  "protoPayload": {
    "methodName": "io.k8s.core.v1.pods.create",
    "authorizationInfo": [
      {
        "permission": "container.pods.create",
        "granted": true,
        "resourceAttributes": {
          "namespace": "production",
          "name": "emergency-fix"
        }
      }
    ],
    "metadata": {
      "binaryAuthorization": {
        "policyRef": "projects/my-project/policy",
        "containerChecks": [
          {
            "containerName": "app",
            "image": "gcr.io/my-project/app@sha256:abc123",
            "verdict": "VERDICT_ALLOWED_BY_BREAKGLASS",  // key field
            "checkResults": []
          }
        ]
      }
    },
    "requestMetadata": {
      "callerIp": "203.0.113.X",  // IP của người dùng gcloud/kubectl
      "callerSuppliedUserAgent": "kubectl/v1.28.0"
    }
  }
}

Trường then chốt: verdict: "VERDICT_ALLOWED_BY_BREAKGLASS" — cho phép filter log entries để tìm tất cả break-glass events.

Monitoring Break-glass Abuse

Thiết lập alerting ngay khi bật Binary Authorization:

bash
# Tạo log-based metric cho break-glass events
gcloud logging metrics create breakglass_events \
  --description="Binary Authorization break-glass bypass events" \
  --log-filter='resource.type="k8s_cluster"
    AND protoPayload.metadata.binaryAuthorization.containerChecks.verdict="VERDICT_ALLOWED_BY_BREAKGLASS"'
yaml
# breakglass-alert.yaml
displayName: "URGENT: Binary Authorization Break-glass Used"
combiner: OR
conditions:
- displayName: "Break-glass event detected"
  conditionThreshold:
    filter: metric.type="logging.googleapis.com/user/breakglass_events"
    comparison: COMPARISON_GT
    thresholdValue: 0
    duration: 0s  # alert ngay lập tức, không đợi
alertStrategy:
  autoClose: 300s  # auto-close sau 5 phút
notificationChannels:
- "projects/my-project/notificationChannels/security-team-pagerduty"
- "projects/my-project/notificationChannels/security-slack"

Query để audit break-glass history:

bash
# Tất cả break-glass events trong 30 ngày qua
gcloud logging read \
  'resource.type="k8s_cluster"
   AND protoPayload.metadata.binaryAuthorization.containerChecks.verdict="VERDICT_ALLOWED_BY_BREAKGLASS"' \
  --project=${PROJECT_ID} \
  --freshness=30d \
  --format='table(
    timestamp,
    resource.labels.cluster_name,
    resource.labels.namespace_name,
    protoPayload.authorizationInfo[0].resourceAttributes.name,
    protoPayload.requestMetadata.callerIp,
    protoPayload.authenticationInfo.principalEmail
  )'

IAM Kiểm Soát Ai Có Thể Dùng Break-glass

Break-glass không có IAM control riêng — bất kỳ ai có quyền container.pods.create (tức là có thể deploy Pod) đều có thể dùng annotation break-glass. Không có permission riêng để "enable break-glass".

Implication: Nếu muốn restrict break-glass chỉ cho một nhóm nhất định, phải restrict container.pods.create permission cho namespace production. Mọi người có quyền deploy đều có quyền break-glass trong context đó.

Phương án alternative: Dùng policy + automation để detect break-glass trong CI/CD pipeline và require approval trước khi annotation được thêm vào (ví dụ: require 2 approvals trong GitHub để merge PR có break-glass annotation).

Lifecycle Sau Break-glass

Break-glass là stopgap — deployment khẩn cấp cho đến khi proper attestation được tạo. Cần process để "heal" sau break-glass:

1. Emergency: Deploy với break-glass annotation
2. Alert fired → security team notified
3. Root cause analysis: Tại sao cần break-glass?
   - CI pipeline broken? → Fix CI
   - Attestation key issue? → Fix key management
   - New image source not in policy? → Update policy properly
4. Create proper attestation cho image đã deploy
5. Redeploy image với digest (loại bỏ break-glass annotation)
6. Verify: break-glass annotation không còn trong any running Pod

Post-incident requirement: Sau khi dùng break-glass, phải tạo attestation và redeploy không có annotation. Để lại break-glass annotation vĩnh viễn là anti-pattern nghiêm trọng.


Allowlist Exceptions: Policy Carve-outs

admissionWhitelistPatterns: Cơ Chế

Allowlist cho phép một số images bypass tất cả policy evaluation:

yaml
admissionWhitelistPatterns:
- namePattern: gcr.io/google_containers/*
- namePattern: k8s.gcr.io/**
- namePattern: registry.k8s.io/**
- namePattern: gcr.io/gke-release/**

Matching semantics:

  • *: Match bất kỳ ký tự nào ngoại trừ / — tức là match một path segment
  • **: Match bất kỳ ký tự nào bao gồm / — tức là match nhiều path segments

Ví dụ:

gcr.io/my-project/*       → match: gcr.io/my-project/app
                          → KHÔNG match: gcr.io/my-project/team/app
gcr.io/my-project/**      → match: gcr.io/my-project/app
                          → match: gcr.io/my-project/team/app

Allowlist check xảy ra trước attestation lookup — nếu image match bất kỳ pattern nào, attestation không được check.

globalPolicyEvaluationMode: System Images Exemption

yaml
globalPolicyEvaluationMode: ENABLE

Khi enable, Binary Authorization tự động exempt một danh sách system images được Google quản lý. Danh sách này bao gồm:

  • GKE node agent images
  • Kubernetes system component images
  • GKE addons images
bash
# Xem danh sách system images được exempt
gcloud alpha container binauthz policy export-system-policy

Đây là necessary exemption cho GKE hoạt động đúng. Nếu không enable, các system components sẽ không deploy được và cluster không khởi động đúng.

Khi Nào Dùng Allowlist Hợp Lệ

Hợp lệ:

  1. GKE system images và Kubernetes system components
  2. Third-party sidecar images không thể tạo attestation (ví dụ: Istio proxy từ official registry, khi attestation workflow không cover images external)
  3. Images trong environment không thể thay đổi dễ dàng (legacy, vendor-provided)

Không hợp lệ:

  1. Team images để tránh phải setup attestation pipeline — đây là lazy exemption, không phải legitimate use case
  2. Wildcard patterns quá rộng: ** hoặc gcr.io/** — exempts tất cả images từ một registry
  3. Tag-based patterns thay vì digest-based khi có thể

Best practice cho allowlist:

yaml
# KHÔNG tốt: quá rộng
admissionWhitelistPatterns:
- namePattern: gcr.io/my-project/**  # mọi image trong project đều exempt

# TỐT HƠN: specific với digest
admissionWhitelistPatterns:
- namePattern: gcr.io/my-project/legacy-app@sha256:KNOWN_DIGEST  # pin exact digest

# TỐT NHẤT: không dùng allowlist, tạo attestation cho mọi image
# Chỉ exempt system images qua globalPolicyEvaluationMode

Anti-patterns Phổ Biến

Anti-pattern 1: DRYRUN_AUDIT_LOG_ONLY Mãi Không Chuyển Sang Enforce

Mô tả: Team enable Binary Authorization với enforcementMode: DRYRUN_AUDIT_LOG_ONLY để "test trước" nhưng không bao giờ chuyển sang ENFORCED_BLOCK_AND_AUDIT_LOG.

Vì sao xảy ra: Dry-run mode tiện lợi — không block deployments, chỉ log. Team luôn có lý do để trì hoãn: "pipeline chưa ổn định", "cần thêm time để test", "đang trong freeze period". Dry-run trở thành permanent state.

Vấn đề cốt lõi: Dry-run mode không cung cấp bảo vệ gì. Binary Authorization bật nhưng không enforce nghĩa là không có supply chain security. Log violations nhưng không block là false sense of security — bạn biết có violations nhưng không làm gì.

Cách phòng: Set deadline rõ ràng khi bắt đầu dry-run. Ví dụ: "dry-run 2 tuần, sau đó switch to enforce". Track số violations giảm dần theo thời gian là indicator thành công. Nếu sau 4 tuần vẫn còn violations, có vấn đề với attestation pipeline, không phải với policy.

Anti-pattern 2: Allowlist Quá Rộng

Mô tả: Để tránh "ảnh hưởng deployment", team add allowlist entries rộng:

yaml
# Anti-pattern
admissionWhitelistPatterns:
- namePattern: us.gcr.io/**           # mọi image từ US GCR
- namePattern: gcr.io/my-company/**   # mọi image từ company GCR
- namePattern: docker.io/**           # Docker Hub — mọi image public

Vì sao nguy hiểm: Allowlist entries rộng có nghĩa là policy không có tác dụng gì với những images đó. Nếu gcr.io/my-company/** trong allowlist, attacker chỉ cần push malicious image vào project nào đó trong company để bypass BinAuthz.

Vấn đề cốt lõi: Allowlist không phải "we trust these images". Allowlist là "we skip attestation check for these images". Trust phải đến từ attestation, không phải location.

Cách phòng:

  • Allowlist chỉ dùng cho images không thể có attestation (system images, legacy images với plan to migrate)
  • Prefer digest-pinned patterns: gcr.io/my-project/specific-image@sha256:DIGEST
  • Regular audit allowlist entries: xóa entries không còn cần thiết
  • Document lý do tại sao mỗi entry tồn tại

Anti-pattern 3: Một Attestor Cho Tất Cả

Mô tả: Team dùng một attestor duy nhất (built-by-ci) cho mọi image. Một signing key, một note, tất cả images được sign bởi cùng một service account.

Vấn đề cốt lõi: Attestor đại diện cho "loại approval". Một attestor duy nhất nghĩa là một gate — không có defense in depth. Nếu CI service account bị compromise, tất cả attestations không còn đáng tin.

Multi-stage approval — attestors riêng cho "passed security scan", "passed QA", "approved for production" — tạo ra multiple independent gates mà attacker phải compromise cả cụm.

Cách phòng:

yaml
# Tốt hơn: multiple attestors cho defense in depth
requireAttestationsBy:
- projects/my-project/attestors/security-scan    # CVE scan CI tool
- projects/my-project/attestors/qa-approved      # QA team approval
- projects/my-project/attestors/built-by-cloud-build  # origin verification

Với setup này, compromise CI credentials chỉ compromise built-by-cloud-build attestor — attacker vẫn cần compromise qa-approved (controlled bởi QA team với separate credentials).

Anti-pattern 4: Không Monitor Break-glass

Mô tả: Break-glass annotation được document trong runbook nhưng không có alerting. Audit logs có nhưng không ai xem.

Vấn đề cốt lõi: Nếu break-glass được dùng và không ai biết ngay, có thể có window lớn khi cluster chạy với unattested image. Tệ hơn: nếu break-glass annotation bị "quên" trong Deployment manifest, cluster chạy permanently với bypass active.

Anti-pattern thực tế: Developer dùng break-glass cho emergency fix, quên xóa annotation khỏi Deployment manifest, commit vào git. Sau đó mọi deployment của Deployment đó đều có break-glass — không ai để ý vì "nó vẫn deploy được".

Cách phòng:

  1. Alerting ngay khi có break-glass event (xem phần monitoring trên)
  2. CI gate: scan Kubernetes manifests cho alpha.image-policy.k8s.io/break-glass: "true" annotation — fail CI nếu tìm thấy trong non-emergency branch
  3. Regular audit: kubectl get pods --all-namespaces -o json | jq '.items[] | select(.metadata.annotations["alpha.image-policy.k8s.io/break-glass"] == "true") | .metadata.name'

Anti-pattern 5: Tag Thay Vì Digest Trong Manifest

Mô tả: Mặc dù attestation được tạo đúng với digest, deployment manifest vẫn dùng tag:

yaml
# Anti-pattern trong Deployment manifest
containers:
- name: app
  image: gcr.io/my-project/app:v1.2.3   # tag, không phải digest

Vấn đề cốt lõi: Đã được mô tả chi tiết trong file 03. Tag là mutable pointer — Binary Authorization phải resolve tag sang digest khi kiểm tra, và digest có thể đã thay đổi so với digest được sign trong CI.

Cách phòng: Enforce digest-only trong CI/CD. Khi tạo attestation, lưu full image reference với digest và dùng nó trong deploy step. Dùng admission webhook tùy chỉnh hoặc CI gate để reject Kubernetes manifests có image reference dùng tag (không có @sha256:).

bash
# Kiểm tra trong CI
if kubectl get pod my-pod -o json | jq -r '.spec.containers[].image' | grep -v '@sha256:'; then
  echo "ERROR: Found images without digest pinning"
  exit 1
fi

Anti-pattern 6: Default Rule ALWAYS_ALLOW Cho Production

Mô tả: Team set ALWAYS_ALLOW cho defaultAdmissionRule và chỉ configure REQUIRE_ATTESTATION cho specific clusters. Khi cluster mới được tạo, nó tự động fall vào defaultAdmissionRule với ALWAYS_ALLOW.

yaml
# Nguy hiểm
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW      # Tất cả clusters mới sẽ không có enforcement
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG

Vấn đề cốt lõi: Policy mở theo mặc định (allow-first) thay vì đóng (deny-first). Cluster staging mới, cluster experimental — nếu không có cluster-specific rule, tất cả đều bị exempt. New cluster creation không trigger bất kỳ security review nào.

Cách phòng: Set defaultAdmissionRule với REQUIRE_ATTESTATION (hoặc ít nhất ALWAYS_DENY). Chỉ relax cho specific clusters khi cần, không phải relax cho "everything else".

yaml
# Đúng: deny-first default
defaultAdmissionRule:
  evaluationMode: REQUIRE_ATTESTATION    # Enforce cho tất cả clusters không có rule riêng
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
  requireAttestationsBy:
  - projects/my-project/attestors/security-scan

# Relax cho dev clusters explicitly
clusterAdmissionRules:
  us-central1-a.dev-cluster:
    evaluationMode: ALWAYS_ALLOW
    enforcementMode: DRYRUN_AUDIT_LOG_ONLY

Governance Pattern: Vận Hành Break-glass An Toàn

Để dùng break-glass an toàn trong tổ chức, cần process rõ ràng:

Trước khi dùng break-glass:

  1. Escalate to on-call security engineer (nếu có thể)
  2. Document lý do trong incident ticket
  3. Thử alternative: là CI pipeline có thể được fix nhanh không? Attestation có thể được tạo thủ công không?

Khi dùng break-glass:

  1. Thêm annotation vào manifest
  2. Deploy
  3. Verify alert fired → security team notified
  4. Ghi lại incident ticket ID trong annotation comment nếu có thể

Sau khi dùng break-glass:

  1. Tạo proper attestation cho image (bước này không thể skip)
  2. Redeploy không có break-glass annotation
  3. Verify annotation đã được xóa khỏi tất cả running Pods
  4. Post-incident review: làm gì để tránh break-glass lần sau
bash
# Verify không còn break-glass annotations đang active
kubectl get pods --all-namespaces -o json | \
  jq -r '.items[] | select(.metadata.annotations["alpha.image-policy.k8s.io/break-glass"] == "true") | 
    "\(.metadata.namespace)/\(.metadata.name)"'
# Output kỳ vọng: empty (không có Pod nào)

Tài liệu tham khảo