Configure GCP Identity-Aware Proxy IAM Policies

The gcp:iap/webRegionBackendServiceIamPolicy:WebRegionBackendServiceIamPolicy resource, part of the Pulumi GCP provider, manages IAM policies for Identity-Aware Proxy regional backend services, controlling who can access IAP-protected resources. This guide focuses on three capabilities: authoritative policy replacement, role-based member grants, and time-based access conditions.

IAM management for IAP backend services comes in three forms: Policy (authoritative, replaces entire policy), Binding (authoritative for one role, preserves other roles), and Member (non-authoritative, adds one member to a role). The examples are intentionally small. Combine them with your own backend services and access requirements.

Grant a role to multiple members with Binding

Teams managing IAP access often need to grant the same role to multiple users or service accounts at once.

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

const binding = new gcp.iap.WebRegionBackendServiceIamBinding("binding", {
    project: _default.project,
    region: _default.region,
    webRegionBackendService: _default.name,
    role: "roles/iap.httpsResourceAccessor",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.iap.WebRegionBackendServiceIamBinding("binding",
    project=default["project"],
    region=default["region"],
    web_region_backend_service=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.NewWebRegionBackendServiceIamBinding(ctx, "binding", &iap.WebRegionBackendServiceIamBindingArgs{
			Project:                 pulumi.Any(_default.Project),
			Region:                  pulumi.Any(_default.Region),
			WebRegionBackendService: 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.WebRegionBackendServiceIamBinding("binding", new()
    {
        Project = @default.Project,
        Region = @default.Region,
        WebRegionBackendService = @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.WebRegionBackendServiceIamBinding;
import com.pulumi.gcp.iap.WebRegionBackendServiceIamBindingArgs;
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 WebRegionBackendServiceIamBinding("binding", WebRegionBackendServiceIamBindingArgs.builder()
            .project(default_.project())
            .region(default_.region())
            .webRegionBackendService(default_.name())
            .role("roles/iap.httpsResourceAccessor")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:iap:WebRegionBackendServiceIamBinding
    properties:
      project: ${default.project}
      region: ${default.region}
      webRegionBackendService: ${default.name}
      role: roles/iap.httpsResourceAccessor
      members:
        - user:jane@example.com

The WebRegionBackendServiceIamBinding resource manages all members for a specific role while preserving other roles in the policy. The members property lists all identities that should have the role; the role property specifies which IAP permission to grant. This approach is authoritative for the specified role but non-authoritative for the overall policy.

Add a single member to a role with Member

When you need to grant access to one user without affecting other members of the role, Member resources provide non-authoritative updates.

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

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

member = gcp.iap.WebRegionBackendServiceIamMember("member",
    project=default["project"],
    region=default["region"],
    web_region_backend_service=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.NewWebRegionBackendServiceIamMember(ctx, "member", &iap.WebRegionBackendServiceIamMemberArgs{
			Project:                 pulumi.Any(_default.Project),
			Region:                  pulumi.Any(_default.Region),
			WebRegionBackendService: 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.WebRegionBackendServiceIamMember("member", new()
    {
        Project = @default.Project,
        Region = @default.Region,
        WebRegionBackendService = @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.WebRegionBackendServiceIamMember;
import com.pulumi.gcp.iap.WebRegionBackendServiceIamMemberArgs;
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 WebRegionBackendServiceIamMember("member", WebRegionBackendServiceIamMemberArgs.builder()
            .project(default_.project())
            .region(default_.region())
            .webRegionBackendService(default_.name())
            .role("roles/iap.httpsResourceAccessor")
            .member("user:jane@example.com")
            .build());

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

The WebRegionBackendServiceIamMember resource adds one identity to a role without replacing existing members. The member property specifies a single identity (user, service account, or group). Multiple Member resources can target the same role, and they can coexist with Binding resources as long as they don’t manage the same role.

Replace the entire IAM policy with Policy

Some deployments require complete control over the IAM policy, replacing any existing grants with a new authoritative configuration.

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

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/iap.httpsResourceAccessor",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.iap.WebRegionBackendServiceIamPolicy("policy", {
    project: _default.project,
    region: _default.region,
    webRegionBackendService: _default.name,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/iap.httpsResourceAccessor",
    "members": ["user:jane@example.com"],
}])
policy = gcp.iap.WebRegionBackendServiceIamPolicy("policy",
    project=default["project"],
    region=default["region"],
    web_region_backend_service=default["name"],
    policy_data=admin.policy_data)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		admin, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/iap.httpsResourceAccessor",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = iap.NewWebRegionBackendServiceIamPolicy(ctx, "policy", &iap.WebRegionBackendServiceIamPolicyArgs{
			Project:                 pulumi.Any(_default.Project),
			Region:                  pulumi.Any(_default.Region),
			WebRegionBackendService: pulumi.Any(_default.Name),
			PolicyData:              pulumi.String(admin.PolicyData),
		})
		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 admin = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/iap.httpsResourceAccessor",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.Iap.WebRegionBackendServiceIamPolicy("policy", new()
    {
        Project = @default.Project,
        Region = @default.Region,
        WebRegionBackendService = @default.Name,
        PolicyData = admin.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.iap.WebRegionBackendServiceIamPolicy;
import com.pulumi.gcp.iap.WebRegionBackendServiceIamPolicyArgs;
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) {
        final var admin = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/iap.httpsResourceAccessor")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new WebRegionBackendServiceIamPolicy("policy", WebRegionBackendServiceIamPolicyArgs.builder()
            .project(default_.project())
            .region(default_.region())
            .webRegionBackendService(default_.name())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:iap:WebRegionBackendServiceIamPolicy
    properties:
      project: ${default.project}
      region: ${default.region}
      webRegionBackendService: ${default.name}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/iap.httpsResourceAccessor
            members:
              - user:jane@example.com

The WebRegionBackendServiceIamPolicy resource sets the complete IAM policy from a data source. The policyData property comes from gcp.organizations.getIAMPolicy, which constructs the policy structure with bindings. This resource cannot be used alongside Binding or Member resources because it replaces the entire policy, not just specific roles or members.

Apply time-based access with IAM Conditions

Access requirements often include temporal constraints, such as granting permissions that expire after a specific date.

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

const binding = new gcp.iap.WebRegionBackendServiceIamBinding("binding", {
    project: _default.project,
    region: _default.region,
    webRegionBackendService: _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.WebRegionBackendServiceIamBinding("binding",
    project=default["project"],
    region=default["region"],
    web_region_backend_service=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.NewWebRegionBackendServiceIamBinding(ctx, "binding", &iap.WebRegionBackendServiceIamBindingArgs{
			Project:                 pulumi.Any(_default.Project),
			Region:                  pulumi.Any(_default.Region),
			WebRegionBackendService: pulumi.Any(_default.Name),
			Role:                    pulumi.String("roles/iap.httpsResourceAccessor"),
			Members: pulumi.StringArray{
				pulumi.String("user:jane@example.com"),
			},
			Condition: &iap.WebRegionBackendServiceIamBindingConditionArgs{
				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.WebRegionBackendServiceIamBinding("binding", new()
    {
        Project = @default.Project,
        Region = @default.Region,
        WebRegionBackendService = @default.Name,
        Role = "roles/iap.httpsResourceAccessor",
        Members = new[]
        {
            "user:jane@example.com",
        },
        Condition = new Gcp.Iap.Inputs.WebRegionBackendServiceIamBindingConditionArgs
        {
            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.WebRegionBackendServiceIamBinding;
import com.pulumi.gcp.iap.WebRegionBackendServiceIamBindingArgs;
import com.pulumi.gcp.iap.inputs.WebRegionBackendServiceIamBindingConditionArgs;
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 WebRegionBackendServiceIamBinding("binding", WebRegionBackendServiceIamBindingArgs.builder()
            .project(default_.project())
            .region(default_.region())
            .webRegionBackendService(default_.name())
            .role("roles/iap.httpsResourceAccessor")
            .members("user:jane@example.com")
            .condition(WebRegionBackendServiceIamBindingConditionArgs.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:WebRegionBackendServiceIamBinding
    properties:
      project: ${default.project}
      region: ${default.region}
      webRegionBackendService: ${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")

IAM Conditions add constraint expressions to role grants. The condition block requires a title, optional description, and an expression using Common Expression Language (CEL). The expression compares request.time against a timestamp to enforce expiration. Conditions work with Binding and Member resources but have known limitations documented by Google Cloud.

Beyond these examples

These snippets focus on specific IAM management features: authoritative vs non-authoritative IAM management, role-based access control, and time-based access with IAM Conditions. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as regional backend services (webRegionBackendService) and GCP project and region configuration. They focus on configuring IAM policies rather than provisioning the backend services themselves.

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

  • Policy data source for reading existing policies
  • Combining Binding and Member resources for the same role
  • Custom IAM roles (examples use predefined roles/iap.httpsResourceAccessor)
  • Advanced condition expressions (resource attributes, request context)

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

Let's configure GCP Identity-Aware Proxy IAM Policies

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
Which IAM resource should I use: Policy, Binding, or Member?
Use gcp.iap.WebRegionBackendServiceIamPolicy for full policy control (replaces entire policy), gcp.iap.WebRegionBackendServiceIamBinding to manage all members for a specific role (preserves other roles), or gcp.iap.WebRegionBackendServiceIamMember to add individual members (preserves other members and roles).
Why am I getting conflicts between my IAM resources?
gcp.iap.WebRegionBackendServiceIamPolicy cannot be used with gcp.iap.WebRegionBackendServiceIamBinding or gcp.iap.WebRegionBackendServiceIamMember because they will conflict over policy management. Choose one approach for your use case.
Can I use Binding and Member resources together?
Yes, but only if they manage different roles. gcp.iap.WebRegionBackendServiceIamBinding and gcp.iap.WebRegionBackendServiceIamMember will conflict if they grant privileges to the same role.
IAM Conditions
How do I add time-based or conditional access controls?
Add a condition block with title, description, and expression fields. For example, use expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")" for time-based expiration.
Are there any limitations with IAM Conditions?
Yes, IAM Conditions have known limitations. Review the Google Cloud documentation at https://cloud.google.com/iam/docs/conditions-overview#limitations if you encounter issues.
Configuration & Properties
What properties are immutable after creation?
The project, region, and webRegionBackendService properties are immutable and cannot be changed after resource creation.
How do I generate the policy data for WebRegionBackendServiceIamPolicy?
Use the gcp.organizations.getIAMPolicy data source to generate policyData, then pass it to the policyData property as shown in the examples.

Using a different cloud?

Explore iam guides for other cloud providers: