The destination bucket does not need to belong to the same project as the
service agent. The steps are the same regardless of which project the bucket is
in.
User permissions
In order to grant the required permissions to the service agent, you must have
the relevant permissions on the destination bucket:
storage.buckets.getIamPolicy
storage.buckets.setIamPolicy
The Storage Legacy Bucket Owner role (roles/storage.legacyBucketOwner) or
the Storage Admin role (roles/storage.admin) provide the required
permissions.
Auto-granting permissions in the Google Cloud console
If you're using the Google Cloud console to create your transfer and have
the permissions listed in User permissions,
the service agent will automatically be granted the required permissions on
your destination bucket.
The service agent must have the following permissions for the destination
bucket:
Permission
Description
storage.buckets.get
Allows the service account to get the location of the bucket.
storage.objects.get
Allows the service account to view objects and their metadata,
excluding ACLs. Required if your transfer is configured to
[overwrite objects](/storage-transfer/docs/reference/rest/v1/TransferOptions#OverwriteWhen)
in the sink when different, or never. Not required if your transfer
setting is to overwrite always.
storage.objects.create
Allows the service account to add objects to the bucket.
storage.objects.delete
Allows the service account to delete objects in the bucket.
Required if you set overwriteObjectsAlreadyExistingInSink
or deleteObjectsUniqueInSink to true.
Note that if the destination bucket has
object versioning
enabled, neither overwriteObjectsAlreadyExistingInSink
nor deleteObjectsUniqueInSink permanently delete any
objects. Instead, relevant live object versions become noncurrent.
storage.objects.list
Allows the service account to list objects in the bucket. Required if
you set overwriteObjectsAlreadyExistingInSink to
false or deleteObjectsUniqueInSink to
true.
The following predefined role grants the required permissions:
In addition, for transfers configured to
overwrite objects
in the sink when different, or never, assign the following
predefined role to the service agent:
An interactive panel opens, titled Try this method.
In the panel, under Request parameters, enter your
project ID. The project you specify here must be the project that
you're using to manage Storage Transfer Service, which might be different from the
destination bucket's project.
Click Execute.
Your service agent's email is returned as the value of accountEmail. Copy
this value.
The service agent's email uses the format
project-PROJECT_NUMBER@storage-transfer-service.iam.gserviceaccount.com.
Add the service agent to a bucket-level policy
Console
In the Google Cloud console, go to the Cloud Storage Buckets page.
namespacegcs=::google::cloud::storage;using::google::cloud::StatusOr;[](gcs::Clientclient,std::stringconst&bucket_name,std::stringconst&role,std::stringconst&member){autopolicy=client.GetNativeBucketIamPolicy(bucket_name,gcs::RequestedPolicyVersion(3));if(!policy)throwstd::move(policy).status();policy->set_version(3);for(auto&binding:policy->bindings()){if(binding.role()!=role||binding.has_condition()){continue;}auto&members=binding.members();if(std::find(members.begin(),members.end(),member)==members.end()){members.emplace_back(member);}}autoupdated=client.SetNativeBucketIamPolicy(bucket_name,*policy);if(!updated)throwstd::move(updated).status();std::cout << "Updated IAM policy bucket " << bucket_name << ". The new policy is " << *updated << "\n";}
usingGoogle.Apis.Storage.v1.Data;usingGoogle.Cloud.Storage.V1;usingSystem;usingSystem.Collections.Generic;publicclassAddBucketIamMemberSample{publicPolicyAddBucketIamMember(stringbucketName="your-unique-bucket-name",stringrole="roles/storage.objectViewer",stringmember="serviceAccount:dev@iam.gserviceaccount.com"){varstorage=StorageClient.Create();varpolicy=storage.GetBucketIamPolicy(bucketName,newGetBucketIamPolicyOptions{RequestedPolicyVersion=3});// Set the policy schema version. For more information, please refer to https://cloud.google.com/iam/docs/policies#versions.policy.Version=3;Policy.BindingsDatabindingToAdd=newPolicy.BindingsData{Role=role,Members=newList<string>{member}};policy.Bindings.Add(bindingToAdd);varbucketIamPolicy=storage.SetBucketIamPolicy(bucketName,policy);Console.WriteLine($"Added {member} with role {role} "+$"to {bucketName}");returnbucketIamPolicy;}}
import("context""fmt""io""time""cloud.google.com/go/iam""cloud.google.com/go/storage")// addBucketIAMMember adds the bucket IAM member to permission role.funcaddBucketIAMMember(wio.Writer,bucketNamestring)error{// bucketName := "bucket-name"ctx:=context.Background()client,err:=storage.NewClient(ctx)iferr!=nil{returnfmt.Errorf("storage.NewClient: %w",err)}deferclient.Close()ctx,cancel:=context.WithTimeout(ctx,time.Second*10)defercancel()bucket:=client.Bucket(bucketName)policy,err:=bucket.IAM().Policy(ctx)iferr!=nil{returnfmt.Errorf("Bucket(%q).IAM().Policy: %w",bucketName,err)}// Other valid prefixes are "serviceAccount:", "user:"// See the documentation for more values.// https://cloud.google.com/storage/docs/access-control/iamidentity:="group:cloud-logs@google.com"varroleiam.RoleName="roles/storage.objectViewer"policy.Add(identity,role)iferr:=bucket.IAM().SetPolicy(ctx,policy);err!=nil{returnfmt.Errorf("Bucket(%q).IAM().SetPolicy: %w",bucketName,err)}// NOTE: It may be necessary to retry this operation if IAM policies are// being modified concurrently. SetPolicy will return an error if the policy// was modified since it was retrieved.fmt.Fprintf(w,"Added %v with role %v to %v\n",identity,role,bucketName)returnnil}
importcom.google.cloud.Binding;importcom.google.cloud.Policy;importcom.google.cloud.storage.Storage;importcom.google.cloud.storage.StorageOptions;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.List;publicclassAddBucketIamMember{/** Example of adding a member to the Bucket-level IAM */publicstaticvoidaddBucketIamMember(StringprojectId,StringbucketName){// The ID of your GCP project// String projectId = "your-project-id";// The ID of your GCS bucket// String bucketName = "your-unique-bucket-name";// For more information please read:// https://cloud.google.com/storage/docs/access-control/iamStoragestorage=StorageOptions.newBuilder().setProjectId(projectId).build().getService();PolicyoriginalPolicy=storage.getIamPolicy(bucketName,Storage.BucketSourceOption.requestedPolicyVersion(3));Stringrole="roles/storage.objectViewer";Stringmember="group:example@google.com";// getBindingsList() returns an ImmutableList and copying over to an ArrayList so it's mutable.List<Binding>bindings=newArrayList(originalPolicy.getBindingsList());// Create a new binding using role and memberBinding.BuildernewMemberBindingBuilder=Binding.newBuilder();newMemberBindingBuilder.setRole(role).setMembers(Arrays.asList(member));bindings.add(newMemberBindingBuilder.build());// Update policy to add memberPolicy.BuilderupdatedPolicyBuilder=originalPolicy.toBuilder();updatedPolicyBuilder.setBindings(bindings).setVersion(3);PolicyupdatedPolicy=storage.setIamPolicy(bucketName,updatedPolicyBuilder.build());System.out.printf("Added %s with role %s to %s\n",member,role,bucketName);}}
/** * TODO(developer): Uncomment the following lines before running the sample. */// The ID of your GCS bucket// const bucketName = 'your-unique-bucket-name';// The role to grant// const roleName = 'roles/storage.objectViewer';// The members to grant the new role to// const members = [// 'user:jdoe@example.com',// 'group:admins@example.com',// ];// Imports the Google Cloud client libraryconst{Storage}=require('@google-cloud/storage');// Creates a clientconststorage=newStorage();asyncfunctionaddBucketIamMember(){// Get a reference to a Google Cloud Storage bucketconstbucket=storage.bucket(bucketName);// For more information please read:// https://cloud.google.com/storage/docs/access-control/iamconst[policy]=awaitbucket.iam.getPolicy({requestedPolicyVersion:3});// Adds the new roles to the bucket's IAM policypolicy.bindings.push({role:roleName,members:members,});// Updates the bucket's IAM policyawaitbucket.iam.setPolicy(policy);console.log(`Added the following member(s) with role ${roleName} to ${bucketName}:`);members.forEach(member=>{console.log(` ${member}`);});}addBucketIamMember().catch(console.error);
use Google\Cloud\Storage\StorageClient;/** * Adds a new member / role IAM pair to a given Cloud Storage bucket. * * @param string $bucketName The name of your Cloud Storage bucket. * (e.g. 'my-bucket') * @param string $role The role to which the given member should be added. * (e.g. 'roles/storage.objectViewer') * @param string[] $members The member(s) to be added to the role. * (e.g. ['group:example@google.com']) */function add_bucket_iam_member(string $bucketName, string $role, array $members): void{ $storage = new StorageClient(); $bucket = $storage->bucket($bucketName); $policy = $bucket->iam()->policy(['requestedPolicyVersion' => 3]); $policy['version'] = 3; $policy['bindings'][] = [ 'role' => $role, 'members' => $members ]; $bucket->iam()->setPolicy($policy); printf('Added the following member(s) to role %s for bucket %s' . PHP_EOL, $role, $bucketName); foreach ($members as $member) { printf(' %s' . PHP_EOL, $member); }}
fromgoogle.cloudimportstoragedefadd_bucket_iam_member(bucket_name,role,member):"""Add a new member to an IAM Policy"""# bucket_name = "your-bucket-name"# role = "IAM role, e.g., roles/storage.objectViewer"# member = "IAM identity, e.g., user: name@example.com"storage_client=storage.Client()bucket=storage_client.bucket(bucket_name)policy=bucket.get_iam_policy(requested_policy_version=3)policy.bindings.append({"role":role,"members":{member}})bucket.set_iam_policy(policy)print(f"Added {member} with role {role} to {bucket_name}.")
defadd_bucket_iam_memberbucket_name:# The ID of your GCS bucket# bucket_name = "your-unique-bucket-name"require"google/cloud/storage"storage=Google::Cloud::Storage.newbucket=storage.bucketbucket_namerole="roles/storage.objectViewer"member="group:example@google.com"bucket.policyrequested_policy_version:3do|policy|policy.bindings.insertrole:role,members:[member]endputs"Added #{member} with role #{role} to #{bucket_name}"end
Rust
usegoogle_cloud_iam_v1::model::Binding;usegoogle_cloud_storage::client::StorageControl;pubasyncfnsample(client:&StorageControl,bucket_id:&str,role:&str,member:&str,)->anyhow::Result<()>{letmutpolicy=client.get_iam_policy().set_resource(format!("projects/_/buckets/{bucket_id}")).send().await?;policy.bindings.push(Binding::new().set_role(role).set_members([member]));letupdated_policy=client.set_iam_policy().set_resource(format!("projects/_/buckets/{bucket_id}")).set_policy(policy).send().await?;println!("Successfully added binding for {member} to bucket {bucket_id} policy: {updated_policy:?}");Ok(())}
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2026-06-09 UTC."],[],[]]