IAM roles for Google IAP TCP forwarding
IAP decides whether a tunnel may open by checking IAM. Getting the roles right is what turns "anyone in the project can reach every VM" into "this contractor can reach this one port on this one VM". Here are the roles involved, how to scope them, and where to see who used them.
1. The roles
| Role | Grants | Needed by |
|---|---|---|
roles/iap.tunnelResourceAccessor — IAP-secured Tunnel User | iap.tunnelInstances.accessViaIAP, iap.tunnelDestGroups.accessViaIAP: may open IAP tunnels to the instance(s) it's granted on | Everyone who connects |
roles/compute.instanceAdmin.v1 — Compute Instance Admin (v1) | Read instance details (compute.instances.get/list), push SSH keys to metadata, reset Windows passwords | People using gcloud compute ssh without OS Login, or reset-windows-password |
roles/compute.osLogin / roles/compute.osAdminLogin | Linux login via OS Login, without / with sudo | SSH users when OS Login is enabled |
roles/iam.serviceAccountUser | Act as the VM's service account | Required with reset-windows-password when the VM runs as a service account |
roles/iap.admin — IAP Policy Admin | Manage IAP access policies | Administrators only |
Note that tunnelResourceAccessor says nothing about the OS login — Windows passwords and
Linux keys are a separate layer.
2. Project-wide vs per-instance
Project-wide (every VM in the project):
gcloud projects add-iam-policy-binding PROJECT_ID \
--member=group:[email protected] \
--role=roles/iap.tunnelResourceAccessor
Per-instance — the least-privilege choice for contractors. Google documents two ways:
the console (Security → Identity-Aware Proxy → SSH and TCP Resources, tick the VM, add
the principal with the Tunnel User role) and the IAP API's setIamPolicy on the resource
projects/PROJECT_NUMBER/iap_tunnel/zones/ZONE/instances/INSTANCE_ID. Current gcloud
has no iap tcp add-iam-policy-binding command; setting the binding on the Compute
instance resource with gcloud compute instances add-iam-policy-binding is the approach
our Remote Targets guide uses. Tags cannot be used to
scope IAP tunnel access.
Prefer Google Groups as members: adding or removing a person from the group is the whole onboarding/offboarding step.
3. Narrowing with IAM conditions
A condition on the binding restricts when the role applies. Google's examples:
-
Only one port:
destination.port == 22 -
Only from a device/network that meets a Context-Aware Access level, to one internal IP and port:
"accessPolicies/POLICY_NAME/accessLevels/ACCESS_LEVEL_NAME" in request.auth.access_levels && destination.ip == "10.0.0.1" && destination.port == 22
Add a condition in the console when granting the role, or with
--condition=expression=...,title=... on add-iam-policy-binding. Access levels come from
Access Context Manager (corporate network, managed device, region) — this is how IAP
enforces "only from a company laptop" without a VPN.
4. Auditing who connected
IAP writes to Cloud Audit Logs. In Logs Explorer:
protoPayload.serviceName="iap.googleapis.com"
Useful fields in each entry: authenticationInfo.principalEmail (who),
requestMetadata.callerIp (from where), authorizationInfo.resource (which instance) and
authorizationInfo.granted (allowed or denied). Data Access audit logs for IAP must be
enabled for the project to record accesses (Admin Activity logs, such as SetIamPolicy,
are always on). Pair this with OS Login audit logs for the Linux side.
5. A least-privilege pattern that scales
- Create a Google Group per access tier (
vm-admins@,vm-rdp-contractors@). - Grant
roles/iap.tunnelResourceAccessorper instance (or with adestination.portcondition) to the contractor group; project-wide to the admin group. - Enable OS Login and grant
roles/compute.osLoginto the same groups; giveosAdminLoginonly to admins. - Require an access level for anything sensitive.
- Review
authorizationInfo.granted=falseentries monthly — they show attempted access that IAM refused.
Common questions
Can I grant access by VM tag?
No. Google's TCP forwarding documentation states tags are not supported for IAP tunnel permissions. Grant per instance or use conditions.
Does the Tunnel User role let someone log in to the OS?
No. It permits the tunnel only; Windows credentials, SSH keys or OS Login roles are still required.
Can I limit access to business hours?
IAM conditions support date/time expressions (request.time) alongside the
IAP-specific destination.* attributes.
Do I need Chrome Enterprise Premium for access levels?
Access Context Manager access levels can be used in IAP conditions; some advanced device signals are part of Chrome Enterprise Premium. Check the current product terms for your organisation.