GCP IAM roles, service accounts and keyless access
Most Google Cloud access problems come down to two questions: which role should this principal get, and where in the hierarchy should it be granted? The third question, which matters more every year, is how a workload proves who it is without someone downloading a long-lived key file and leaving it in a repository.
The Associate Cloud Engineer exam asks these as hands-on tasks: grant the right role at the right level, attach a service account to a VM, let a developer act as a service account. The Professional Cloud Architect exam asks the same thing at organisation scale: central guardrails, least privilege across hundreds of projects, and getting rid of keys entirely. The answers that win are almost always the narrowest role, granted at the highest level that still covers exactly the right resources, with no keys involved.
How an IAM grant works
Access in Google Cloud is an allow policy attached to a resource. The policy holds role bindings, and each binding connects a role to one or more principals: Google accounts, Google groups, service accounts, Cloud Identity domains, or federated identities. A role is a named collection of permissions such as compute.instances.start. You never grant a permission directly; you grant a role that contains it.
The three kinds of role
Basic roles
Owner, Editor and Viewer existed before IAM and apply across nearly every service in a project. Viewer reads, Editor reads and changes most things, and Owner adds managing access and billing. Each holds thousands of permissions, and you can't put IAM Conditions on bindings of these legacy roles. Google's own guidance is not to grant basic roles in production unless there is no alternative. Google has also introduced newer broad roles named Admin, Writer and Reader, currently in Preview; the same caution applies to them.
Predefined roles
Google writes and maintains predefined roles per service, such as roles/compute.viewer, roles/storage.objectViewer or roles/pubsub.publisher. When a service adds a permission, Google updates the role for you. These should be your default choice, and exam answers that use one are usually better than answers that use a basic role.
Custom roles
When no predefined role fits, for example an application must read and create objects but never delete them, you build a custom role with exactly the permissions needed. Custom roles live at the organisation or project level; you can't define one on a folder. A project-level custom role can only be granted inside that project. There is a limit of 300 custom roles per organisation and 300 per project. Some permissions are marked as testing or not supported in custom roles, and because Google doesn't maintain your custom role, you have to update it yourself when services change.
Inheritance down the resource hierarchy
The hierarchy runs organisation, then folders (optional, up to 10 levels deep), then projects, then the resources inside them. An allow policy on any node applies to everything below it, and the effective policy on a resource is the union of its own policy and every ancestor's.
Two consequences follow, and exams test both:
- A grant at a folder automatically covers every project in it, including projects created next month. That is usually the least-effort way to give a team access to "all our retail projects".
- A lower level can only add access. If Editor is granted on a folder, removing Editor from one project inside it does nothing, because the folder binding still applies.
To take access away from above, Google Cloud has IAM deny policies. They attach to an organisation, folder or project, flow down like allow policies, and are checked before any allow policy, so a denied permission stays denied whatever roles the principal holds. Deny rules can list exception principals, such as a break-glass group.
Keep organisation policies separate in your head. They restrict what configurations are allowed (which regions, whether external IPs are allowed, which domains can appear in allow policies, whether keys can be created) rather than who can do what. They are often the right answer when a question says "nobody, regardless of role".
Service accounts
A service account is an identity for a workload rather than a person. It is unusual in being two things at once:
- a principal, which you grant roles to so it can reach resources, and
- a resource, with its own allow policy that says which people may use it.
There are three kinds. User-managed service accounts are the ones you create, and the ones you should use for your own workloads. Default service accounts are created when you enable some services, such as the Compute Engine default account. Service agents are created and managed by Google so a service can act on your resources.
The Compute Engine and App Engine default service accounts used to be granted Editor on the project automatically. The iam.automaticIamGrantsForDefaultServiceAccounts organisation policy stops that, and it is enforced by default for organisations created on or after 3 May 2024. Older organisations may still have default accounts with Editor, which is why a security review flags VMs running as them. The fix is a dedicated user-managed service account with only the roles that one workload needs.
Two roles on a service account are easy to confuse:
- Service Account User (
roles/iam.serviceAccountUser) lets a person attach the service account to a resource, for example create a VM that runs as it. - Service Account Token Creator (
roles/iam.serviceAccountTokenCreator) lets a person get short-lived tokens for the service account and act as it directly. That is impersonation.
Grant either one on the specific service account, not on the whole project, or the person can use every service account in the project.
Impersonation instead of keys
A service account key is a long-lived private key. Anyone who copies the file is the service account until someone notices and deletes the key. Google treats keys as a security risk and gives you organisation policies to block them, iam.disableServiceAccountKeyCreation and iam.disableServiceAccountKeyUpload, both enforced by default for organisations created on or after 3 May 2024.
For a person, the alternative is impersonation. With Token Creator on the service account, a developer runs gcloud with --impersonate-service-account and gcloud fetches short-lived credentials for each command. Nothing is stored on disk, the developer's own account holds none of the service account's roles, and most audit log entries record both the developer and the service account.
For a workload on Google Cloud, attach the service account to the resource (VM, Cloud Run service, function) and let the client libraries pick up credentials from the metadata server. On GKE, use Workload Identity Federation for GKE so one pod gets one identity instead of every pod inheriting the node's service account.
Workload Identity Federation for outside workloads
For workloads outside Google Cloud, such as a GitHub Actions pipeline, an AWS workload, an Azure workload or an on-premises system with an OIDC or SAML identity provider, use Workload Identity Federation. You create a workload identity pool and a provider that trusts the external identity provider. The external workload presents its own token, Google's Security Token Service exchanges it, and the workload receives short-lived Google credentials.
Two settings do the security work. Attribute mappings turn claims in the external token into attributes such as google.subject. Attribute conditions reject tokens that don't match, for example anything not from your own GitHub organisation or repository. Leave out the condition and you may be trusting far more identities than you meant to. The federated identity can then be granted roles on resources directly, which Google recommends where the API supports it, or be allowed to impersonate a service account through the Workload Identity User role.
How to choose
- Start from a predefined role. Use a custom role only when no predefined role is narrow enough. Use basic roles only in sandboxes.
- Grant to groups, not individual users, so joiners and leavers are handled in one place.
- Grant at the lowest node that covers everything the team needs and nothing else: a folder for "all projects in this department", a bucket or topic for "only this one resource".
- To block something everywhere regardless of grants, reach for a deny policy (who can use a permission) or an organisation policy (what configuration is allowed).
- Give each workload its own user-managed service account with only the roles it uses.
- People who need to act as a service account get Token Creator on that account and impersonate.
- Workloads outside Google Cloud use Workload Identity Federation. A key is the last resort.
Common exam traps
- Removing a role at the project to cancel a folder grant. Inheritance is a union; the folder grant still applies. Change it at the folder or use a deny policy.
- Picking a basic role because it "covers everything". Editor works, but it is never the least privilege answer when a predefined role exists.
- Trying to create a custom role on a folder. Custom roles live at the organisation or project.
- Mixing up Service Account User and Token Creator. One lets you attach the account to a resource; the other lets you act as it.
- Solving a CI/CD credential problem with a key stored as a secret. If the question mentions short-lived credentials or a ban on keys, the answer is Workload Identity Federation.
- Granting Token Creator on the project. That allows impersonating every service account in it.
A worked example
A company has an analytics folder with eight projects. Its data engineers need to run BigQuery jobs in all of them, including projects added later. A nightly pipeline in GitHub Actions loads files into one bucket in the analytics-prod project. Security forbids service account keys.
For the engineers, grant the predefined BigQuery roles they need, such as BigQuery Job User and BigQuery Data Viewer, to their Google group on the analytics folder. Inheritance covers all eight projects and any new ones, and nothing outside the folder. Granting at the organisation would be too broad; granting project by project would miss future projects.
For the pipeline, create a workload identity pool and an OIDC provider for GitHub with an attribute condition limited to the company's repository. Grant the federated principal Storage Object Creator on that one bucket, or let it impersonate a dedicated service account that holds that role. No key exists anywhere, and the credentials the pipeline gets expire on their own.
Practice questions
- Read-only access for a whole folder of projects
- Running gcloud as a service account under a key ban
- Read and create objects, never delete
- A VM running as an over-privileged default account
- Authenticating a GitHub Actions pipeline
- Keeping outside accounts out of every allow policy