Manage GCP Access Context Manager IAM Policies

The gcp:accesscontextmanager/accessPolicyIamMember:AccessPolicyIamMember resource, part of the Pulumi GCP provider, grants IAM permissions on Access Context Manager access policies, controlling who can manage VPC Service Controls perimeters and access levels. This guide focuses on three capabilities: non-authoritative member grants, authoritative role bindings, and full policy replacement.

The three IAM resources (AccessPolicyIamMember, AccessPolicyIamBinding, AccessPolicyIamPolicy) reference an existing access policy by name and differ in how they handle conflicts with existing IAM bindings. The examples are intentionally small. Choose the resource that matches your conflict-handling needs: non-authoritative for adding members, role-authoritative for managing a complete role, or policy-authoritative for replacing all permissions.

Grant a role to a single member non-authoritatively

When you need to add one person or service account without affecting other existing permissions, the non-authoritative approach preserves all other role assignments.

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

const member = new gcp.accesscontextmanager.AccessPolicyIamMember("member", {
    name: access_policy.name,
    role: "roles/accesscontextmanager.policyAdmin",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.accesscontextmanager.AccessPolicyIamMember("member",
    name=access_policy["name"],
    role="roles/accesscontextmanager.policyAdmin",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := accesscontextmanager.NewAccessPolicyIamMember(ctx, "member", &accesscontextmanager.AccessPolicyIamMemberArgs{
			Name:   pulumi.Any(access_policy.Name),
			Role:   pulumi.String("roles/accesscontextmanager.policyAdmin"),
			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.AccessContextManager.AccessPolicyIamMember("member", new()
    {
        Name = access_policy.Name,
        Role = "roles/accesscontextmanager.policyAdmin",
        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.accesscontextmanager.AccessPolicyIamMember;
import com.pulumi.gcp.accesscontextmanager.AccessPolicyIamMemberArgs;
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 AccessPolicyIamMember("member", AccessPolicyIamMemberArgs.builder()
            .name(access_policy.name())
            .role("roles/accesscontextmanager.policyAdmin")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:accesscontextmanager:AccessPolicyIamMember
    properties:
      name: ${["access-policy"].name}
      role: roles/accesscontextmanager.policyAdmin
      member: user:jane@example.com

The AccessPolicyIamMember resource adds a single member to a role without removing other members who already have that role. The member property accepts various identity formats: user emails, service accounts, groups, domains, or federated identities. This resource is safe to use alongside other IAM resources as long as they don’t grant the same member the same role.

Grant a role to multiple members authoritatively

Teams managing access policies often need to define the complete list of members for a specific role, replacing any previous assignments for that role while preserving other roles.

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

const binding = new gcp.accesscontextmanager.AccessPolicyIamBinding("binding", {
    name: access_policy.name,
    role: "roles/accesscontextmanager.policyAdmin",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.accesscontextmanager.AccessPolicyIamBinding("binding",
    name=access_policy["name"],
    role="roles/accesscontextmanager.policyAdmin",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := accesscontextmanager.NewAccessPolicyIamBinding(ctx, "binding", &accesscontextmanager.AccessPolicyIamBindingArgs{
			Name: pulumi.Any(access_policy.Name),
			Role: pulumi.String("roles/accesscontextmanager.policyAdmin"),
			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.AccessContextManager.AccessPolicyIamBinding("binding", new()
    {
        Name = access_policy.Name,
        Role = "roles/accesscontextmanager.policyAdmin",
        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.accesscontextmanager.AccessPolicyIamBinding;
import com.pulumi.gcp.accesscontextmanager.AccessPolicyIamBindingArgs;
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 AccessPolicyIamBinding("binding", AccessPolicyIamBindingArgs.builder()
            .name(access_policy.name())
            .role("roles/accesscontextmanager.policyAdmin")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:accesscontextmanager:AccessPolicyIamBinding
    properties:
      name: ${["access-policy"].name}
      role: roles/accesscontextmanager.policyAdmin
      members:
        - user:jane@example.com

The AccessPolicyIamBinding resource sets the authoritative member list for a single role. When you apply this configuration, any members previously granted this role but not listed in members will lose access. Other roles on the access policy remain unchanged. You can combine multiple AccessPolicyIamBinding resources as long as each manages a different role.

Replace the entire IAM policy authoritatively

When you need complete control over all IAM bindings for an access policy, the policy resource replaces the entire IAM configuration in one operation.

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

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/accesscontextmanager.policyAdmin",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.accesscontextmanager.AccessPolicyIamPolicy("policy", {
    name: access_policy.name,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/accesscontextmanager.policyAdmin",
    "members": ["user:jane@example.com"],
}])
policy = gcp.accesscontextmanager.AccessPolicyIamPolicy("policy",
    name=access_policy["name"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/accesscontextmanager"
	"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/accesscontextmanager.policyAdmin",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = accesscontextmanager.NewAccessPolicyIamPolicy(ctx, "policy", &accesscontextmanager.AccessPolicyIamPolicyArgs{
			Name:       pulumi.Any(access_policy.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/accesscontextmanager.policyAdmin",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.AccessContextManager.AccessPolicyIamPolicy("policy", new()
    {
        Name = access_policy.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.accesscontextmanager.AccessPolicyIamPolicy;
import com.pulumi.gcp.accesscontextmanager.AccessPolicyIamPolicyArgs;
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/accesscontextmanager.policyAdmin")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new AccessPolicyIamPolicy("policy", AccessPolicyIamPolicyArgs.builder()
            .name(access_policy.name())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:accesscontextmanager:AccessPolicyIamPolicy
    properties:
      name: ${["access-policy"].name}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/accesscontextmanager.policyAdmin
            members:
              - user:jane@example.com

The AccessPolicyIamPolicy resource uses the getIAMPolicy data source to construct a complete policy document, then replaces all IAM bindings on the access policy. The bindings array defines every role and member combination. This is the most authoritative approach: it removes any role assignments not explicitly listed. You cannot use AccessPolicyIamPolicy alongside AccessPolicyIamBinding or AccessPolicyIamMember, as they will conflict over the policy state.

Beyond these examples

These snippets focus on specific IAM management features: non-authoritative member grants, authoritative role bindings, and full policy replacement. They’re intentionally minimal rather than complete access control configurations.

The examples reference pre-existing infrastructure such as an Access Context Manager access policy (referenced by name). They focus on configuring IAM permissions rather than creating the underlying access policy.

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

  • Conditional IAM bindings (condition property)
  • Custom role definitions
  • Federated identity principals
  • Service account impersonation

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

Let's manage GCP Access Context Manager 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 for managing Access Policy permissions?
Choose based on your needs: AccessPolicyIamPolicy for full policy control (replaces entire policy), AccessPolicyIamBinding to manage all members for a specific role (preserves other roles), or AccessPolicyIamMember to add individual members without affecting others (non-authoritative).
Can I use multiple IAM resource types together?
AccessPolicyIamPolicy cannot be used with AccessPolicyIamBinding or AccessPolicyIamMember, as they will conflict. However, AccessPolicyIamBinding and AccessPolicyIamMember can be used together only if they manage different roles.
IAM 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/....
What format do custom roles require?
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 member, role, or name after creation?
No, all three properties (member, role, and name) are immutable and cannot be changed after the resource is created.
Import & Migration
How do I import an IAM member with a custom role?
Use the full custom role name in the import command: pulumi import gcp:accesscontextmanager/accessPolicyIamMember:AccessPolicyIamMember editor "accessPolicies/{{access_policy}} projects/my-project/roles/my-custom-role user:jane@example.com".
What's the import syntax for AccessPolicyIamMember?
Use space-delimited identifiers: pulumi import gcp:accesscontextmanager/accessPolicyIamMember:AccessPolicyIamMember editor "accessPolicies/{{access_policy}} roles/accesscontextmanager.policyAdmin user:jane@example.com".

Using a different cloud?

Explore security guides for other cloud providers: