Migrating projects

This guide explains how to move a project between organizations or places within a resource hierarchy.

The project resource is the base-level organizing entity in a Google Cloud organization. Projects are created under organizations, and can be placed under folders or the organization resource itself, forming the resource hierarchy. You may need to migrate projects between organizations due to acquisitions, regulatory requirements, and separation between business units, among other things.

You can use the Resource Manager API to move projects across organizations or to another place in the resource hierarchy of its current organization. The Resource Manager API also lets you roll back the migration, moving the project back to its original place in the resource hierarchy.

Create a migration plan

The most important thing to consider during a project move is how the migration will impact the services running inside the project. The Resource Manager API treats the project resource and all services running underneath it as a single unit, meaning that no configuration changes will be applied inside the project.

While migration will not make direct configuration changes to the project, the change in the resource hierarchy is likely to have an impact on the function of the project and its running services. Inherited policies, such as Identity and Access Management or organization policies, will not move with the project during migration, only policies and service accounts that are attached directly to the resource. This may cause unintended behavior after the migration is complete.

Before moving your project, you should consider creating a migration plan to determine the readiness of both your organization and the projects you want to move. In this migration plan, take inventory of each of the services that your project is running, and any other services that may be impacted by the move, or by the resource hierarchy in the destination for your project.

Inventory overview

Use Cloud Asset Inventory to create an overview of resources in use, including Identity and Access Management policies. You can use this overview to help outline your migration plan.

You can also use Cloud Asset Inventory to transfer this data into BigQuery. This will allow you to query the data using SQL, which is easier to read compared to interpreting JSON-formatted data. For information about exporting this data, see Exporting to BigQuery.

Policy verification

When you migrate your project, it will no longer inherit the policies from its current place in the resource hierarchy, and will be subject to the effective policy evaluation at its destination. We recommend making sure that the effective policies at the project's destination match as much as possible the policies that the project had in its source location.

Any policy that is applied directly to the project will still be attached after the migration is complete. Applying policies directly to the project is a good way to verify that the correct policies are applied from the moment the move is complete.

Identity and Access Management policies and organization policies are inherited through the resource hierarchy, and can block a service from functioning if not set properly. Determine the effective policy at the project's destination in your resource hierarchy to ensure the policy aligns with your governance objectives.

Manage encrypted keys

You should verify if your project has a customer-managed encrypted key or other Cloud Key Management Service enabled on it. Cryptographic keys are owned by the project, and a user with owner access to that project will therefore be able to manage and perform cryptographic operations on keys in Cloud KMS in that project.

For more information, see Separation of duties.

Preview features

You can enable preview features on organizations, folders, or projects. If you have enabled an alpha or beta feature on the project to be moved, this feature should continue to function after the migration. If the preview feature is private and not allowlisted for the destination organization, you will not be able to make any configuration changes after the move is complete.

Rollback plan

If you discover that something is not working on any of the projects you have migrated, you can move them back to their original location. In order to do that, you need to have the necessary IAM permissions and set the required organization policies so that you can run the project migration in reverse.

For a list of permissions required, see Assign permissions. For the organization policies you need to configure to allow a project migration, see Configure organization policies.

Dedicated import and export folders

Policy inheritance can cause unintended effects when you are migrating a project, both in the source and destination organizations. You can mitigate this risk by creating specific folders to hold only projects for export and import, and ensuring that the same policies are inherited by the folders in both organizations. You can also set permissions on these folders that will be inherited to the projects moved within them, helping to accelerate the project migration process.

When planning a migration, consider setting up a dedicated source folder first. To do this, create a folder for each organization to which you plan to export projects. Then, set an organization policy on these folders, each with the constraints/resourcemanager.allowedExportDestinations constraint set to the single organization to which you want to export projects.

For example, you could set up Export to Marketing Org and Export to Sales Org folders, each with appropriate organization policy constraints set.

Similarly, set up dedicated import folders in the destination organization, one for each organization from which you want to import projects. To do this, create a folder for each organization from which you plan to import projects. Then, set an organization policy on these folders, each with the constraints/resourcemanager.allowedImportSources constraint set to the single organization from which you want to import projects.

For example, you could set up Import from Marketing Org and Import from App Development Org folders, each with appropriate organization policy constraints set.

On each of the import and export folders, assign the person who will be moving the projects the roles/resourcemanager.projectMover role. This role will be inherited by any projects that are contained within these folders, giving the user the ability to perform the move operations on any project that is moved into those folders.

After you have completed your project migration, you should remove these dedicated folders.

For information about setting organization policies, see Configure organization policies.

Assign permissions

You need the following permissions to move a project between organizations.

To gain these permissions, ask your administrator to grant the suggested role at the appropriate level of the resource hierarchy.

Project move permissions

On the project resource that you want to move and its parent resource, you need the Project Mover role (roles/resourcemanager.projectMover), or another role that includes the following permissions for the v1 Resource Manager API:

  • Permission required for the resource you're moving:

    • resourcemanager.projects.update
  • Permission required for the parent resource:

    • resourcemanager.projects.move

On the destination resource, the permission you need depends on the resource to which you are moving the project.

  • If the destination resource is a folder, you need the Project Mover role (roles/resourcemanager.projectMover), or another role that includes the resourcemanager.projects.move permission.

  • If the destination resource is an organization, you need the Project Creator role (roles/resourcemanager.projectCreator), or another role that includes the resourcemanager.projects.create permissions.

Organization policy permissions

On the source and destination organizations, you must have the roles/orgpolicy.policyAdmin role, which grants permission to create and manage organization policies.

Configure organization policies

To move a project resource to a new organization, you must first apply an organization policy that will define the organizations to which the project can be moved. You must also set an organization policy in the destination that defines the organizations from which projects can be imported.

On the parent resource to the project you want to move, set an organization policy that includes the constraints/resourcemanager.allowedExportDestinations constraint. This will define the target destination as a valid location to which you can migrate the project.

On the destination resource, set an organization policy that includes the constraints/resourcemanager.allowedImportSources constraint. This will define the source as a valid location from which you can migrate your project.

For example, say you had a project my-test-project that existed under an organization with the ID 12345678901, and you wanted to move it to a new organization for your secondary business unit, with the ID 45678901234.

You would set an organization policy on organizations/12345678901with the constraints/resourcemanager.allowedExportDestinations constraint enforced and under:organizations/45678901234 set as an allowed_value.

Then, set an organization policy on organizations/45678901234 with the constraints/resourcemanager.allowedImportSources constraint enforced and under:organizations/12345678901 set as an allowed_value.

Once these organization policies are enforced, you will be able to move my-test-project from organizations/12345678901 to organizations/45678901234, assuming you have the permissions noted in Assign permissions.

Change the billing account for a project

Cloud Billing accounts can be used across organizations. Moving a project from one organization to another won't impact billing, and charges will continue against the old billing account. However, organization moves often also include a requirement to move to a new billing account.

To change the billing account for an existing project, you must have the roles/owner role on the project, and the roles/billing.admin role on the destination billing account. To change the billing account:

  1. Go to the Billing page in the Cloud Console.
    Go to the Billing page
  2. Click the name of the billing account you want to change.
  3. Under Projects linked to this billing account, find the name of the Project to move and then click the menu button to the right.
  4. Click Change billing, and then select the new billing account.
  5. Click Set account.

Charges already incurred that have not yet been reported in the transaction history will be billed to the former billing account. This can include charges from up to two days prior to when the project was moved.

Move a billing account between organizations

A billing account can be moved from one organization to another, although this isn't often a necessary step. Most existing organizations will already have a billing account that should be used instead. If you need to migrate an existing billing account:

  1. Get the roles/billing.admin role on the source and destination organizations.
  2. Go to the Billing page in the Cloud Console.
    Go to the Billing page
  3. Click on the name of the billing account you want to move.
  4. At the top of the Account Management page, click Change organization.
  5. Select the destination organization, and then click Ok.

The billing account is now associated with the specified organization.

Perform the migration

If you have the appropriate IAM permissions and the required organization policies are enforced, you can use the Resource Manager API to move a project resource.

gcloud

To migrate a project under an organization, run the following command:

gcloud beta projects move PROJECT_ID \
    --organization ORGANIZATION_ID

You can also specify a folder as the target resource, with the following command:

gcloud beta projects move PROJECT_ID \
    --folder FOLDER_ID

Where:

  • PROJECT_ID is the ID or number of the project you wish to migrate.
  • ORGANIZATION_ID is the ID of the organization to which you want to move the project. You can only specify one target, either an organization or a folder.
  • FOLDER_ID is the ID of the folder to which you want to move the project. You can only specify one target, either a folder or an organization.

API

Using the v1 Resource Manager API, you can move a project by setting its parent field to the ID of the destination resource.

To migrate a project=:

  • Get the project object using projects.get() method.
  • Set its parent field to the organization ID of the organization, or the folder ID of the folder to which you are moving it.
  • Update the project object using projects.update() method.

The following code snippet demonstrates the steps above:

    project = crm.projects().get(projectId=flags.projectId).execute()
    project['parent'] = {
        'type': 'organization',
        'id': flags.organizationId
    }

    project = crm.projects().update(
    projectId=flags.projectId, body=project).execute()

Roll back a migration

