Search code examples
azureterraformterragrunt

DRY code with terragrunt to deploy resource group and key vault with azure


TL;DR at the end.

I am completely new to terragrunt and I am trying to use it to take advantage of the DRY (don't repeat yourself) feature it offers. My tree is shown below, I plan to use this repository for aws, gcp and azure, and in this use case I am only focusing on azure, once I will have understand the usage of terragrunt I should be able to apply the logic for other providers. My tree might be one of the issues so do not hesitate to let me know if I did it wrong.

I would like to reuse my code instead of copy pasting the same thing over and over again. Focusing azure, the end goal here is to create only a resource group with an azure key vault inside it to be able to understand how works the usage of terragrunt.

From my understanding creating the tenant.hcl, subcription.hcl and env.hcl allow me to not have to change this value in my code.

About the rest I might have forgotten some dependencies according to my error messages... I am positionning myself in IaC/deployments/subscription-test-1/dev/client-test/ and running a "terragrunt plan" but then get some failures with the following errors messages:

Error message:

The system cannot find the path specified. time=2023-03-30T09:26:00+02:00 level=error msg=Unable to determine underlying exit code, so Terragrunt will exit with error code 1

    IaC/
├─ deployments/
│  ├─ azure/
│  │  ├─ subscription-test-1/
│  │  │  ├─ dev/
│  │  │  │  ├─ client-test/
│  │  │  │  │  ├─ terragrunt.hcl
│  │  │  │  ├─ env.hcl
│  │  │  ├─ ppd/
│  │  │  ├─ subscription.hcl
│  │  ├─ subscription-test-2/
│  │  │  ├─ dev/
│  │  │  ├─ ppd/
│  │  ├─ subscription-test-3/
│  │  │  ├─ prd/
│  │  │  ├─ sbx/
│  ├─ aws/
│  ├─ gcp/
│  ├─ tenant.hcl
├─ modules/
│  ├─ aws/
│  ├─ azuread/
│  │  ├─ security-groups/
│  │  ├─ spn/
│  ├─ azurerm/
│  │  ├─ akv/
│  │  │  ├─ main.tf
│  │  │  ├─ variables.tf
│  │  ├─ rg/
│  │  │  ├─ main.tf
│  │  │  ├─ variables.tf
│  ├─ databricks/
│  ├─ gcp/
├─ project-templates/
│  ├─ aws/
│  ├─ azure/
│  │  ├─ project-template-solution-1/
│  │  │  ├─ akv.tf
│  │  │  ├─ main.tf
│  │  │  ├─ rg.tf
│  │  │  ├─ variables.tf
│  │  │  ├─ terragrunt.hcl
│  │  ├─ project-template-solution-2/
│  │  ├─ project-template-solution-3/
│  ├─ gcp/
├─ terragrunt.hcl

Below is the terragrunt & terraform code per folders:

IaC/terragrunt.hcl

locals {
  # Automatically load subscription variables
  subscription_vars = read_terragrunt_config(find_in_parent_folders("subscription.hcl"))

  # Automatically load tenant-level variables
  tenant_var = read_terragrunt_config(find_in_parent_folders("tenant.hcl"))

  # Automatically load environment-level variables
  env_vars = read_terragrunt_config(find_in_parent_folders("env.hcl"))
  
  environment       = local.env_vars.locals.environment
  subscription_id   = local.subscription_vars.locals.subscription_id
}

IaC/modules/azurerm/akv/main.tf

terraform {

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "3.42.0"
    }
  }
}

#Configure the Azure Resource Management Provider
provider "azurerm" {
    subscription_id = var.azure_subscription_id
    tenant_id = var.azure_tenant_id
    features {
    key_vault {
      purge_soft_delete_on_destroy    = true
      recover_soft_deleted_key_vaults = true
    }
  }
}

#create azure key vault
resource "azurerm_key_vault" "akv" {
  name                        = lower("${var.azure_project_code}-${var.azure_env_code}-akv-01")
  location                    = var.azure_resource_group_location
  resource_group_name         = var.azure_rg_name
  enabled_for_disk_encryption = true
  tenant_id                   = var.azure_tenant_id
  soft_delete_retention_days  = 7
  purge_protection_enabled    = false
  sku_name = "standard"
}

IaC/modules/azurerm/akv/variables.tf

variable "azure_subscription_id" {
  type        = string
  description = "Azure Subscription Id"
}

variable "azure_tenant_id" {
  type        = string
  description = "Azure Tenant Id"
}

variable "azure_rg_name" {
  type        = string
  description = "Azure Resource Group Name"
}

variable "azure_resource_group_location" {
  default = "west europe"
  description   = "Location of the resource group."
}

variable "azure_env_code" {
  type        = string
  description = "Azure Environment Code"
}

variable "azure_project_code" {
  type        = string
  description = "Azure Project Code"
}

IaC/modules/azurerm/rg/main.tf

terraform {


  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "3.42.0"
    }
  }
}

provider "azurerm" {
    subscription_id = var.azure_subscription_id
    tenant_id = var.azure_tenant_id
    features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
}

#create azure resource group
resource "azurerm_resource_group" "rg" {
  name     = var.azure_rg_name
  location = var.azure_resource_group_location

}

IaC/modules/azurerm/rg/variables.tf

variable "azure_subscription_id" {
  type        = string
  description = "Azure Subscription Id"
}

variable "azure_tenant_id" {
  type        = string
  description = "Azure Tenant Id"
}

variable "azure_rg_name" {
  type        = string
  description = "Azure Resource Group Name"
}

variable "azure_resource_group_location" {
  default = "west europe"
  description   = "Location of the resource group."
}

IaC/project-template-solution-1/terragrunt.hcl

include {
  path = find_in_parent_folders()
}

IaC/project-template-solution-1/akv.tf

module "akv" {
    source                          ="../..//modules/azurerm/akv/"
    azure_subscription_id           = var.azure_subscription_id
    azure_tenant_id                 = var.azure_tenant_id
    azure_rg_name                   = var.azure_rg_name
    azure_resource_group_location   = var.azure_resource_group_location
    azure_project_code              = var.azure_project_code
    azure_env_code                  = var.azure_env_code
}

IaC/project-template-solution-1/rg.tf

module "rg" {
    source                          ="../..//modules/azurerm/rg/"
    azure_subscription_id           = var.azure_subscription_id
    azure_tenant_id                 = var.azure_tenant_id
    azure_rg_name                   = var.azure_rg_name
    azure_resource_group_location   = var.azure_resource_group_location

}

IaC/project-template-solution-1/main.tf

terraform {

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "3.42.0"
    }
  }
}

provider "azurerm" {
    subscription_id = var.azure_subscription_id
    tenant_id = var.azure_tenant_id
    features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
}

IaC/project-template-solution-1/variables.tf

variable "azure_subscription_id" {
  type        = string
  description = "Azure Subscription Id"
}

variable "azure_tenant_id" {
  type        = string
  description = "Azure Tenant Id"
}

variable "azure_rg_name" {
  type        = string
  description = "Azure Resource Group Name"
}

variable "azure_resource_group_location" {
  default = "west europe"
  description   = "Location of the resource group."
}

variable "azure_env_code" {
  type        = string
  description = "Azure Environment Code"
}

variable "azure_project_code" {
  type        = string
  description = "Azure Project Code"
}

IaC/deployments/azure/tenant.hcl

locals {
    tenant_id = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}

IaC/deployments/azure/subscription-test-1/subscription.hcl

locals {
    subscription_id = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}

IaC/deployments/azure/subscription-test-1/dev/env.hcl

locals {
  environment = "dev"
}

TL;DR: I am trying to deploy architecture mixing terraform and terragrunt by using modules (modules folder) and "calling modules" (project-templates folder). To deploy at first with azure a resource group with an azure key vault inside it.

I tried to upload my code to GitHub but this is my first time using it so I might've done mistakes. You can find it here if you want to download it and edit it and send me your updates. https://github.com/leanne-kami/IaC

Thanks for anyone who will take the time to help me :)


Solution

  • A friend helped me to fix the issue with the two following steps:

    1. Removing the dependency block in IaC/deployments/azure/subscription-test-1/dev/client-test/terragrunt.hcl
    2. Editing the path in IaC/project-templates/azure/project-template-solution-1/akv.tf and rg.tf to make the directory understand the actual location of module folders.
        module "rg" {
            source                          ="../..//modules/azurerm/rg/"
            azure_subscription_id           = var.azure_subscription_id
            azure_tenant_id                 = var.azure_tenant_id
            azure_rg_name                   = var.azure_rg_name
            azure_resource_group_location   = var.azure_resource_group_location
        }