Deploying Multiple OS-Patches to Different GCP Projects Using Terraform & Terragrunt

Asrın Andırın
8 min readOct 15, 2023

--

Greetings to everyone. In this article, we will deploy an operating system patch to multiple VMs that reside in different GCP projects using Terraform & Terragrunt.

I would like to start by assuming that you have knowledge of Terraform and Google Cloud. During the next sections, we will discover some shortcomings of Terraform and see how we can eliminate these shortcomings with Terragrunt. Then, we will have an example to better understand the principles.

Key Concepts

  • VM Manager Review.
  • Terraform OS-Patch Module Review.
  • Terraform Shortcomings Against Wide Range Operations.
  • What is Terragrunt ?
  • Terragrunt pros.
  • Implementation.

VM Manager

VM Manager is a suite of services available in Google Cloud Platform (GCP) that provides capabilities for automating patch deployment and managing virtual machines. It includes services such as Patch, OS inventory management, and OS policies.

  • Patch: Apply patches manually or on a schedule. Check compliance with patches using Patch.
  • OS inventory management: Gather and review operating system details with this service.
  • OS policies: Install, uninstall, and automatically update software packages using this service.

Pricing

The VM Manager suite is offered as a single service at a fixed rate for each VM with an active OS Config agent. Charges are based on the number of VMs with active agents:

  • Free tier allows up to 100 VMs per month per Cloud Billing account for testing purposes.
  • Beyond the free tier, each active OS Config agent on a VM is charged $0.003 per hour per VM.

Terraform OS-Patch Module Review

This module makes it easy to deploy new patch deployments to the GCP VM Manager for Centos and Windows servers. I plan to expand this module and include other services according to the company’s needs in the upcoming periods, but its current state will be more than sufficient for us.

This module will basically create/trigger patch deployment for one or more VM instances that have CentOS or Windows operating systems. You will need a service account in the organization scope with the role of PatchDeployment Admin to apply this solution.

To understand this module in more depth, you can examine in the git repo.

Terraform Shortcomings Against Wide Range Operations

Handling the state file, especially in a team or multi-module environment, can be quite challenging and susceptible to errors. It requires careful attention and meticulous management.

In such scenarios, the backend block restricts the usage of any additional variables, limiting flexibility and adaptability. This can lead to code repetition, as similar configurations need to be duplicated across various environments and modules. As a result, the codebase becomes more complex, difficult to maintain, and prone to inconsistencies.

Fortunately, we have a tool to overcome these and similar deficiencies.

What is Terragrunt ?

Terragrunt is an open-source tool developed by Gruntwork that acts as a thin wrapper for Terraform, an infrastructure as code (IaC) tool. Terragrunt simplifies and enhances Terraform’s capabilities by providing features for managing multiple Terraform modules, handling remote state, and improving the organization and reusability of configurations. It helps address some of the challenges and complexities that can arise when working with Terraform at scale or in a team environment.

Terragrunt Pros

Remote State Management: Terragrunt simplifies remote state management by configuring and automating the setup of state storage, such as Google Cloud Storage, and locking to prevent conflicts when multiple people or processes attempt to modify the same state.

DRY (Don’t Repeat Yourself) Configurations: Terragrunt enables you to reuse common configurations in multiple environments or projects, keeping your Terraform code concise and making it easier to maintain your infrastructure code.

Efficient Dependency Management: Terragrunt efficiently manages dependencies between modules by allowing developers to explicitly define them. This ensures the correct order of module application and enables the passing of outputs from one module to another, facilitating data sharing and chaining between multiple modules.

Automated Initialization: Terragrunt automates the process of setting up a module. It makes sure that all the things required for the module, like downloading providers and modules, are done before applying the module.

Implementation

There are a couple more implementation practices for the Terraform & Terragrunt duo. I will apply my choice, and of course, you can go with the way you like.

I manage all of my configurations with the terragrunt.hcl file. You need to add this file to all project configuration folders and one for the parent folder. As you create project configuration folders, you need to name them with the exact project ID. You will understand why in the next parts.

There is parent terragrunt.hcl file below. We control all of the inputs, remote state configurations and provider configurations here.

inputs = {

// Common Configs, they will applied to the all projects.

// Centos Patch Configurations
security = true
minimal = false
// Windows Patch Configurations
classifications = ["SECURITY"]
time_of_day = [ 0,30,0,0 ]
reboot_config = "NEVER"
duration = "5600s"

// Prod-1 project configs
month_day-prod1 = 10
patch_deployment_id-prod1 = "prod-1-windows-centos-sec-patches"
instances-prod1 = ["my-windows-1,us-central1-a","my-windows-2,us-central1-b","centos-api,us-central1-c"]

// Test-1 project configs
month_day-test1 = 2
patch_deployment_id-test1 = "test-1-windows-sec-patches"
instances-test1 = ["windows-central-1,us-central1-f","windows-dev,us-central1-c"]

// Test-2 project configs
month_day-test2 = 4
patch_deployment_id-test2 = "test-2-centos-sec-patches"
instances-test2 = ["windows-1,us-central1-f","centos-test-dev,us-central1-c", "centos-2,us-central1-d"]

}

