Manage GCP Subnetwork IAM Permissions

The gcp:compute/subnetworkIAMMember:SubnetworkIAMMember resource, part of the Pulumi GCP provider, grants IAM roles to individual members on VPC subnetworks without affecting other members or roles. This guide focuses on two capabilities: non-authoritative member grants and time-based IAM Conditions.

This resource is one of three IAM management options for subnetworks. SubnetworkIAMMember is non-authoritative: it adds one member to one role while preserving other members and roles. SubnetworkIAMBinding manages all members for a single role authoritatively, and SubnetworkIAMPolicy replaces the entire IAM policy. The examples are intentionally small. Combine them with your own VPC subnetworks and identity management.

Grant a single user access to a subnetwork

Most IAM configurations add individual users or service accounts to specific subnetworks without disrupting existing permissions.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const member = new gcp.compute.SubnetworkIAMMember("member", {
    project: network_with_private_secondary_ip_ranges.project,
    region: network_with_private_secondary_ip_ranges.region,
    subnetwork: network_with_private_secondary_ip_ranges.name,
    role: "roles/compute.networkUser",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.compute.SubnetworkIAMMember("member",
    project=network_with_private_secondary_ip_ranges["project"],
    region=network_with_private_secondary_ip_ranges["region"],
    subnetwork=network_with_private_secondary_ip_ranges["name"],
    role="roles/compute.networkUser",
    member="user:jane@example.com")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewSubnetworkIAMMember(ctx, "member", &compute.SubnetworkIAMMemberArgs{
			Project:    pulumi.Any(network_with_private_secondary_ip_ranges.Project),
			Region:     pulumi.Any(network_with_private_secondary_ip_ranges.Region),
			Subnetwork: pulumi.Any(network_with_private_secondary_ip_ranges.Name),
			Role:       pulumi.String("roles/compute.networkUser"),
			Member:     pulumi.String("user:jane@example.com"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var member = new Gcp.Compute.SubnetworkIAMMember("member", new()
    {
        Project = network_with_private_secondary_ip_ranges.Project,
        Region = network_with_private_secondary_ip_ranges.Region,
        Subnetwork = network_with_private_secondary_ip_ranges.Name,
        Role = "roles/compute.networkUser",
        Member = "user:jane@example.com",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.SubnetworkIAMMember;
import com.pulumi.gcp.compute.SubnetworkIAMMemberArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var member = new SubnetworkIAMMember("member", SubnetworkIAMMemberArgs.builder()
            .project(network_with_private_secondary_ip_ranges.project())
            .region(network_with_private_secondary_ip_ranges.region())
            .subnetwork(network_with_private_secondary_ip_ranges.name())
            .role("roles/compute.networkUser")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:compute:SubnetworkIAMMember
    properties:
      project: ${["network-with-private-secondary-ip-ranges"].project}
      region: ${["network-with-private-secondary-ip-ranges"].region}
      subnetwork: ${["network-with-private-secondary-ip-ranges"].name}
      role: roles/compute.networkUser
      member: user:jane@example.com

The member property specifies the identity to grant access, using formats like “user:jane@example.com” for Google accounts or “serviceAccount:app@project.iam.gserviceaccount.com” for service accounts. The role property sets the permission level; “roles/compute.networkUser” allows attaching instances to the subnetwork. The subnetwork, project, and region properties identify which subnetwork to grant access to. Because SubnetworkIAMMember is non-authoritative, it preserves other members with the same role and other roles on the subnetwork.

Grant time-limited access with IAM Conditions

Teams often need temporary access that expires automatically, such as contractor access or time-boxed testing.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const member = new gcp.compute.SubnetworkIAMMember("member", {
    project: network_with_private_secondary_ip_ranges.project,
    region: network_with_private_secondary_ip_ranges.region,
    subnetwork: network_with_private_secondary_ip_ranges.name,
    role: "roles/compute.networkUser",
    member: "user:jane@example.com",
    condition: {
        title: "expires_after_2019_12_31",
        description: "Expiring at midnight of 2019-12-31",
        expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
    },
});
import pulumi
import pulumi_gcp as gcp

member = gcp.compute.SubnetworkIAMMember("member",
    project=network_with_private_secondary_ip_ranges["project"],
    region=network_with_private_secondary_ip_ranges["region"],
    subnetwork=network_with_private_secondary_ip_ranges["name"],
    role="roles/compute.networkUser",
    member="user:jane@example.com",
    condition={
        "title": "expires_after_2019_12_31",
        "description": "Expiring at midnight of 2019-12-31",
        "expression": "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewSubnetworkIAMMember(ctx, "member", &compute.SubnetworkIAMMemberArgs{
			Project:    pulumi.Any(network_with_private_secondary_ip_ranges.Project),
			Region:     pulumi.Any(network_with_private_secondary_ip_ranges.Region),
			Subnetwork: pulumi.Any(network_with_private_secondary_ip_ranges.Name),
			Role:       pulumi.String("roles/compute.networkUser"),
			Member:     pulumi.String("user:jane@example.com"),
			Condition: &compute.SubnetworkIAMMemberConditionArgs{
				Title:       pulumi.String("expires_after_2019_12_31"),
				Description: pulumi.String("Expiring at midnight of 2019-12-31"),
				Expression:  pulumi.String("request.time < timestamp(\"2020-01-01T00:00:00Z\")"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var member = new Gcp.Compute.SubnetworkIAMMember("member", new()
    {
        Project = network_with_private_secondary_ip_ranges.Project,
        Region = network_with_private_secondary_ip_ranges.Region,
        Subnetwork = network_with_private_secondary_ip_ranges.Name,
        Role = "roles/compute.networkUser",
        Member = "user:jane@example.com",
        Condition = new Gcp.Compute.Inputs.SubnetworkIAMMemberConditionArgs
        {
            Title = "expires_after_2019_12_31",
            Description = "Expiring at midnight of 2019-12-31",
            Expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.SubnetworkIAMMember;
import com.pulumi.gcp.compute.SubnetworkIAMMemberArgs;
import com.pulumi.gcp.compute.inputs.SubnetworkIAMMemberConditionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var member = new SubnetworkIAMMember("member", SubnetworkIAMMemberArgs.builder()
            .project(network_with_private_secondary_ip_ranges.project())
            .region(network_with_private_secondary_ip_ranges.region())
            .subnetwork(network_with_private_secondary_ip_ranges.name())
            .role("roles/compute.networkUser")
            .member("user:jane@example.com")
            .condition(SubnetworkIAMMemberConditionArgs.builder()
                .title("expires_after_2019_12_31")
                .description("Expiring at midnight of 2019-12-31")
                .expression("request.time < timestamp(\"2020-01-01T00:00:00Z\")")
                .build())
            .build());

    }
}
resources:
  member:
    type: gcp:compute:SubnetworkIAMMember
    properties:
      project: ${["network-with-private-secondary-ip-ranges"].project}
      region: ${["network-with-private-secondary-ip-ranges"].region}
      subnetwork: ${["network-with-private-secondary-ip-ranges"].name}
      role: roles/compute.networkUser
      member: user:jane@example.com
      condition:
        title: expires_after_2019_12_31
        description: Expiring at midnight of 2019-12-31
        expression: request.time < timestamp("2020-01-01T00:00:00Z")

The condition block adds time-based or attribute-based restrictions to the grant. The expression property uses Common Expression Language (CEL) to define the condition; here, “request.time < timestamp(…)” expires access at midnight on 2020-01-01. The title property provides a unique identifier for the condition, and description explains its purpose. IAM Conditions have some limitations documented in the GCP IAM Conditions overview; review those if you encounter issues with complex conditions.

Beyond these examples

These snippets focus on specific SubnetworkIAMMember features: single-member IAM grants and time-based IAM Conditions. They’re intentionally minimal rather than full IAM policies.

The examples reference pre-existing infrastructure such as VPC subnetworks (by name, project, and region). They focus on granting access to one member rather than managing complete IAM policies.

To keep things focused, common IAM patterns are omitted, including:

  • Authoritative policy management (SubnetworkIAMPolicy)
  • Role-level binding management (SubnetworkIAMBinding)
  • Service account and group identities
  • Federated identity and workload identity pool principals

These omissions are intentional: the goal is to illustrate how SubnetworkIAMMember grants are wired, not provide drop-in IAM modules. See the SubnetworkIAMMember resource reference for all available configuration options.

Let's manage GCP Subnetwork IAM Permissions

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Selection & Conflicts
What's the difference between SubnetworkIAMPolicy, SubnetworkIAMBinding, and SubnetworkIAMMember?
SubnetworkIAMPolicy is authoritative and replaces the entire IAM policy. SubnetworkIAMBinding is authoritative for a specific role, updating the member list while preserving other roles. SubnetworkIAMMember is non-authoritative, adding a single member to a role while preserving other members.
Can I use these IAM resources together on the same subnetwork?
SubnetworkIAMPolicy cannot be used with SubnetworkIAMBinding or SubnetworkIAMMember as they will conflict. However, SubnetworkIAMBinding and SubnetworkIAMMember can be used together only if they manage different roles.
Member & Role Configuration
What member identity formats are supported?
Supported formats include allUsers, allAuthenticatedUsers, user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, projectOwner/Editor/Viewer:{projectid}, and federated identities like principal://iam.googleapis.com/....
How do I specify a custom IAM role?
Custom roles must use the format [projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role.
IAM Conditions & Advanced Features
How do I add time-based or conditional access restrictions?
Use the condition property with title, description, and expression fields. For example, to expire access at a specific time: expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")".
Are there any limitations with IAM Conditions?
IAM Conditions are supported but have known limitations. Review the limitations before using conditions, particularly for complex scenarios.

Using a different cloud?

Explore security guides for other cloud providers: