The gcp:iap/webForwardingRuleServiceIamBinding:WebForwardingRuleServiceIamBinding resource, part of the Pulumi GCP provider, manages IAM role bindings for Identity-Aware Proxy forwarding rule services. This resource is authoritative for a given role, meaning it controls the complete list of members who have that role. This guide focuses on three capabilities: granting roles to multiple members, adding time-based access with IAM Conditions, and adding individual members non-authoritatively.
IAM bindings reference existing IAP-protected forwarding rule services and require a configured GCP project. The examples are intentionally small. Combine them with your own forwarding rule infrastructure and access policies.
Grant a role to multiple members with Binding
When managing access to IAP-protected load balancers, you often need to grant the same role to multiple users or service accounts as a group.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const binding = new gcp.iap.WebForwardingRuleServiceIamBinding("binding", {
project: _default.project,
forwardingRuleServiceName: _default.name,
role: "roles/iap.httpsResourceAccessor",
members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp
binding = gcp.iap.WebForwardingRuleServiceIamBinding("binding",
project=default["project"],
forwarding_rule_service_name=default["name"],
role="roles/iap.httpsResourceAccessor",
members=["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.NewWebForwardingRuleServiceIamBinding(ctx, "binding", &iap.WebForwardingRuleServiceIamBindingArgs{
Project: pulumi.Any(_default.Project),
ForwardingRuleServiceName: pulumi.Any(_default.Name),
Role: pulumi.String("roles/iap.httpsResourceAccessor"),
Members: pulumi.StringArray{
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 binding = new Gcp.Iap.WebForwardingRuleServiceIamBinding("binding", new()
{
Project = @default.Project,
ForwardingRuleServiceName = @default.Name,
Role = "roles/iap.httpsResourceAccessor",
Members = new[]
{
"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.WebForwardingRuleServiceIamBinding;
import com.pulumi.gcp.iap.WebForwardingRuleServiceIamBindingArgs;
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 binding = new WebForwardingRuleServiceIamBinding("binding", WebForwardingRuleServiceIamBindingArgs.builder()
.project(default_.project())
.forwardingRuleServiceName(default_.name())
.role("roles/iap.httpsResourceAccessor")
.members("user:jane@example.com")
.build());
}
}
resources:
binding:
type: gcp:iap:WebForwardingRuleServiceIamBinding
properties:
project: ${default.project}
forwardingRuleServiceName: ${default.name}
role: roles/iap.httpsResourceAccessor
members:
- user:jane@example.com
The Binding resource is authoritative for the specified role. The members array lists all identities that should have the role; any members not in this list will lose access. The forwardingRuleServiceName identifies which IAP-protected service receives the binding. Use this when you want to manage all members of a role together.
Add time-based access with IAM Conditions
Organizations with temporary contractors or time-limited projects can use IAM Conditions to automatically expire permissions.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const binding = new gcp.iap.WebForwardingRuleServiceIamBinding("binding", {
project: _default.project,
forwardingRuleServiceName: _default.name,
role: "roles/iap.httpsResourceAccessor",
members: ["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
binding = gcp.iap.WebForwardingRuleServiceIamBinding("binding",
project=default["project"],
forwarding_rule_service_name=default["name"],
role="roles/iap.httpsResourceAccessor",
members=["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.NewWebForwardingRuleServiceIamBinding(ctx, "binding", &iap.WebForwardingRuleServiceIamBindingArgs{
Project: pulumi.Any(_default.Project),
ForwardingRuleServiceName: pulumi.Any(_default.Name),
Role: pulumi.String("roles/iap.httpsResourceAccessor"),
Members: pulumi.StringArray{
pulumi.String("user:jane@example.com"),
},
Condition: &iap.WebForwardingRuleServiceIamBindingConditionArgs{
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 binding = new Gcp.Iap.WebForwardingRuleServiceIamBinding("binding", new()
{
Project = @default.Project,
ForwardingRuleServiceName = @default.Name,
Role = "roles/iap.httpsResourceAccessor",
Members = new[]
{
"user:jane@example.com",
},
Condition = new Gcp.Iap.Inputs.WebForwardingRuleServiceIamBindingConditionArgs
{
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.WebForwardingRuleServiceIamBinding;
import com.pulumi.gcp.iap.WebForwardingRuleServiceIamBindingArgs;
import com.pulumi.gcp.iap.inputs.WebForwardingRuleServiceIamBindingConditionArgs;
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 binding = new WebForwardingRuleServiceIamBinding("binding", WebForwardingRuleServiceIamBindingArgs.builder()
.project(default_.project())
.forwardingRuleServiceName(default_.name())
.role("roles/iap.httpsResourceAccessor")
.members("user:jane@example.com")
.condition(WebForwardingRuleServiceIamBindingConditionArgs.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:
binding:
type: gcp:iap:WebForwardingRuleServiceIamBinding
properties:
project: ${default.project}
forwardingRuleServiceName: ${default.name}
role: roles/iap.httpsResourceAccessor
members:
- 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 a time constraint to the role binding. The expression uses CEL (Common Expression Language) to define when access is valid. Here, access expires at midnight on 2020-01-01. The title and description help identify the condition’s purpose in audit logs and the console.
Add a single member to a role with Member
When you need to grant access to one additional user without replacing the entire member list, use the Member resource.
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 resource is non-authoritative, meaning it adds one member to a role without affecting other members. This is useful when multiple teams manage access independently. The member property specifies a single identity using the same format as the members array in Binding (user:, serviceAccount:, group:, etc.).
Beyond these examples
These snippets focus on specific IAM binding features: role-based access control with Binding and Member resources, and time-based access with IAM Conditions. They’re intentionally minimal rather than complete access control policies.
The examples reference pre-existing infrastructure such as IAP-protected forwarding rule services and a GCP project with IAP enabled. They focus on configuring IAM bindings rather than provisioning the underlying IAP infrastructure.
To keep things focused, common IAM patterns are omitted, including:
- Full policy replacement (IamPolicy resource)
- Custom role definitions
- Attribute-based conditions (resource tags, request attributes)
- Combining Binding and Member for different roles
These omissions are intentional: the goal is to illustrate how each IAM binding feature is wired, not provide drop-in access control modules. See the WebForwardingRuleServiceIamBinding resource reference for all available configuration options.
Let's manage GCP Identity-Aware Proxy IAM Bindings
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Resource Conflicts & Compatibility
WebForwardingRuleServiceIamPolicy cannot be used with WebForwardingRuleServiceIamBinding or WebForwardingRuleServiceIamMember as they will conflict over policy management. Choose either Policy (authoritative) or Binding/Member (non-authoritative).IAM Configuration & Roles
You can use:
- Users:
user:alice@example.com - Service accounts:
serviceAccount:my-app@appspot.gserviceaccount.com - Groups:
group:admins@example.com - Domains:
domain:example.com - Special identifiers:
allUsers,allAuthenticatedUsers - Project roles:
projectOwner:my-project,projectEditor:my-project,projectViewer:my-project - Federated identities:
principal://iam.googleapis.com/locations/global/workforcePools/...
[projects|organizations]/{parent-name}/roles/{role-name}. For example: projects/my-project/roles/my-custom-role or organizations/my-org/roles/my-custom-role.[projects/my-project|organizations/my-org]/roles/my-custom-role. Don’t use shortened formats during import.IAM Conditions
condition property with title, description, and expression fields. Example: expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")" to expire access at a specific time.condition property is immutable. You must recreate the binding to change conditions.