remote_state {
backend = "gcs"
config = {
bucket = "<your-backend-name>"
prefix = path_relative_to_include()
}
}

generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF

provider "google" {
project = "${path_relative_to_include()}"
}

terraform {
backend "gcs" {}
required_providers {
google = "4.10.0"
}
}
EOF
}
  • Inputs block variables are set for various projects, each with specific configurations. Common configurations, such as security, minimal, classifications, time_of_day, reboot_config, and duration, are defined at the top and are shared by all projects. Project-specific configurations are then defined, such as month_day, patch_deployment_id, and instances, for different projects (prod-1, test-1, and test-2).
  • path_relative_to_include() returns exact path to the parent folders from where you apply “include” block in child folders. We use this function to configura “project” setting for provider.tf file. This is why we use project ID’s for folders.
  • generate block creates a provider.tf file in all child folders. It uses the google provider and sets the project attribute based on the project's relative path. The backend for Terraform is configured to use GCS as well. It specifies the required provider version (4.10.0) for Google Cloud.
  • remote state defines the backend for storing Terraform state files. It uses Google Cloud Storage (GCS) as the backend. It creates seperate folders and independent states for all projects.

Then we need to include “include” block to the child folders. In this way, Terragrunt will be able to see each Terraform modules.

// os-module-terragrunt/prod-1-401709/terragrunt.hcl
// os-module-terragrunt/test-1-401709/terragrunt.hcl
// os-module-terragrunt/test-2-401709/terragrunt.hcl

include "root" {
path = find_in_parent_folders()
}

Finally, there is an example module usage for project prod-1. There are common and specific input variables. You use the exact same variable names for common variables.

module "patch_management" {
source = "github.com/asrinandirin/os_patch_management/"
patch_deployment_id = var.patch_deployment_id-prod1
instances = var.instances-prod1
security = var.security
minimal = var.minimal
classifications = var.classifications
time_of_day = var.time_of_day
reboot_config = var.reboot_config
duration = var.duration
month_day = var.month_day-prod1
}

Now all our configuration files are ready. Next is to apply Terragrunt commands to bring everything alive. But before that, lets examine Terragrunt three basic commands.

Terragrunt init

  1. Downloads Terraform modules and providers: Terragrunt checks the source attribute in your Terragrunt configuration file to find and download the necessary modules and providers.
  2. Creates a .terraform directory: It creates a directory to store the downloaded Terraform modules, providers, and other required files.
  3. Generates a Configuration Cache: Terragrunt saves provider configurations in a cache to avoid redundant downloads, improving command speed.
  4. Performs Validation: Terragrunt checks configuration files for issues and ensures they are properly set up for use.

Terragrunt Plan

  1. Generates a Terraform Plan: When you run terragrunt plan, Terragrunt calls terraform plan for each module in your Terragrunt configuration. Terraform compares the current and desired states of your infrastructure to create an execution plan.
  2. Outputs Proposed Changes: The plan provides detailed information on what Terraform will do, such as creating, modifying, or destroying resources. It is presented in a human-readable format for easy review and understanding.
  3. Validation and Analysis: terragrunt plan validates your Terraform configurations, identifying issues or potential problems for the apply phase. This helps catch errors and misconfigurations before making changes.
  4. No Infrastructure Changes: Importantly, terragrunt plan doesn't modify your infrastructure. It is a read-only operation to review and understand the effects of proposed changes before applying them.

Terragrunt Apply

  1. Executing Terraform Apply: When you run terragrunt apply, it applies the changes defined in your Terragrunt configuration to create, modify, or delete resources as described in your Terraform code.
  2. Propagating Infrastructure Changes: The Terraform apply process updates your cloud infrastructure or target environments based on the changes defined in your code. This includes creating new resources, updating existing ones, or possibly deleting resources, depending on your Terraform configurations.
  3. User Confirmation: Before making any changes, Terraform (and Terragrunt) typically asks for confirmation by requesting you to type “yes”. This confirmation step helps prevent accidental modifications.
  4. Logging and Output: During the apply process, Terraform and Terragrunt provide detailed output to inform you about the progress of the applied changes, such as resource creation or updates. Monitoring this output ensures that everything is progressing as expected.
  5. State File Updates: After successfully applying changes, Terraform updates the state file, which records the current state of your infrastructure. This state file is essential for future Terraform runs, as it helps track the existing infrastructure.
  6. Error Handling: If any issues or errors occur during the apply process, Terraform and Terragrunt will provide relevant error messages and, in most cases, revert the changes to maintain a consistent infrastructure state.

After you apply Terragrunt commands in the proper order, you will have three different scheduled deployments in three different projects. Additionally, you will have three different Terraform states stored in a single bucket within an organized folder structure. Moreover, you can choose different buckets to store the states of each project.

Buckets State View

Conclusion

We applied a previously prepared Terraform module to multiple projects. We stored our state files independently of each other in a GCS bucket and completed our configuration by following the DRY (Don’t Repeat Yourself) principles. We accomplished all of this using the Terragrunt tool. In the upcoming articles, I will continue to share with you many more benefits and ways of using Terragrunt.

Thanks for reading :)

--

--

No responses yet