Manage GCP API Gateway IAM Access

The gcp:apigateway/gatewayIamMember:GatewayIamMember resource, part of the Pulumi GCP provider, grants IAM permissions on API Gateway gateways by adding individual members to roles without affecting other permissions. This guide focuses on three approaches: single-member grants with GatewayIamMember, role-level member management with GatewayIamBinding, and complete policy replacement with GatewayIamPolicy.

These resources reference existing API Gateway gateways and require project and region configuration. The examples are intentionally small. Combine them with your own gateway infrastructure and identity management strategy.

Grant a single user access to a gateway

Most IAM configurations start by granting individual users or service accounts access to specific resources without disrupting existing permissions.

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

const member = new gcp.apigateway.GatewayIamMember("member", {
    project: apiGw.project,
    region: apiGw.region,
    gateway: apiGw.gatewayId,
    role: "roles/apigateway.viewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.apigateway.GatewayIamMember("member",
    project=api_gw["project"],
    region=api_gw["region"],
    gateway=api_gw["gatewayId"],
    role="roles/apigateway.viewer",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := apigateway.NewGatewayIamMember(ctx, "member", &apigateway.GatewayIamMemberArgs{
			Project: pulumi.Any(apiGw.Project),
			Region:  pulumi.Any(apiGw.Region),
			Gateway: pulumi.Any(apiGw.GatewayId),
			Role:    pulumi.String("roles/apigateway.viewer"),
			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.ApiGateway.GatewayIamMember("member", new()
    {
        Project = apiGw.Project,
        Region = apiGw.Region,
        Gateway = apiGw.GatewayId,
        Role = "roles/apigateway.viewer",
        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.apigateway.GatewayIamMember;
import com.pulumi.gcp.apigateway.GatewayIamMemberArgs;
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 GatewayIamMember("member", GatewayIamMemberArgs.builder()
            .project(apiGw.project())
            .region(apiGw.region())
            .gateway(apiGw.gatewayId())
            .role("roles/apigateway.viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:apigateway:GatewayIamMember
    properties:
      project: ${apiGw.project}
      region: ${apiGw.region}
      gateway: ${apiGw.gatewayId}
      role: roles/apigateway.viewer
      member: user:jane@example.com

The member property specifies one identity (user, service account, group, or domain). The role property defines what that member can do. GatewayIamMember is non-authoritative: it adds this one member to this one role, preserving all other members and roles on the gateway.

Grant multiple users the same role

When multiple users need identical permissions, you can manage them together in one resource.

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

const binding = new gcp.apigateway.GatewayIamBinding("binding", {
    project: apiGw.project,
    region: apiGw.region,
    gateway: apiGw.gatewayId,
    role: "roles/apigateway.viewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.apigateway.GatewayIamBinding("binding",
    project=api_gw["project"],
    region=api_gw["region"],
    gateway=api_gw["gatewayId"],
    role="roles/apigateway.viewer",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := apigateway.NewGatewayIamBinding(ctx, "binding", &apigateway.GatewayIamBindingArgs{
			Project: pulumi.Any(apiGw.Project),
			Region:  pulumi.Any(apiGw.Region),
			Gateway: pulumi.Any(apiGw.GatewayId),
			Role:    pulumi.String("roles/apigateway.viewer"),
			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.ApiGateway.GatewayIamBinding("binding", new()
    {
        Project = apiGw.Project,
        Region = apiGw.Region,
        Gateway = apiGw.GatewayId,
        Role = "roles/apigateway.viewer",
        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.apigateway.GatewayIamBinding;
import com.pulumi.gcp.apigateway.GatewayIamBindingArgs;
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 GatewayIamBinding("binding", GatewayIamBindingArgs.builder()
            .project(apiGw.project())
            .region(apiGw.region())
            .gateway(apiGw.gatewayId())
            .role("roles/apigateway.viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:apigateway:GatewayIamBinding
    properties:
      project: ${apiGw.project}
      region: ${apiGw.region}
      gateway: ${apiGw.gatewayId}
      role: roles/apigateway.viewer
      members:
        - user:jane@example.com

The members property lists all identities that should have this role. GatewayIamBinding is authoritative for the specified role: it replaces any existing members for that role while preserving other roles. You can combine GatewayIamBinding with GatewayIamMember as long as they don’t grant the same role.

Replace the entire IAM policy

Some deployments need complete control over all roles and members on a gateway.

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

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/apigateway.viewer",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.apigateway.GatewayIamPolicy("policy", {
    project: apiGw.project,
    region: apiGw.region,
    gateway: apiGw.gatewayId,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/apigateway.viewer",
    "members": ["user:jane@example.com"],
}])
policy = gcp.apigateway.GatewayIamPolicy("policy",
    project=api_gw["project"],
    region=api_gw["region"],
    gateway=api_gw["gatewayId"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/apigateway"
	"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/apigateway.viewer",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = apigateway.NewGatewayIamPolicy(ctx, "policy", &apigateway.GatewayIamPolicyArgs{
			Project:    pulumi.Any(apiGw.Project),
			Region:     pulumi.Any(apiGw.Region),
			Gateway:    pulumi.Any(apiGw.GatewayId),
			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/apigateway.viewer",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.ApiGateway.GatewayIamPolicy("policy", new()
    {
        Project = apiGw.Project,
        Region = apiGw.Region,
        Gateway = apiGw.GatewayId,
        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.apigateway.GatewayIamPolicy;
import com.pulumi.gcp.apigateway.GatewayIamPolicyArgs;
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/apigateway.viewer")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new GatewayIamPolicy("policy", GatewayIamPolicyArgs.builder()
            .project(apiGw.project())
            .region(apiGw.region())
            .gateway(apiGw.gatewayId())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:apigateway:GatewayIamPolicy
    properties:
      project: ${apiGw.project}
      region: ${apiGw.region}
      gateway: ${apiGw.gatewayId}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/apigateway.viewer
            members:
              - user:jane@example.com

The policyData property comes from getIAMPolicy, which defines all roles and their members in a single policy document. GatewayIamPolicy is fully authoritative: it replaces the entire IAM policy, removing any permissions not explicitly defined. This resource cannot be used with GatewayIamBinding or GatewayIamMember, as they would conflict over policy ownership.

Beyond these examples

These snippets focus on specific IAM management approaches: single-member grants, role-level member lists, and complete policy replacement. They’re intentionally minimal rather than full access control systems.

The examples reference pre-existing infrastructure such as API Gateway gateways (by gatewayId) and GCP project/region configuration. They focus on granting permissions rather than provisioning the underlying gateway resources.

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

  • Conditional IAM bindings (condition property)
  • Custom role definitions
  • Federated identity configuration
  • Cross-project or organization-level policies

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 GatewayIamMember resource reference for all available configuration options.

Let's manage GCP API Gateway IAM Access

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 GatewayIamPolicy, GatewayIamBinding, and GatewayIamMember?
GatewayIamPolicy is authoritative and replaces the entire IAM policy. GatewayIamBinding is authoritative for a specific role, preserving other roles. GatewayIamMember is non-authoritative, adding a single member to a role while preserving other members.
Can I use GatewayIamPolicy with GatewayIamBinding or GatewayIamMember?
No, GatewayIamPolicy cannot be used with GatewayIamBinding or GatewayIamMember because they will conflict over the policy configuration.
Can I use GatewayIamBinding and GatewayIamMember together?
Yes, but only if they don’t grant privileges to the same role. Using both for the same role causes conflicts.
Which IAM resource should I use for my use case?
Use GatewayIamPolicy to manage the complete policy authoritatively. Use GatewayIamBinding to manage all members for a specific role. Use GatewayIamMember to add individual members without affecting existing ones.
IAM Configuration & Identity Formats
What identity formats can I use in the member property?
You can use 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 grant access to a service account?
Set member to serviceAccount:{emailid}, for example serviceAccount:my-app@appspot.gserviceaccount.com.
How do I grant access to everyone with a Google account?
Use allAuthenticatedUsers as the member value to grant access to anyone authenticated with a Google account or service account.
Custom Roles & Immutability
What format do custom roles need to follow?
Custom roles must use the format [projects|organizations]/{parent-name}/roles/{role-name}, for example projects/my-project/roles/my-custom-role.
Can I change the role or member after creating the resource?
No, all properties (gateway, member, project, region, role) are immutable and cannot be changed after creation.

Using a different cloud?

Explore security guides for other cloud providers: