Manage GCP Identity-Aware Proxy IAM Permissions

The gcp:iap/webForwardingRuleServiceIamMember:WebForwardingRuleServiceIamMember resource, part of the Pulumi GCP provider, grants IAM roles to individual members for Identity-Aware Proxy protected forwarding rules while preserving other role assignments. This guide focuses on two capabilities: single-member role grants and time-based access with IAM Conditions.

This resource is non-authoritative, meaning it adds one identity to one role without removing other members or affecting other roles. It references existing forwarding rules and projects. The examples are intentionally small. Combine them with your own IAP-protected infrastructure and access policies.

Grant access to a single user

Most IAP access control starts by granting individual users permission to access resources behind the proxy.

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

const member = new gcp.iap.WebForwardingRuleServiceIamMember("member", {
    project: _default.project,
    forwardingRuleServiceName: _default.name,
    role: "roles/iap.httpsResourceAccessor",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.iap.WebForwardingRuleServiceIamMember("member",
    project=default["project"],
    forwarding_rule_service_name=default["name"],
    role="roles/iap.httpsResourceAccessor",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := iap.NewWebForwardingRuleServiceIamMember(ctx, "member", &iap.WebForwardingRuleServiceIamMemberArgs{
			Project:                   pulumi.Any(_default.Project),
			ForwardingRuleServiceName: pulumi.Any(_default.Name),
			Role:                      pulumi.String("roles/iap.httpsResourceAccessor"),
			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.Iap.WebForwardingRuleServiceIamMember("member", new()
    {
        Project = @default.Project,
        ForwardingRuleServiceName = @default.Name,
        Role = "roles/iap.httpsResourceAccessor",
        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.iap.WebForwardingRuleServiceIamMember;
import com.pulumi.gcp.iap.WebForwardingRuleServiceIamMemberArgs;
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 WebForwardingRuleServiceIamMember("member", WebForwardingRuleServiceIamMemberArgs.builder()
            .project(default_.project())
            .forwardingRuleServiceName(default_.name())
            .role("roles/iap.httpsResourceAccessor")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:iap:WebForwardingRuleServiceIamMember
    properties:
      project: ${default.project}
      forwardingRuleServiceName: ${default.name}
      role: roles/iap.httpsResourceAccessor
      member: user:jane@example.com

The member property specifies the identity receiving access (user, service account, group, or domain). The role property defines the permission level; roles/iap.httpsResourceAccessor allows HTTPS access through IAP. The forwardingRuleServiceName identifies which forwarding rule this grant applies to. This resource is non-authoritative: it adds this member without affecting other members already granted the same role or other roles on the same resource.

Grant time-limited access with IAM Conditions

Teams often need temporary access for contractors or time-bound projects.

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

const member = new gcp.iap.WebForwardingRuleServiceIamMember("member", {
    project: _default.project,
    forwardingRuleServiceName: _default.name,
    role: "roles/iap.httpsResourceAccessor",
    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.iap.WebForwardingRuleServiceIamMember("member",
    project=default["project"],
    forwarding_rule_service_name=default["name"],
    role="roles/iap.httpsResourceAccessor",
    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/iap"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := iap.NewWebForwardingRuleServiceIamMember(ctx, "member", &iap.WebForwardingRuleServiceIamMemberArgs{
			Project:                   pulumi.Any(_default.Project),
			ForwardingRuleServiceName: pulumi.Any(_default.Name),
			Role:                      pulumi.String("roles/iap.httpsResourceAccessor"),
			Member:                    pulumi.String("user:jane@example.com"),
			Condition: &iap.WebForwardingRuleServiceIamMemberConditionArgs{
				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.Iap.WebForwardingRuleServiceIamMember("member", new()
    {
        Project = @default.Project,
        ForwardingRuleServiceName = @default.Name,
        Role = "roles/iap.httpsResourceAccessor",
        Member = "user:jane@example.com",
        Condition = new Gcp.Iap.Inputs.WebForwardingRuleServiceIamMemberConditionArgs
        {
            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.iap.WebForwardingRuleServiceIamMember;
import com.pulumi.gcp.iap.WebForwardingRuleServiceIamMemberArgs;
import com.pulumi.gcp.iap.inputs.WebForwardingRuleServiceIamMemberConditionArgs;
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 WebForwardingRuleServiceIamMember("member", WebForwardingRuleServiceIamMemberArgs.builder()
            .project(default_.project())
            .forwardingRuleServiceName(default_.name())
            .role("roles/iap.httpsResourceAccessor")
            .member("user:jane@example.com")
            .condition(WebForwardingRuleServiceIamMemberConditionArgs.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:iap:WebForwardingRuleServiceIamMember
    properties:
      project: ${default.project}
      forwardingRuleServiceName: ${default.name}
      role: roles/iap.httpsResourceAccessor
      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 attaches constraints to the role grant. The expression property uses CEL (Common Expression Language) to define when the grant is valid; here, it expires at midnight on 2020-01-01. The title and description properties document the condition’s purpose. IAM Conditions have known limitations around certain resource types and condition combinations; see the GCP documentation for details.

Beyond these examples

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

The examples reference pre-existing infrastructure such as forwarding rules (referenced by forwardingRuleServiceName) and GCP projects. They focus on granting access rather than provisioning the IAP-protected resources themselves.

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

  • Policy and Binding resources (authoritative alternatives)
  • Multiple members or roles in one resource
  • Non-time-based conditions (resource attributes, request context)
  • Custom role definitions

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

Let's manage GCP Identity-Aware Proxy 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 & Usage
What's the difference between IamPolicy, IamBinding, and IamMember?
gcp.iap.WebForwardingRuleServiceIamPolicy is authoritative and replaces the entire IAM policy. gcp.iap.WebForwardingRuleServiceIamBinding is authoritative for a specific role, preserving other roles. gcp.iap.WebForwardingRuleServiceIamMember is non-authoritative and adds a single member to a role without affecting other members.
Can I mix these IAM resource types?
gcp.iap.WebForwardingRuleServiceIamPolicy cannot be used with gcp.iap.WebForwardingRuleServiceIamBinding or gcp.iap.WebForwardingRuleServiceIamMember, as they will conflict. However, gcp.iap.WebForwardingRuleServiceIamBinding and gcp.iap.WebForwardingRuleServiceIamMember can be used together only if they don’t grant privileges to the same role.
IAM Configuration
How do I specify custom roles?
Custom roles must use the full path format: [projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role or organizations/my-org/roles/my-custom-role.
How do I add time-based access with IAM Conditions?
Set the condition property with title, description, and expression fields. The expression uses CEL syntax, for example: request.time < timestamp("2020-01-01T00:00:00Z") for time-based expiration.
What member identity formats are supported?
Supported formats include user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, allUsers, allAuthenticatedUsers, projectOwner:projectid, projectEditor:projectid, projectViewer:projectid, and federated identities like principal://iam.googleapis.com/....
Common Pitfalls & Limitations
What properties can't be changed after creation?
All properties are immutable: forwardingRuleServiceName, member, project, role, and condition. Any changes require recreating the resource.
Are there limitations with IAM Conditions?
IAM Conditions are supported but have known limitations. If you experience issues with IAM Conditions, review the limitations documentation linked in the schema.

Using a different cloud?

Explore security guides for other cloud providers: