Manage GCP Artifact Registry Repository IAM Access

The gcp:artifactregistry/repositoryIamMember:RepositoryIamMember resource, part of the Pulumi GCP provider, grants IAM permissions on Artifact Registry repositories by adding individual members to roles. This guide focuses on three approaches: single-member grants with RepositoryIamMember, multi-member role bindings with RepositoryIamBinding, and full policy replacement with RepositoryIamPolicy.

These three resources reference existing Artifact Registry repositories and have strict compatibility rules. RepositoryIamPolicy is authoritative and replaces the entire policy, so it cannot be used alongside Binding or Member resources. RepositoryIamBinding and RepositoryIamMember can coexist only if they target different roles. The examples are intentionally small. Choose the resource that matches your IAM management approach.

Grant a single user read access to a repository

When you need to add one developer or service account to a repository without affecting other permissions, use RepositoryIamMember.

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

const member = new gcp.artifactregistry.RepositoryIamMember("member", {
    project: my_repo.project,
    location: my_repo.location,
    repository: my_repo.name,
    role: "roles/artifactregistry.reader",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.artifactregistry.RepositoryIamMember("member",
    project=my_repo["project"],
    location=my_repo["location"],
    repository=my_repo["name"],
    role="roles/artifactregistry.reader",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := artifactregistry.NewRepositoryIamMember(ctx, "member", &artifactregistry.RepositoryIamMemberArgs{
			Project:    pulumi.Any(my_repo.Project),
			Location:   pulumi.Any(my_repo.Location),
			Repository: pulumi.Any(my_repo.Name),
			Role:       pulumi.String("roles/artifactregistry.reader"),
			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.ArtifactRegistry.RepositoryIamMember("member", new()
    {
        Project = my_repo.Project,
        Location = my_repo.Location,
        Repository = my_repo.Name,
        Role = "roles/artifactregistry.reader",
        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.artifactregistry.RepositoryIamMember;
import com.pulumi.gcp.artifactregistry.RepositoryIamMemberArgs;
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 RepositoryIamMember("member", RepositoryIamMemberArgs.builder()
            .project(my_repo.project())
            .location(my_repo.location())
            .repository(my_repo.name())
            .role("roles/artifactregistry.reader")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:artifactregistry:RepositoryIamMember
    properties:
      project: ${["my-repo"].project}
      location: ${["my-repo"].location}
      repository: ${["my-repo"].name}
      role: roles/artifactregistry.reader
      member: user:jane@example.com

The member property specifies the identity to grant access, using formats like “user:jane@example.com” or “serviceAccount:app@project.iam.gserviceaccount.com”. The role property sets the permission level; here, “roles/artifactregistry.reader” allows pulling images. This resource is non-authoritative: it adds the member without removing other members from the same role.

Grant a role to multiple members at once

When several users or service accounts need identical access, RepositoryIamBinding assigns them together.

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

const binding = new gcp.artifactregistry.RepositoryIamBinding("binding", {
    project: my_repo.project,
    location: my_repo.location,
    repository: my_repo.name,
    role: "roles/artifactregistry.reader",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.artifactregistry.RepositoryIamBinding("binding",
    project=my_repo["project"],
    location=my_repo["location"],
    repository=my_repo["name"],
    role="roles/artifactregistry.reader",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := artifactregistry.NewRepositoryIamBinding(ctx, "binding", &artifactregistry.RepositoryIamBindingArgs{
			Project:    pulumi.Any(my_repo.Project),
			Location:   pulumi.Any(my_repo.Location),
			Repository: pulumi.Any(my_repo.Name),
			Role:       pulumi.String("roles/artifactregistry.reader"),
			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.ArtifactRegistry.RepositoryIamBinding("binding", new()
    {
        Project = my_repo.Project,
        Location = my_repo.Location,
        Repository = my_repo.Name,
        Role = "roles/artifactregistry.reader",
        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.artifactregistry.RepositoryIamBinding;
import com.pulumi.gcp.artifactregistry.RepositoryIamBindingArgs;
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 RepositoryIamBinding("binding", RepositoryIamBindingArgs.builder()
            .project(my_repo.project())
            .location(my_repo.location())
            .repository(my_repo.name())
            .role("roles/artifactregistry.reader")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:artifactregistry:RepositoryIamBinding
    properties:
      project: ${["my-repo"].project}
      location: ${["my-repo"].location}
      repository: ${["my-repo"].name}
      role: roles/artifactregistry.reader
      members:
        - user:jane@example.com

The members property takes a list of identities to bind to the role. RepositoryIamBinding is authoritative for the specified role: it sets the complete member list for that role, removing any members not in the list. Other roles in the repository’s IAM policy remain unchanged.

Replace the entire IAM policy with a new definition

Organizations managing IAM centrally sometimes need to set the complete policy for a repository.

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

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/artifactregistry.reader",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.artifactregistry.RepositoryIamPolicy("policy", {
    project: my_repo.project,
    location: my_repo.location,
    repository: my_repo.name,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/artifactregistry.reader",
    "members": ["user:jane@example.com"],
}])
policy = gcp.artifactregistry.RepositoryIamPolicy("policy",
    project=my_repo["project"],
    location=my_repo["location"],
    repository=my_repo["name"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/artifactregistry"
	"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/artifactregistry.reader",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = artifactregistry.NewRepositoryIamPolicy(ctx, "policy", &artifactregistry.RepositoryIamPolicyArgs{
			Project:    pulumi.Any(my_repo.Project),
			Location:   pulumi.Any(my_repo.Location),
			Repository: pulumi.Any(my_repo.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/artifactregistry.reader",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.ArtifactRegistry.RepositoryIamPolicy("policy", new()
    {
        Project = my_repo.Project,
        Location = my_repo.Location,
        Repository = my_repo.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.artifactregistry.RepositoryIamPolicy;
import com.pulumi.gcp.artifactregistry.RepositoryIamPolicyArgs;
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/artifactregistry.reader")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new RepositoryIamPolicy("policy", RepositoryIamPolicyArgs.builder()
            .project(my_repo.project())
            .location(my_repo.location())
            .repository(my_repo.name())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:artifactregistry:RepositoryIamPolicy
    properties:
      project: ${["my-repo"].project}
      location: ${["my-repo"].location}
      repository: ${["my-repo"].name}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/artifactregistry.reader
            members:
              - user:jane@example.com

The policyData property accepts a full IAM policy document, typically constructed with the getIAMPolicy data source. RepositoryIamPolicy is fully authoritative: it replaces the entire IAM policy for the repository, removing any bindings not included in policyData. This resource cannot be used alongside RepositoryIamBinding or RepositoryIamMember.

Beyond these examples

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

The examples reference pre-existing infrastructure such as Artifact Registry repositories. They focus on granting permissions rather than provisioning repositories or defining custom roles.

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

  • Conditional IAM bindings (condition property)
  • Custom role definitions
  • Federated identity principals
  • Cross-project or cross-organization access

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

Let's manage GCP Artifact Registry Repository 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
Which IAM resources can I use together?
RepositoryIamPolicy cannot be used with RepositoryIamBinding or RepositoryIamMember because they’ll conflict over the policy. RepositoryIamBinding and RepositoryIamMember can be used together only if they grant different roles.
What's the difference between RepositoryIamPolicy, RepositoryIamBinding, and RepositoryIamMember?
RepositoryIamPolicy is authoritative and replaces the entire IAM policy. RepositoryIamBinding is authoritative for a specific role but preserves other roles. RepositoryIamMember is non-authoritative and preserves other members for the same role.
When should I use RepositoryIamMember vs RepositoryIamBinding?
Use RepositoryIamMember to add individual members to a role without affecting other members. Use RepositoryIamBinding when you want to manage the complete list of members for a specific role.
IAM Configuration
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.
What member identity formats are supported?
Supported formats include allUsers, allAuthenticatedUsers, user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, projectOwner:projectid, projectEditor:projectid, projectViewer:projectid, and federated identities like principal://iam.googleapis.com/....
What are the valid multi-region location values?
Multi-region locations are asia, europe, and us. You can also use specific regional locations or omit the location to use the value from the provider configuration.
Resource Management
Can I modify IAM properties after creation?
No, all properties (location, member, project, repository, role, condition) are immutable and require resource replacement if changed.
How do I import an existing IAM member?
Use space-delimited identifiers with the resource path, role, and member identity: pulumi import gcp:artifactregistry/repositoryIamMember:RepositoryIamMember editor "projects/{{project}}/locations/{{location}}/repositories/{{repository}} roles/artifactregistry.reader user:jane@example.com"

Using a different cloud?

Explore security guides for other cloud providers: