Implementing GCP VPC Service controls using Terraform (Terragrunt)

Harinderjit Singh
ITNEXT
Published in
8 min readJun 27, 2023

--

Objective

VPC service controls is an amazing security feature from the Google Cloud Platform which I was really curious about, and fortunately, I got to work with an environment where this was implemented.

VPC Service Perimeters function like a firewall for GCP APIs. If you want to create a resource in GCP, you invoke an API to do so. GCP APIs are exposed over public internet. Suppose you lost private key for a service account which has editor role on a project, anyone with access to the private key can create or edit resources in your project. SCARY 😱!!! To protect from such attacks, you can choose which projects or VPC networks you wish to be part of the perimeter and which services you want to be protected by it.

To learn more about it, I explored the official documentation and some training videos and found it a very interesting and complex topic. To clear some of my doubts, I am going to do some experiments related to implementing VPC service controls with a shared VPC network environment. The experiments and tests are covered in a separate post.

As a prerequisite to performing those experiments, I needed to set up the infrastructure, and I decided to use terraform and terragrunt to do that. We will go through the whole process to do the same. I have shared a public git repository so that you can try the same and learn about implementing VPC service controls in a GCP environment with a shared VPC network.

First, Let’s start with basic terms related to VPC Service Controls (VPC SC) and after that, we will proceed to the goal of this post.

Basic terminology related to VPC Service controls

VPC Service Controls: GCP Technology that enables us to define a service perimeter around resources of Google-managed services to control communication to and between those services

Service perimeter: A service perimeter around Google-managed resources. It allows free communication within the perimeter but, by default, blocks all communication across the perimeter.

Ingress rule: A rule that allows an API client that is outside the perimeter to access resources within a perimeter. Ingress rules allow to use projects, VPC Networks, and access levels as sources.

Egress rule: A rule that allows an API client or resource that is inside the perimeter to access Google Cloud resources outside the perimeter. The perimeter does not block access to any third-party API or services on the internet.

Service perimeter bridge: A perimeter bridge allows projects in different service perimeters to communicate. Perimeter bridges are bidirectional, allowing projects from each service perimeter equal access within the scope of the bridge.

Instead of using a perimeter bridge, it is recommended to use ingress and egress rules that provide more granular controls.

Access level: A classification of requests over the internet based on several attributes, such as source IP range, client device, geolocation, and others. A service perimeter can be configured to grant access from the internet based on the access level associated with a request. Access level can’t be used for egress.

Access policy: A GCP resource that defines service perimeters. You can create access policies that are scoped to specific folders or projects alongside an access policy that can apply to the entire organization.

Architecture

Let's take a quick look at the architecture we are working with:

  • An un-scoped access policy at organization level.
  • A Service Perimeter which protects the Service projects, a Host project, and the Shared VPC (in the Host project). You may exclude or include projects as per needs. I am creating another service perimeter which by default is not protecting any resources but will be used in next post.
  • Few Restricted APIs which include APIs such as compute.googleapis.com, storage.googleapis.com, etc.
  • Access levels are an extra level of security requirements based on request attributes such as location, IP, Identity, etc. You can require that incoming requests meet these access levels in order to access resources. We are using three conditions to validate the access i.e. IP address, identity, and the location of the API client.
  • A simple ingress rule which allows access to all restricted APIs in all protected projects and shared VPC only if all conditions in the ingress rule are met. Here we are using the Ingress rule which validates that the request source should be validated by access level and the identity of the API client should be “harinderjit.singh@xx.com”.
  • Rule in Ingress policy applies to all the projects protected by the perimeter.
  • Within the perimeter, APIs are accessible unless explicitly restricted using an ingress rule.
  • An egress rule that you can create if you need to make an API call to resources in another Service Perimeter or to unprotected GCP resources. The default one will allow all egress to the projects selected in the configuration.
  • In this config, Ingress and Egress rules apply to all the services (select all services on “to” section of the rule)
  • VPC accessible services for perimeter is set to “RESTRICTED-SERVICES”.

Here is a diagram of a simple VPC SC design that I am implementing using Terraform.

Components to provision

  1. A GCP host project
  2. A GCS Bucket in host project (for terraform state files)
  3. A VPC Network
  4. 3 GCP service projects
  5. Enable Shared VPC
  6. Subnet IAM bindings to allow service projects to use subnets
  7. VPC SC Service perimeter and access level
  8. A GCE VM in a Service project

Requirements

