← Cloud · GCP← Cloud · GCP
Cloud · GCPCloud · GCP19 Th7, 2026Jul 19, 202611 phút đọc10 min read

Identity & Access Management (IAM)Identity & Access Management (IAM)

Thuộc bộ tài liệu Cloud knowledge base — GCP deep dive. Bổ sung cho DevOps Roadmap.

Tổng quan

Cloud IAM trả lời một câu hỏi cho mọi lời gọi API: ai được làm gì trên tài nguyên nào? Trong GCP nó tách thành ba phần — một member (ai), một role gom các permission (làm gì), và một resource mà binding gắn vào (trên cái nào). Một binding (member, role) trên một resource là một allow policy (trước đây gọi là “IAM policy”).

Đặc điểm định hình của GCP IAM là thừa kế theo phân cấp: một policy đặt ở Organization hay Folder chảy xuống mọi project và resource bên dưới, và policy hiệu lực tại một node bất kỳ là hợp (union) của binding của chính nó cộng tất cả binding thừa kế. Không có khái niệm “mặc định deny theo thừa kế” — các grant cộng dồn xuống dưới. Điều này khiến resource hierarchy (ở trang Overview) trở thành xương sống của toàn bộ mô hình truy cập, nên hãy làm đúng ngay từ đầu.

Kiến thức nền tảng

Member (principal)

Member là bất kỳ identity nào có thể được cấp role. Tiền tố trong chuỗi member cho IAM biết đó là loại gì:

Loại memberDạng chuỗiDùng cho
Google accountuser:alice@example.comMột người có identity Google/Workspace
Google groupgroup:devs@example.comCấp cho một team; quản lý thành viên trong group
Service accountserviceAccount:svc@PROJECT.iam.gserviceaccount.comWorkload phi con người (app, VM, pipeline)
Workspace / Cloud Identity domaindomain:example.comMọi người trong org
Workload Identity Federationprincipal://… / principalSet://…Identity ngoài (GitHub, AWS, OIDC) không cần key
Mọi identity đã xác thựcallAuthenticatedUsersBất kỳ ai đã xác thực bằng Google (hiếm khi hợp lý)
Tất cả, không xác thựcallUsersHoàn toàn public (ví dụ bucket/website công khai)

Hãy ưu tiên cấp role cho group, không phải cá nhân — bạn quản lý truy cập bằng cách đổi thành viên group trong identity provider, vừa audit được vừa tồn tại qua việc người vào/ra.

Role

Role là một tập permission có tên. Bản thân permission (ví dụ compute.instances.start) không bao giờ được cấp trực tiếp — luôn qua một role. Có ba cấp:

Loại roleLà gìVí dụKhi nào dùng
Basic (primitive)Role cũ, rất rộng: roles/owner, roles/editor, roles/viewerroles/editor cho quyền ghi lên gần như mọi thứTránh trong production — quá thô
PredefinedRole do Google biên soạn, giới hạn theo dịch vụ, luôn cập nhậtroles/compute.instanceAdmin.v1, roles/storage.objectViewerLựa chọn mặc định — least-privilege mà không phải bảo trì
CustomRole bạn tự định nghĩa từ danh sách permission chọn tayroles/customDeployBotKhi không predefined role nào vừa và cần phạm vi chặt hơn

Nguyên tắc: bắt đầu từ predefined role gần nhất. Chỉ dùng custom role khi predefined quá rộng, và để dành basic role cho project sandbox nhỏ (hoặc không bao giờ).

Allow policy & binding

Một allow policy gắn vào resource là danh sách các binding. Mỗi binding gắn một role với một tập member, tùy chọn kèm condition:

{
  "bindings": [
    {
      "role": "roles/storage.objectViewer",
      "members": [
        "group:analysts@example.com",
        "serviceAccount:etl@payments-prod.iam.gserviceaccount.com"
      ]
    },
    {
      "role": "roles/compute.instanceAdmin.v1",
      "members": ["group:sre@example.com"],
      "condition": {
        "title": "prod-only",
        "expression": "resource.name.startsWith('projects/payments-prod')"
      }
    }
  ],
  "etag": "BwY...",
  "version": 3
}

etag cung cấp optimistic concurrency (đọc-sửa-ghi an toàn). version: 3 là bắt buộc mỗi khi có condition.

Thừa kế xuống phân cấp

Policy hiệu lực trên một resource là hợp của binding đặt trực tiếp trên nó cộng mọi binding thừa kế từ project, folder và organization:

Binding IAM theo phân cấp tài nguyên
  1. Org
    group:security-admins → roles/iam.securityReviewerđọc IAM toàn org
  2. Folder "Engineering"
    group:eng-leads → roles/resourcemanager.folderViewer
  3. Project "payments-prod"
    group:payments-dev → roles/run.developer
  4. Resource (một bucket)
    serviceAccount:etl@… → roles/storage.objectAdmin

Một thành viên của security-admins nhận role đó trên mọi thứ; payments-dev chỉ nhận run.developer trên đúng project đó. Vì grant chỉ luôn cộng thêm quyền xuống dưới, IAM cố tình permissive theo thiết kế — các guardrail thật sự có thể cấm điều gì đó là Organization PolicyIAM Conditions / deny policy, không phải allow binding thông thường.

Khái niệm chính

Service account

Service account (SA) là identity đặc biệt cho workload phi con người. Nó vừa là identity (được cấp role) vừa là resource (người/SA khác có thể được cấp role trên nó, như quyền impersonate nó). Ba loại:

Key vs keyless — đây là quyết định IAM quan trọng nhất.

CáchCơ chếRủi roKết luận
SA key (JSON)Private key sống lâu, tải về đượcRò rỉ trong Git, laptop, log CI; không hết hạnTránh. Vector rò rỉ credential số 1 của GCP
Attached SAVM/Cloud Run/GKE chạy dưới danh nghĩa một SA; metadata server phát token ngắn hạnToken tự xoay, không nằm trên đĩaƯu tiên cho workload trong cloud
ImpersonationMột principal có roles/iam.serviceAccountTokenCreator phát token ngắn hạn cho một SAKhông key; có audit; giới hạn thời gianƯu tiên cho người/CI thao tác dưới danh nghĩa một SA
Workload Identity Federation (WIF)IdP ngoài (GitHub, AWS, OIDC/SAML) đổi token của chính nó lấy token GCP ngắn hạnKhông key nào rời khỏi hệ thống ngoàiƯu tiên cho GKE và CI/CD bên ngoài

Ví dụ impersonation (chạy lệnh dưới danh nghĩa một deploy SA, không key file):

gcloud storage ls gs://payments-artifacts \
  --impersonate-service-account=deployer@payments-prod.iam.gserviceaccount.com

Workload Identity cho GKE ánh xạ một Kubernetes service account (KSA) sang một Google service account (GSA) để pod nhận token mà không mount key:

gcloud iam service-accounts add-iam-policy-binding \
  my-gsa@payments-prod.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="serviceAccount:payments-prod.svc.id.goog[prod-ns/my-ksa]"
# rồi annotate KSA:  iam.gke.io/gcp-service-account=my-gsa@payments-prod.iam.gserviceaccount.com

WIF cho GitHub Actions — cho một workflow GitHub xác thực mà không lưu secret nào, giới hạn vào đúng một repo:

# 1. Tạo workload identity pool + OIDC provider cho GitHub
gcloud iam workload-identity-pools create github-pool \
  --location=global --display-name="GitHub Actions"

gcloud iam workload-identity-pools providers create-oidc github-provider \
  --location=global --workload-identity-pool=github-pool \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
  --attribute-condition="assertion.repository=='my-org/my-repo'"

# 2. Cho identity từ repo đó impersonate deploy SA
gcloud iam service-accounts add-iam-policy-binding \
  deployer@payments-prod.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="principalSet://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/github-pool/attribute.repository/my-org/my-repo"

attribute-condition là cực kỳ quan trọng — không ghim repository (hoặc branch/ref) thì bất kỳ repo GitHub nào cũng có thể đổi token lấy SA của bạn.

Ví dụ: cấp role bằng gcloud

# Cấp cho một group một predefined role trên một project
gcloud projects add-iam-policy-binding payments-prod \
  --member="group:payments-dev@example.com" \
  --role="roles/run.developer"

# Cấp trên một resource đơn lẻ (bucket) thay vì cả project
gcloud storage buckets add-iam-policy-binding gs://payments-artifacts \
  --member="serviceAccount:etl@payments-prod.iam.gserviceaccount.com" \
  --role="roles/storage.objectViewer"

# Kiểm tra ai đang có quyền
gcloud projects get-iam-policy payments-prod --format=json

IAM Conditions

Condition thêm quy tắc dựa trên thuộc tính lên trên một binding bằng CEL (Common Expression Language). Dùng phổ biến:

Condition biến một role rộng thành một grant hẹp, hiểu ngữ cảnh mà không cần bịa ra custom role.

IAM deny policy

Allow policy chỉ cộng thêm quyền. Deny policy gắn các quy tắc từ chối được đánh giá trước allow và ghi đè chúng — cách để nói “không ai ngoài X được phép làm Y”, kể cả khi có binding thừa kế cấp quyền đó. Dùng cho guardrail cứng (ví dụ deny iam.serviceAccountKeys.create toàn org).

Organization Policy vs IAM

Phân biệt rõ hai cái:

IAM (allow/deny policy)Organization Policy Service
Câu hỏiAi được làm ?Cái gì được phép tồn tại / thế nào?
Độ chi tiếtMember + role + resourceConstraint trên cấu hình resource
Ví dụ”Group SRE được admin VM""Không VM nào được có external IP”
Ghi đè Owner?Deny policy thì đượcCó — cả Owner cũng bị ràng

Org policy là guardrail tuân thủ (xem Overview); IAM là mô hình truy cập hằng ngày.

IAM Recommender & least privilege

IAM Recommender (thuộc Policy Intelligence) phân tích 90 ngày sử dụng thực tế và đề xuất gỡ permission không dùng hoặc đổi một role rộng lấy một role chặt hơn. Policy Analyzer trả lời “ai truy cập được resource này?” và “member này truy cập được gì?”. Kết hợp lại, chúng giúp bạn tiến tới least privilege bằng bằng chứng thay vì phỏng đoán.

Best Practices

  1. Cấp cho group, không cho cá nhân. Quản lý truy cập bằng thành viên group trong IdP — audit được, và tồn tại qua người vào/ra mà không phải sửa policy.
  2. Ưu tiên predefined role hơn basic role. Owner/Editor/Viewer quá rộng; predefined role được biên soạn theo hướng least-privilege.
  3. Không bao giờ tải service account key. Dùng attached SA, impersonation hoặc Workload Identity Federation. Cưỡng chế bằng iam.disableServiceAccountKeyCreation. Key rò rỉ là vector breach hàng đầu của GCP.
  4. Một SA chuyên biệt cho mỗi workload. Đừng dùng chung SA giữa các app; một vụ xâm nhập nên bị giới hạn trong đúng phạm vi hẹp của workload đó.
  5. Vô hiệu hóa hoặc hạ quyền default service account. Compute Engine default SA nhận Editor — thay bằng một user-managed SA least-privilege.
  6. Dùng Workload Identity Federation cho CI/CD và cloud bên ngoài. GitHub Actions, GitLab, và workload AWS nên đổi identity gốc lấy token GCP ngắn hạn — không lưu secret ở đâu cả.
  7. Luôn ghim WIF attribute condition vào đúng repo/branch/subject. Một pool provider không ghim thực chất là một cánh cửa công khai vào project của bạn.
  8. Cấp ở node hiệu lực thấp nhất. Bind trên project hoặc resource, không phải org/folder, trừ khi truy cập thực sự cần rộng như vậy — thừa kế khiến grant cao trở nên rất rộng.
  9. Dùng IAM Conditions cho truy cập giới hạn thời gian và phạm vi. Nâng quyền trong một khoảng, hoặc giới hạn role theo tiền tố tên resource, thay vì một grant rộng vĩnh viễn.
  10. Dùng deny policy cho các quy tắc “không bao giờ” cứng. Mã hóa các điều không thương lượng (không tạo key, không xóa audit sink) để không allow thừa kế nào ghi đè được.
  11. Chạy IAM Recommender định kỳ và gỡ grant không dùng. Tiến tới least privilege bằng bằng chứng sử dụng; grant rộng đã cũ là rủi ro âm thầm.
  12. Tách bạch nhiệm vụ giữa các môi trường. Group/SA khác nhau cho dev/staging/prod; không identity con người đơn lẻ nào nên giữ quyền admin prod theo mặc định.
  13. Để dành Owner chỉ cho break-glass. Loại nó khỏi quy trình hằng ngày; log và alert mỗi khi nó được dùng.
  14. Bật Cloud Audit Logs (Admin Activity + Data Access) và giám sát thay đổi IAM. Alert khi có tạo key mới, cấp role ở cấp org/folder, và lời gọi setIamPolicy.
  15. Quản lý IAM bằng code (Terraform). Ưu tiên resource kiểu authoritative nhưng hẹp như google_project_iam_member hơn _policy để tránh vô tình xóa binding bạn không quản lý; review mọi thay đổi trong PR.

Tài liệu tham khảo

Part of the Cloud knowledge base — GCP deep dive. Complements DevOps Roadmap.

Overview

Cloud IAM answers one question for every API call: who can do what on which resource? In GCP that decomposes into three parts — a member (the who), a role that bundles permissions (the what), and a resource the binding is attached to (the which). A binding of (member, role) on a resource is an allow policy (formerly “IAM policy”).

The defining feature of GCP IAM is hierarchical inheritance: a policy set on the Organization or a Folder flows down to every project and resource beneath it, and the effective policy at any node is the union of its own bindings and all inherited ones. There is no “deny by inheritance by default” — grants accumulate downward. This makes the resource hierarchy (from the Overview page) the backbone of your entire access model, so get it right early.

Fundamentals

Members (principals)

A member is any identity that can be granted a role. The prefix in the member string tells IAM what kind it is:

Member typeString formUse for
Google accountuser:alice@example.comA human with a Google/Workspace identity
Google groupgroup:devs@example.comGrant to a team; manage membership in the group
Service accountserviceAccount:svc@PROJECT.iam.gserviceaccount.comNon-human workloads (apps, VMs, pipelines)
Workspace / Cloud Identity domaindomain:example.comEveryone in your org
Workload Identity Federationprincipal://… / principalSet://…External identities (GitHub, AWS, OIDC) with no key
All authenticated usersallAuthenticatedUsersAny Google-authenticated identity (rarely appropriate)
Everyone, no authallUsersFully public (e.g. a public bucket/website)

Prefer granting roles to groups, not individuals — you then manage access by changing group membership in your identity provider, which is auditable and survives people joining/leaving.

Roles

A role is a named collection of permissions. Permissions themselves (e.g. compute.instances.start) are never granted directly — always via a role. There are three tiers:

Role typeWhat it isExampleWhen to use
Basic (primitive)Legacy, very broad roles: roles/owner, roles/editor, roles/viewerroles/editor grants write on almost everythingAvoid in production — far too coarse
PredefinedGoogle-curated, service-scoped roles kept up to dateroles/compute.instanceAdmin.v1, roles/storage.objectViewerThe default choice — least-privilege without custom maintenance
CustomRoles you define from a hand-picked permission listroles/customDeployBotWhen no predefined role fits and you need tighter scope

Rule of thumb: start from the closest predefined role. Reach for a custom role only when a predefined one is too broad, and reserve basic roles for tiny sandbox projects (or never).

Allow policies & bindings

An allow policy attached to a resource is a list of bindings. Each binding ties one role to a set of members, optionally with a condition:

{
  "bindings": [
    {
      "role": "roles/storage.objectViewer",
      "members": [
        "group:analysts@example.com",
        "serviceAccount:etl@payments-prod.iam.gserviceaccount.com"
      ]
    },
    {
      "role": "roles/compute.instanceAdmin.v1",
      "members": ["group:sre@example.com"],
      "condition": {
        "title": "prod-only",
        "expression": "resource.name.startsWith('projects/payments-prod')"
      }
    }
  ],
  "etag": "BwY...",
  "version": 3
}

The etag provides optimistic concurrency (read-modify-write safely). version: 3 is required whenever conditions are present.

Inheritance down the hierarchy

The effective policy on a resource is the union of bindings set directly on it plus every binding inherited from its project, folders, and organization:

IAM bindings down the resource hierarchy
  1. Org
    group:security-admins → roles/iam.securityReviewerorg-wide read of IAM
  2. Folder "Engineering"
    group:eng-leads → roles/resourcemanager.folderViewer
  3. Project "payments-prod"
    group:payments-dev → roles/run.developer
  4. Resource (a bucket)
    serviceAccount:etl@… → roles/storage.objectAdmin

A member of security-admins gets its role on everything; payments-dev gets run.developer on that project only. Because grants only ever add permissions downward, IAM is deliberately permissive by design — the guardrails that can actually forbid things are Organization Policies and IAM Conditions / deny policies, not plain allow bindings.

Key Concepts

Service accounts

A service account (SA) is a special identity for non-human workloads. It is both an identity (it can be granted roles) and a resource (people/SAs can be granted roles on it, like the right to impersonate it). Three types:

Keys vs keyless — this is the single most important IAM decision.

ApproachMechanismRiskVerdict
SA keys (JSON)Downloadable long-lived private keyLeaks in Git, laptops, CI logs; never expiresAvoid. The #1 GCP credential-leak vector
Attached SAVM/Cloud Run/GKE runs as an SA; metadata server mints short-lived tokensTokens auto-rotate, never on diskPreferred for in-cloud workloads
ImpersonationA principal with roles/iam.serviceAccountTokenCreator mints a short-lived token for an SANo keys; audited; time-boxedPreferred for humans/CI acting as an SA
Workload Identity Federation (WIF)External IdP (GitHub, AWS, OIDC/SAML) exchanges its own token for a short-lived GCP tokenNo keys leave the external systemPreferred for GKE and external CI/CD

Impersonation example (run a command as a deploy SA, no key file):

gcloud storage ls gs://payments-artifacts \
  --impersonate-service-account=deployer@payments-prod.iam.gserviceaccount.com

Workload Identity for GKE maps a Kubernetes service account (KSA) to a Google service account (GSA) so pods get tokens with no mounted key:

gcloud iam service-accounts add-iam-policy-binding \
  my-gsa@payments-prod.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="serviceAccount:payments-prod.svc.id.goog[prod-ns/my-ksa]"
# then annotate the KSA:  iam.gke.io/gcp-service-account=my-gsa@payments-prod.iam.gserviceaccount.com

WIF for GitHub Actions — let a GitHub workflow authenticate with no stored secret, restricted to a specific repo:

# 1. Create a workload identity pool + OIDC provider for GitHub
gcloud iam workload-identity-pools create github-pool \
  --location=global --display-name="GitHub Actions"

gcloud iam workload-identity-pools providers create-oidc github-provider \
  --location=global --workload-identity-pool=github-pool \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
  --attribute-condition="assertion.repository=='my-org/my-repo'"

# 2. Let identities from that repo impersonate the deploy SA
gcloud iam service-accounts add-iam-policy-binding \
  deployer@payments-prod.iam.gserviceaccount.com \
  --role=roles/iam.workloadIdentityUser \
  --member="principalSet://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/github-pool/attribute.repository/my-org/my-repo"

The attribute-condition is critical — without pinning repository (or the branch/ref), any GitHub repo could exchange a token for your SA.

