Skip to content

Terraform Guide Azure

Vitalii Kanivets edited this page Aug 10, 2023 · 2 revisions

Terraform is an IaC tool used to create and change your virtual infrastructure. Custodian team uses Terraform for testing policies. Creation of a Terraform code will require you to follow the procedure and general rules introduced below.


Table of Contents

  1. Pre-requisites
    1.1. Create folders
    1.2 Green/Red folder structure
  2. Rules for Terraform code creation
    2.1. Split terraform resources by service into separate files
    2.2. Content of "provider.tf" file
    2.3. Content of "variables.tf" file
    2.4. Content of "terraform.tfvars" file
    2.5. A "resource" block name
    2.6. Value of the argument "Name"
    2.7. Tags
    2.9. Random password generation
  3. Terraform language style conventions
  4. Terraform basic tutorials

Pre-requisites

Create folders

Before you start writing a code, you need to create the necessary folders.

Perform the following steps:

1. In the local branch, in the folder "terraform", create a general folder with the name of the policy, e.g., "ecc-azure-000-example_policy".

2. In this folder, create three other folders:

  • Folder with "green" infrastructure – name: "green"
  • Folder with a JSON file with permissions for a user to run Custodian policy – name: "iam"
  • Folder with "red" infrastructure – name: “red”

This should look something like this (Azure example):

image

ℹ️ Note: In some cases, red or green infrastructure building is not possible.

 Green/Red folder structure

Green and red infrastructure folders have the same structure:

  • Resources that will be created;
  • Default variables;
  • Terraform vars (terraform.tfvars);
  • Provider configuration for connecting with Azure account.

For example:

image

Rules for Terraform code creation

Split terraform resources by service into separate files

If you have a script with multiple resources, it is recommended to create separate files for the main of them.
For example, it will be easier for understanding to have separate files containing information about the storage (storage.tf), vault configuration (key_vault.tf), etc.

image

Content of "provider.tf" file

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
  }
}

provider "azurerm" {
  features {}
}

Content of "variables.tf" file

variable "prefix" {
  type = string
}

variable "location" {
  type = string
}

variable "tags" {
  type = map(string)
}

Content of "terraform.tfvars" file

prefix = <rule_number>		# e.g. prefix = "348"

location = "eastus"

tags = {
  CustodianRule    = "ecc-azure-348-mysql_harden_usage_for_local_infile"
  ComplianceStatus = "Green"
}

ℹ️ Note: All regions and locations are used as an example and can be changed depending on your case.

A "resource" block name

The "resource" block name should be assigned according to the recommendations below:

  • If the resource module creates a single resource of a specific service, the resource name should be this :
resource "azurerm_app_service_certificate" "this" {
  # ... remaining arguments omitted
}
  • If you have multiple resources of a specific service, then more descriptive names should be assigned: private, public, or main :
resource "azurerm_subnet" "public" {
  # ... remaining arguments omitted
}
  • If you have multiple resources but with the same or similar configurations, their functionality should be described in a comment before the resource name. You can also name them bucket1, bucket2:
# resource description
resource "azurerm_role_definition" "role1" {
  # ... remaining arguments omitted
}

Value of the argument "Name"

Value of the argument "Name" must include:

  • Rule ID;
  • Resource description;
  • Infrastructure identification: "green" or "red".

For example:

resource "azurerm_resource_group" "this" {
  name     = "002-rg-green"
  location = "eastus"
}

In some cases, a "name" cannot include a symbol "_" or be started with numbers and should look as follows:

resource "resource" "this" {
  bucket = "resource-000-green"
}

resource "resource" "this" {
  name = "000resourcegreen"
   # ... remaining arguments omitted
}

Tags

Tags should contain the rule name and compliance status - "green" or "red":

resource "resource" "this" {
  name = "000_resource_green"

  # ... remaining arguments omitted

  tags = {
   CustodiaRule     = "ecc-azure-000-example_policy"
   Description      = "..."  
   ComplianceStatus = "Green"
  }
}

ℹ️ Note: The line containing description is optional 

Tags, as well as meta-arguments "depends_on" and "lifecycle", should be separated by a single empty line:

resource "resource" "this" {
  name = "000_resource_green"

  # ... remaining arguments omitted

  tags = {
   CustodianRule    = "ecc-azure-000-example_policy"
   Description      = "..."
   ComplianceStatus = "Green"
  }

 depends_on = {
      ...
  }

  lifecycle = {
      ...
  }
}

Random password generation

All passwords (IDs where possible) should be randomly generated:

resource "random_password" "this" {
  length           = 12
  special          = true
  number           = true
  override_special = "!#$%\*()-_=+[]{}:?"
}

resource "azurerm_mssql_server" "this" {

  # ... remaining arguments omitted

  name                         = "014-azuresqlserver-green"
  administrator_login_password = random_password.this.result
}

Terraform basic tutorials