If you have mistakenly moved a project, you can roll back the operation by performing the move again, with the old source as the new destination, and the old destination as the new source. You must have the necessary IAM permissions and organization policies enforced to allow this as if this were an entirely new migration.

Handling special cases

Migrating projects with no organization

You can migrate a project that is not associated with an organization into an organization. However, you can't change it back to No organization using this process. If you have a project that is associated with your organization and you want to revert it to No organization, reach out to your Support representative for assistance.

The process of migrating a project not associated with an organization is similar to the process for migrating a project between organizations, but does not require all of the steps involved in the migration plan. To migrate a project into an organization, you should follow these steps:

  1. Verify the impact on this project of the policies it will inherit.

  2. Create a dedicated import folder in the destination organization, if desired.

  3. Assign Identity and Access Management permissions for the project and the destination parent as detailed in Assign permissions.

  4. Determine if you need to change the billing account.

Then, you can perform the migration.

Console

To migrate a project into an organization:

  1. Open the IAM & admin > Settings page in the Cloud Console.

    Open the Settings page

  2. Select the Project picker at the top of the page.

  3. From the Organization picker, select No Organization. If you are not associated with any organization, the Organization picker will not appear, and you can skip this step.

  4. Select the project you want to migrate.

    Screenshot of project picker

  5. At the top of the page, click Migrate.

  6. On the Organization drop-down list, select the organization you want to migrate your project to..

gcloud

To migrate a project into an organization, run the following command:

gcloud beta projects move PROJECT_ID \
    --organization ORGANIZATION_ID

Where:

  • PROJECT_ID is the ID of the project you wish to move into the organization.
  • ORGANIZATION_ID is the ID of the organization to which you wish to move the project.

API

Using the Resource Manager API, you can move a project into the organization resource by setting its parent field to the organization ID of the organization.

To migrate a project into the organization:

  • Get the project object using projects.get() method.
  • Set its parent field to the Organization ID of the organization.
  • Update the project object using projects.update() method.

You can't change the parent field after you set it.

The following code snippet demonstrates the steps above:

    project = crm.projects().get(projectId=flags.projectId).execute()
    project['parent'] = {
        'type': 'organization',
        'id': flags.organizationId
    }

Shared VPC

Shared VPC projects can be migrated following certain conditions. First, a user with the roles/orgpolicy.policyAdmin role in the source organization must set an organization policy containing the constraints/resourcemanager.allowEnabledServicesForExport constraint on the parent of the project to be exported. This constraint should list SHARED_VPC as an allowed_value.

The Shared VPC host project must be migrated first, followed by all of its service projects. We recommend that you match the firewall rules between the organizations at the source and target locations, which should minimize potential issues and avoid any downtime for the projects and network during the migration. We do not offer guarantees about the healthiness of your network if you leave some service projects in the source organization indefinitely while migrating others.

If you move the host project, you can move it back to the source organization, but once you begin moving the service projects, you must move all of them before you can move the host project again.

Custom Identity and Access Management roles

Custom Identity and Access Management roles can be created at the organization level to provide granular control of access to resources, but they are only valid in the organization in which they are created. If you try to move a project that contains an IAM policy binding of a user to an organization-level custom IAM role, the move will fail with a failed precondition error, explaining that the role in question does not exist in the destination organization.

To list all custom IAM roles at the level of your organization, run the following gcloud command-line tool command:

gcloud iam roles list --organization ORGANIZATION_ID

Where the ORGANIZATION_ID is the organization ID for which you want to list roles. For information on finding your organization ID, see Creating and managing organizations.

To get information on a custom Identity and Access Management role in your organization, run the following gcloud command-line tool command:

gcloud iam roles describe --organization ORGANIZATION_ID \
    ROLE_ID

Where:

  • ORGANIZATION_ID is the organization ID of the role's parent organization.

  • ROLE_ID is the name of the role you want to describe.

To work around the failed precondition error, you should create equivalent project-level custom roles for each of the organization-level custom roles that the project inherits. Then, remove the IAM role bindings that reference the organization-level custom roles.

Once the project has been migrated, you can update the IAM policies to use the organization-level custom roles in the destination organization.

For more information about custom roles, see Creating and managing custom roles.

Bucket Lock

Cloud Storage Bucket Lock allows you to configure a data retention policy on a Cloud Storage bucket that governs how long objects in the bucket must be retained. The bucket lock is protected using a lien to prevent accidentally deleting the project.

The retention policy and lien are kept with the project during a migration, but you should be aware if you are moving a project with a bucket lock enforced, and prevent accidental moves.

VPC Service Controls security perimeters

VPC Service Controls allows users to set up a project-based security perimeter around their Google Cloud services to mitigate data exfiltration risks. You cannot migrate a project that is protected by a VPC Service Controls security perimeter.

To remove a project from a security perimeter, see Managing service perimeters. Projects in VPC Service Controls perimeters may not be blocked from being moved across organizations for up to a day after a perimeter has been created or updated. It may take several hours for the project to be movable after it has been removed from the service perimeter.

Dedicated Interconnect

We recommend migrating projects with Dedicated Interconnect objects and projects with VLAN attachments to these Dedicated Interconnect objects together. While projects with Dedicated Interconnect objects or VLAN attachments connected to them can be migrated and will function between organizations, you will not be able to create new VLAN attachments across the organization split.

Configuration changes made to a project in one organization that has a Dedicated Interconnect object attached or a VLAN attachment to the Dedicated Interconnect object may not propagate to the other, so we recommend not leaving such projects split across organizations for very long if possible.

Partner Interconnect

There are no special considerations needed when migrating projects with Partner Interconnect.

Assured Workloads

You cannot move an Assured Workloads project between organizations. Any attempt to do so will be programmatically blocked.

Cross-project service accounts

If you are moving a project that has a cross-project service account attached to it, that service account will still function in the destination organization. That project will continue to work with the attached service account even if there is an organization policy that restricts the domain of that project.

If you are moving a project that owns a cross-project service account attached to another project in the source organization, the service account will still function in the destination organization. However, you will not be able to use the service account on any resources that have a domain restriction organization policy applied to them that restricts them to the source organization's domain.

For example, assume you have project-A, in organizations/12345678901. This project has serviceAccount-1 attached to it, which is set up as a cross-project service account. project-B and project-C, also in organizations/12345678901, use serviceAccount-1 as well.

You have applied an organization policy with the domain restriction constraint to project-C, which only allows it to access the domain of organizations/12345678901.

If you add serviceAccount-1 to the IAM binding for project-C, and then move project-A to organizations/45678901234, the service account will function.

If you move project-A to organizations/45678901234, and then try to add serviceAccount-1 to the IAM binding for project-C, the binding will fail as it violates the domain restriction constraint.

Support cases

If you move a project that has an open support case, you need to reach out to your Google Support contact to let them know the migration has occurred. Any projects that have an open support case with Google will not be able to view those support cases until Google Support updates the case metadata to point to the new organization.

If your project is configured to use an Internal OAuth consent screen and you migrate it to another organization, only members of the destination organization can authorize requests. It may take up to 24 hours for this behavior to take effect. Until then, members of the source organization can authorize requests.

The steps below explain how to ensure members in your source organization do not lose access during migration. Consider creating new users in your destination organization for organization members so that you do not need to change the OAuth consent screen configuration.

To avoid loss of access for members in the source organization:

  1. Update the OAuth consent screen to be external instead of internal.

  2. Apps that are marked internal and use sensitive data do not need to apply for app verification. If the app uses sensitive data, then when the consent screen is updated to external, the users of the source organization will see an unverified app screen before the authorization screen. To avoid this, apply for app verification for the use of sensitive or restricted scopes.

OS Login

If OS Login is enabled in your source project, assign the roles/compute.osLoginExternalUser IAM role to the members of the source project, in the destination organization to avoid those members losing access.

Attaching service accounts to resources

For most Google Cloud services, users need the iam.serviceAccounts.actAs permission on a service account to attach that service account to a resource. However, in the past, to ease onboarding certain services allowed users to attach service accounts to resources even if the users didn't have permission to impersonate the service accounts. This is documented here.

If a customer's source organization has the legacy behavior (service accounts attachment is possible without the normal role grant) and the destination organization does not, grant roles/iam.serviceAccountUser to users that attach these service accounts to resources. For information about impersonating service accounts, see Impersonating service accounts.

To see if your organization has the legacy behavior, do the following:

  1. In the Cloud Console, go to the Organization policies page.

    Go to the Organization policies page

  2. From the project selector at the top of the page, choose the organization you want to check for legacy status.

  3. In the filter box at the top of the list of organization policies, enter constraints/appengine.enforceServiceAccountActAsCheck.

  4. If the appengine.enforceServiceAccountActAsCheck organization policy appears in the list, the organization has the legacy behavior.

  5. Repeat steps 3 and 4 for each of the following organization policy c constraints:

    • appengine.enforceServiceAccountActAsCheck
    • dataflow.enforceComputeDefaultServiceAccountCheck
    • dataproc.enforceComputeDefaultServiceAccountCheck
    • composer.enforceServiceAccountActAsCheck
  6. If any of these organization policy constraints appear, your organization uses the legacy behavior.

If the source organization has the legacy behavior and the destination does not, grant the roles as mentioned above. If both the source and destination organizations have the legacy behavior, no action is required, but consider enforcing the policy to prevent unintended impersonation.