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

RoleGrantsNeeded by
roles/iap.tunnelResourceAccessor — IAP-secured Tunnel Useriap.tunnelInstances.accessViaIAP, iap.tunnelDestGroups.accessViaIAP: may open IAP tunnels to the instance(s) it's granted onEveryone who connects
roles/compute.instanceAdmin.v1 — Compute Instance Admin (v1)Read instance details (compute.instances.get/list), push SSH keys to metadata, reset Windows passwordsPeople using gcloud compute ssh without OS Login, or reset-windows-password
roles/compute.osLogin / roles/compute.osAdminLoginLinux login via OS Login, without / with sudoSSH users when OS Login is enabled
roles/iam.serviceAccountUserAct as the VM's service accountRequired with reset-windows-password when the VM runs as a service account
roles/iap.admin — IAP Policy AdminManage IAP access policiesAdministrators 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

  1. Create a Google Group per access tier (vm-admins@, vm-rdp-contractors@).
  2. Grant roles/iap.tunnelResourceAccessor per instance (or with a destination.port condition) to the contractor group; project-wide to the admin group.
  3. Enable OS Login and grant roles/compute.osLogin to the same groups; give osAdminLogin only to admins.
  4. Require an access level for anything sensitive.
  5. Review authorizationInfo.granted=false entries 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.

Sources