Example: granting a role with gcloud

# Grant a group a predefined role on a project
gcloud projects add-iam-policy-binding payments-prod \
  --member="group:payments-dev@example.com" \
  --role="roles/run.developer"

# Grant on a single resource (bucket) instead of the whole project
gcloud storage buckets add-iam-policy-binding gs://payments-artifacts \
  --member="serviceAccount:etl@payments-prod.iam.gserviceaccount.com" \
  --role="roles/storage.objectViewer"

# Inspect who has access
gcloud projects get-iam-policy payments-prod --format=json

IAM Conditions

Conditions add attribute-based rules on top of a binding using CEL (Common Expression Language). Common uses:

Conditions turn a broad role into a narrow, context-aware grant without inventing a custom role.

IAM deny policies

Allow policies only add access. Deny policies attach denial rules that are evaluated before allows and override them — the way to say “no one except X may ever do Y”, even if some inherited binding grants it. Use them for hard guardrails (e.g. deny iam.serviceAccountKeys.create org-wide).

Organization Policies vs IAM

Keep the two straight:

IAM (allow/deny policies)Organization Policy Service
QuestionWho can do what?What is allowed to exist / how?
GranularityMember + role + resourceConstraints on resource config
Example”SRE group can admin VMs""No VM may have an external IP”
Overrides Owners?Deny policies canYes — even Owners are bound

Org policies are the compliance guardrails (see Overview); IAM is the day-to-day access model.

IAM Recommender & least privilege

The IAM Recommender (part of Policy Intelligence) analyzes 90 days of actual usage and recommends removing unused permissions or swapping a broad role for a tighter one. Policy Analyzer answers “who can access this resource?” and “what can this member access?”. Together they let you drive toward least privilege with evidence rather than guesswork.

Best Practices

  1. Grant to groups, not individuals. Manage access by group membership in your IdP — auditable, and it survives joiners/leavers without policy edits.
  2. Prefer predefined roles over basic roles. Owner/Editor/Viewer are far too broad; predefined roles are curated and least-privilege by design.
  3. Never download service account keys. Use attached SAs, impersonation, or Workload Identity Federation. Enforce with iam.disableServiceAccountKeyCreation. Leaked keys are the top GCP breach vector.
  4. One dedicated SA per workload. Don’t share SAs across apps; a compromise should be contained to that one workload’s narrow permissions.
  5. Disable or de-privilege default service accounts. The Compute Engine default SA gets Editor — replace it with a least-privilege user-managed SA.
  6. Use Workload Identity Federation for CI/CD and external clouds. GitHub Actions, GitLab, and AWS workloads should exchange their native identity for short-lived GCP tokens — no secrets stored anywhere.
  7. Always pin WIF attribute conditions to a specific repo/branch/subject. An unpinned pool provider is effectively a public door into your project.
  8. Grant at the lowest effective node. Bind on the project or resource, not the org/folder, unless the access genuinely needs to be that broad — inheritance makes high grants very wide.
  9. Use IAM Conditions for time-boxed and scoped access. Elevate access for a window, or scope a role to a resource-name prefix, instead of a permanent broad grant.
  10. Use deny policies for hard “never” rules. Codify non-negotiables (no key creation, no deletion of audit sinks) so no inherited allow can override them.
  11. Run the IAM Recommender regularly and remove unused grants. Drive to least privilege with usage evidence; stale broad grants are silent risk.
  12. Separate duties across environments. Different groups/SAs for dev/staging/prod; no single human identity should hold prod admin by default.
  13. Reserve Owner for break-glass only. Keep it out of daily workflows; log and alert whenever it is used.
  14. Enable Cloud Audit Logs (Admin Activity + Data Access) and monitor IAM changes. Alert on new key creation, role grants at org/folder level, and setIamPolicy calls.
  15. Manage IAM as code (Terraform). Prefer authoritative-but-scoped resources like google_project_iam_member over _policy to avoid accidentally wiping bindings you don’t manage; review every change in PRs.

References