Before you execute the code, you must ensure that the following pre-requisites are fulfilled:

  • GCP Organization. You must have Organization enabled in your domain. Click here to see how to create an organization with additional information.
  • A GCP folder
  • Install terraform, terragrunt, make, and gcloud CLI on the machine where Terraform is executed.
  • The Service Account or identity along with the editor and Compute Shared VPC Admin(compute.xpnAdmin) role
  • The Service Account or identity you will execute terraform with has the right permissions. In order to create a policy, you need to grant your service account/identity the Access Context Manager Admin role at the organization level: roles/accesscontextmanager.policyAdmin.
  • In order to view VPC Service Controls and Access Context Manager using the Google Cloud Platform Console, your user accounts will need to be granted the Resource Manager Organization Viewer: roles/resourcemanager.organizationViewer

This is a fresh implementation for learning purposes only. You may use/update the code as per your needs.

Implementation

Clone the GitHub repository

cd
git clone https://github.com/harinderjits-git/vpcsc-1.git

Edit the YAML as per your environment

  • core-prod-networks.yaml YAML file has the configuration of the Shared VPC Network.
  • If you need to add a subnet or change the subnet regions, you can edit this yaml, so changes to this yaml are really optional
~/vpcsc-1/terraform/gcp/terragrunt/orchestration/core-prod-networks.yaml
  • The second is config_env_sampleapp.yaml YAML file which has the configuration of the infrastructure.
~/vpcsc-1/terraform/gcp/terragrunt/orchestration/config_env_sampleapp.yaml
  • This one has billing information, organization information and other GCP and infrastructure configuration of you environment, so you will need to edit it.
  • Below snapshot describes the 8 inputs related to your GCP environment that you must update
  • In the same Yaml you can edit the VPC SC configuration, below snapshot describes what you must change.
  • You can add multiple service perimeters to access policy under vpcsc.service_perimeters
  • You can add or remove protected projects from the service perimeter.
  • You can select whether to add Shared VPC network to the perimeter
  • You can select what projects to add to “allowed egress” rule which allows the egress to all projects selected in the rule.
  • You can select what projects to add to “allowed ingress” rule which allows the API calls from all projects selected in the rule.
  • You can add or remove allowed IPs, Locations, and identities to access level configuration

Once you have updated the config_env_sampleapp.yaml with values as per your environment and needs, you can try and provision the infrastructure.

Provision Infrastructure

  • Initiate terraform remote state.
  • This step will create a GCP Host project and a storage bucket in the host project for storing terraform remote state.
gcloud auth  application-default login  #follow the prompts
cd ~/vpcsc-1/terraform/gcp/rundir_init
. ~/vpcsc-1/terraform/gcp/terragrunt/set-env.sh
terraform init
terraform apply -auto-approve
  • Create all base infra GCP resources such as service projects, subnet IAM bindings, shared VPC and VPC service control perimeter using terragrunt and terraform
cd  ~/vpcsc-1/terraform/gcp/terragrunt
make apply-base-infra
  • Let’s try to create a VM in the GCE project
make apply-gce-vm

And it fails because of the VPC SC perimeter. But didn’t I add my location, IP, and identity to the access level configuration? 👀

Looking further, I figured that the Public IP I used in the configuration was wrong. I used the console to edit the access level, corrected my configuration in yaml, and reran terragrunt apply for vpcsc.

So it worked as expected.

Let’s try again and create a VM

make apply-gce-vm

It worked and created VM

A Quick Test

We will dig deeper into VPC SC testing with some scenarios. For now, I am going to do another test where I am going to change the allowed Location in the Access level from US/CA to IN

cd  ~/vpcsc-1/terraform/gcp/terragrunt
make apply-base-infra

Now let’s try to destroy the VM

make destroy-gce-vm

And since I am in North America, an attempt to destroy should fail because Terraform can’t read the state file which is stored in GCS Bucket which is part of the same VPC SC perimeter.

To destroy this infra, I will have to edit the access level and add US/CA location as the allowed location and wait for 15 mins.

Now I can go ahead and delete the VM successfully.

So if you have followed all steps till here, you should be all set with a working environment with a Shared VPC and a secure VPC Service control perimeter. You can now proceed to my next post about conducting some interesting tests on VPC Service Controls.

References

Please read my other articles as well and share your feedback. If you like the content shared please like, comment, and subscribe for new articles.

--

--

Technical Solutions Developer (GCP). Writes about significant learnings and experiences at work.