Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Last active January 31, 2024 13:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save salrashid123/e0b1fbf662f52e89711f48871ae1c346 to your computer and use it in GitHub Desktop.
Save salrashid123/e0b1fbf662f52e89711f48871ae1c346 to your computer and use it in GitHub Desktop.
Migrate non-org gcp project into org wihout console

this will migrate a project (your-project-to-migrate) that sits outside of an cloud org (yourdomain.com)

  1. its owned by alice@domain

  2. admin@domain is a cloud org domain owner who can migrate a project over

  3. enable domain wide delegation on a service account with scopes

    "https://www.googleapis.com/auth/cloud-platform"

    see ref

  4. run the program below to assign both

    "roles/resourcemanager.projectMover" "roles/resourcemanager.projectIamAdmin" roles to admin@ against your-project-to-migrate

  5. wait 60s, migrate project as admin@:

    gcloud beta projects move your-project-to-migrate


package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/option"

	"google.golang.org/api/cloudresourcemanager/v1"
)

const (
	projectID = "core-eso"
)

func main() {

	ctx := context.Background()

	data, err := ioutil.ReadFile("/home/srashid/gcp_misc/certs/dwd_core-eso.json")
	if err != nil {
		fmt.Println(err)
		return
	}

	credentials, err := google.CredentialsFromJSONWithParams(ctx, data, google.CredentialsParams{
		Scopes:  []string{"https://www.googleapis.com/auth/cloud-platform"},
		Subject: "alice@yourdomain.com",
	})
	if err != nil {
		fmt.Printf("error getting credentials: %v", err)
		return
	}

	crmService, err := cloudresourcemanager.NewService(ctx, option.WithCredentials(credentials))
	if err != nil {
		log.Fatalf("cloudresourcemanager.NewService: %v", err)
	}

	projectID := "your-project-to-migrate"
	member := "user:admin@yourdomain.com"
	role := "roles/resourcemanager.projectMover" // "roles/resourcemanager.projectIamAdmin"
	addBinding(crmService, projectID, member, role)

}

func addBinding(crmService *cloudresourcemanager.Service, projectID, member, role string) {

	policy := getPolicy(crmService, projectID)

	var binding *cloudresourcemanager.Binding
	for _, b := range policy.Bindings {
		if b.Role == role {
			binding = b
			break
		}
	}

	if binding != nil {
		binding.Members = append(binding.Members, member)
	} else {
		binding = &cloudresourcemanager.Binding{
			Role:    role,
			Members: []string{member},
		}
		policy.Bindings = append(policy.Bindings, binding)
	}

	setPolicy(crmService, projectID, policy)

}

func getPolicy(crmService *cloudresourcemanager.Service, projectID string) *cloudresourcemanager.Policy {

	ctx := context.Background()

	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
	defer cancel()
	request := new(cloudresourcemanager.GetIamPolicyRequest)
	policy, err := crmService.Projects.GetIamPolicy(projectID, request).Do()
	if err != nil {
		log.Fatalf("Projects.GetIamPolicy: %v", err)
	}

	return policy
}

func setPolicy(crmService *cloudresourcemanager.Service, projectID string, policy *cloudresourcemanager.Policy) {

	ctx := context.Background()

	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
	defer cancel()
	request := new(cloudresourcemanager.SetIamPolicyRequest)
	request.Policy = policy
	policy, err := crmService.Projects.SetIamPolicy(projectID, request).Do()
	if err != nil {
		log.Fatalf("Projects.SetIamPolicy: %v", err)
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment