Cloud Foundation Toolkit: The Starting Point for Your GCP Journey

Hugo Soto
Globant
Published in
7 min readDec 21, 2023
Deployed infrastructure diagram. Image source: CFT website

Sometimes, customers want to move their solutions to the cloud with the help of Google, and since you know your tools, you want to use Terraform to keep track of the resources you create. But then you think, is there something already created that can help fast-track the creation of all these resources? The answer is yes, and it is called the Cloud Foundations Toolkit (CFT). Google created several blueprints to help you create and manage the resources you need and their dependencies, also following the best practices for resource tracking, such as:

  • Managing Identity Access Management (IAM).
  • Keep track of the servers you create/need.
  • Configuring different flavors of Storage.

The most important part, have a unique source of truth for your whole organization. CFT, by default, anchors all the resources below one GCP organization. However, since CFT is not a silver bullet and doesn’t provide a “one size fits all solution,” you can customize the code to anchor the resources below a specific folder within your organization.

Note: The scope of this article is to use the default CFT configuration. If your organization needs a different layout, please refer to the documentation.

Understanding CFT

The stages described below are based on the order CFT is intended to be applied. Further details about this can be found in the official documentation. The list of stages is:

  1. Bootstrap
  2. Org (organization)
  3. Environments
  4. Networks
  5. Projects

Bootstrap

This stage sets up the very basic resources you need to get started. Here, you will need to choose between Jenkins and Cloud Build as a Continuous Integration/Continuous Deployment (CI/CD) solution. In this post, we will use Cloud Build. In whatever case, you can delete all the code related to the discarded solution. How would you know which resources are tied with Cloud Build and Jenkins? Jenkins’ solution comes commented out by default.

Organization

This stage creates all resources that will be used across different environments, teams, and so on because organization policies should be established here, along with projects for centralized logging and a security baseline for all other activities.

Environments

In this stage, you can create the different environments that will be available to your organization teams. The most common ones are development, non-production, and production. You can rename them and add more environments or delete the ones you don’t need. These environments are laid out in this example.

Networks

Before creating any resource, you need to make a choice. CFT offers two network designs: shared Virtual Private Clouds (VPC) or Hub and Spoke. In this article, we will focus on the latter and why this one and the comparison between those two models is a topic for another blog post.

Projects

As the name suggests, this stage aims to create all the necessary projects associated with the networks and environments you will have. As a best practice, you should aim for a component-segment approach. In other words, you should have a project for all the compute resources (VM instances, clusters, instance groups, etc.), another project for environment-scoped security (encryption keys, secrets), and so on.

Note: This is not a strict rule of deployment. CFT is modeled this way since this is the most common way to structure a foundational deployment. The final layout of the deployed resources, with default configuration, can be found here. If you need to change and customize where, how, and when things are deployed, you can do this easily, keeping in mind that you know what you are doing.

Real-Life Usage

Leaving the theory aside for a moment, when this solution was implemented, the customer didn’t have centralized infrastructure management and didn’t follow any particular workflow for handling their resources. CFT comes perfectly to start following Google's best practices. Particularly for us, the use case was to provision the infrastructure necessary for a new product they were releasing. One key change we needed to apply was to accommodate the code to live under a specific folder instead of one clean (no previously existing resource) GCP organization.

Implementation

The following configuration works for creating a cloud infrastructure from scratch, following the Google Cloud Foundation best practices. Below will detail some changes, per stage, we needed to make considering the client’s needs and requirements:

Bootstrap: In the org stage, we applied some configurations in the terraform.tfvars file:

# variable values in terraform.tfvars
billing_account = "aaaaaa-bbbbbb-cccccc"
organization_id = "111111111111"
default_region = "us-east1"
country_code = "SOME_COUNTRY_ID"
group_org_admins = "some_org_email@here.com"
group_billing_admins = "some_billing_email@here.com"
root_folder = {
display_name = "some_folder_name"
parent = "organizations/some_org_id_here"
}

Here, country_codeis a custom variable we need to use to comply with a client’s requirement. root_folder is another custom variable we needed to apply since we were creating the entire folder layout, which seemed a neat way of organizing the code.

Organization: In this stage, we are going to set the folder layout and configure the organization’s policies. It is important to note that these policies, in our case, were applied at the folder level since there were other products the client had in the same GCP organization we were working with:

# terraform.tfvars
terraform_service_account = "some-service-account-email@some-project-id.iam.gserviceaccount.com"
org_id = "some-org-id"
billing_account = "some-bill-acc-number"
env_code = "shr"
env_name = "shared"
app_code = "some-app-code"
app_name = "some-app-code"
country_code = "mcr"
country = "multi-country"

Let’s now review each of the variables in use:

  • terraform_service_account: defines the email of the service account Terraform uses to deploy all the resources.
  • org_id: ID of the organization where the resources will be created.
  • billing_account: Billing account ID to associate resources.
  • env_code: Shortened name for environment. The purpose of this variable is to make handling resources per environment more intuitive.
  • env_name: Full name of the environment.
  • app_code: Shortened name of the application. As a team decision, we agreed to use the name of the project for this property.
  • app_name: Full name of the application.
  • country: Full name of the country where the application would be available.
  • country_code: Shortened name of the country where the app is available.

A note about the country and country_code variables. They were initially a client’s requirement at the initial stage of the project, where the idea was to deploy the application progressively to different countries, and this variable would be responsible for handling that. But after conversations and project advances, it was discarded.

Environment: Keeping in mind that CFT doesn’t propose a “one size fits all” solution. In our case, we skipped the environment stage due mainly to the client’s requirements, being necessary to have a custom folder layout instead of the one layout CFT suggests.

Network: We needed to arrange this stage to scale (resource-wise) and execute it before creating the projects that will use the networks, subnets, and other potential resources created here. For this stage, we wrote terraform modules similarly so that in different stages, whoever adds more code to it would be familiar with all the stages and how to work with them. The following code shows, in a very simplified way, how we implemented the VPC network:

vpc_spokes = {
##### Dev Shared VPC
"${local.vpc_code}-dev-${var.svpc_prefix}" = {
project_id = data.google_project.some_project.id
description = "Some VPC description"
// custom VPC properties…
subnets = [
{
subnet_name = "some_subnet_name"
subnet_ip = "1.9.2.0/21"
// custom subnet properties…
},
// more subnets…
]
secondary_ranges = {
"some_sec_range_name" = [
{
range_name = "some_subnet_sec_range"
ip_cidr_range = "1.2.8.0/17"
},
// more sec ranges…
]
}
},
// more VPC definitions…
}

The default example of the CFT works with one data block pointing to the previous stage to use some of the previously built resources. In our opinion, this was a big approach, so we defined a data block whenever we needed to depend on a specific resource, not belonging to this stage. The best example of this is the usage of the project ID in the VPC configuration.

Projects: For this stage, before jumping into the terraform code, we structured the files into folders per environment. This allowed us to handle in a better way the resources created in each environment:

projects = {
### DEV Backend project
"${local.application_preffix}-backend" = {
folder_id = data.google_folder.some_folder.id
project_id_suffix = "some_suffix_id"
svpc_host_project_id = data.google_project.some_project.id
shared_vpc_subnets = data.google_compute_network.some_network.subnetworks_self_links
activate_apis = [
// some project APIs …
]
labels = {
// some project labels…
}
},
}

Services: For this particular project, we created a new stage called Services. This was needed to centralize all the extra configuration and infrastructure we were creating surrounding the micro-services the developers manage. Also, to create and manage the resources necessary to talk to the rest of the client’s services that are out of the scope of our responsibilities. I won’t be posting code in this section since we mainly use the currently available terraform modules for different services (GKE, Cloud SQL, Pub/Sub, IAM, etc.).

Conclusions

CFT enables you to quickly start up your customer’s deployments. It establishes a solid structure with the common use case of foundational deployment in mind while also giving flexibility in customizing the resource as you go. Using this as a starting point for this real-life usage, and the ones before has saved us a lot of time and headaches. However, as you can see from the resources it embraces, the first time you use CFT, you will have to invest a decent amount of time in understanding it before applying it. This product has a medium to steep learning curve. On the good side, you will learn to work with several blueprints for different services, which you will be able to reuse in different scenarios.

References

--

--