Posted on Leave a comment

Deploy resources on aws using terraform

Terraform is the most popular IAC tool among developers and devops engineers created by hashicorp. Anyone can use it freely to create multiple deployment environments and make the deployment procedure faster. In this article we will examine how we can use terraform AWS provider to deploy resources on AWS cloud.

The terraform AWS provider documentation can be found in the below link.

hashicorp/aws | Terraform Registry

The first need we will need to do is to create a user in AWS from IAM in order to create an access token for the deployment. By navigating in the IAM tab you can go and create a new user for terraform. I gave this user the name terraform

Then by pressing the user you can go in the security credentials tab and create a new access key. Those will be needed in the terraform script later on.

When creating the user you must specify the permission policies to attach. This will allow the necessary actions on the infrastructure. As in the provided terraform script below I only create a new vpc I should use the least privilege principal and only provide the permissions that are required. As a result I do not provide administrator access but only AmazonVPCFullAccess for this user. This build in policy rule allow full access on VPCs like creating, updating, deleting etc.

After those steps I will need to run my terraform script to create the resources I need. First you will need to initialize the terraform so that it downloads the providers stated in the files

terraform init

and the second step would be to apply the configuration

terraform apply

when you apply the configuration you will view what is created or deleted

Code:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region     = "eu-west-1"
  access_key = "KEY" // access key you generated for the user
  secret_key = "SECRET" // secret of the key
}

resource "aws_vpc" "vpc-test" {
  cidr_block = "10.10.0.0/16"


  tags = {
    Name = "ExampleAppServerInstance"
  }
}

When the deployment finishes you can find your vpc in your account.

Build infrastructure | Terraform | HashiCorp Developer

Youtube video:

Posted on 10 Comments

Pass variables values inside terraform modules

In this article I will explain two different ways to pass variables values inside terraform modules. Modules let you separate your code into small units and help the engineer structure its project better.

https://www.terraform.io/language/modules/syntax

Modules in terraform (terraform files) can be placed on folders and their location should be provided on the module directive. Lets say for example that you host a main.tf on your current working directory which should call two modules. The first module would be a storage account and the second would be an app service. Your main.tf file should look like below.

module "app_service_test" {
  source                  = "./modules/appservice"
}
module "storage_account_test" {
  source                  = "./modules/storageaccount"
}

However you want to pass some variables inside the child modules for example the resource group name, location etc.

First method – Define variables on root module

The first way you can pass variables inside your child modules would be to define a variables.tf file on your main module and a terraform.tfvars. Then you should also define a variables.tf file inside each module and contain the definition of each module.

terraform.tfvars (root module)

app_service_plan_name   = "ger-plan-test"
app_service_name        = "ger-site-test"
resource_group_name     = "geralexgr-terraform-rg"
resource_group_location = "West Europe"
storage_account_name    = "geralexgrsgv2"

variables.tf (root module)

variable "storage_account_name" {
  type        = string
  description = "Storage account name"
  default     = ""
}

variable "resource_group_name" {
  type        = string
  description = "RG name in Azure"
}

variable "app_service_plan_name" {
  type        = string
  description = "App Service Plan name in Azure"
}

variable "app_service_name" {
  type        = string
  description = "Name for the app service"
}

variable "resource_group_location" {
  type        = string
  description = "RG location in Azure"
}

variables.tf (storageaccount module)

variable "storage_account_name" {
    type        = string
    description = "Storage account name"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}

variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

variables.tf (appservice module)

variable "app_service_plan_name" {
    type        = string
    description = "App Service Plan name in Azure"
}

variable "app_service_name" {
    type = string
    description = "Name for the app service"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}

variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

Then on your main module you should call your child modules as follows:

module "app_service_test" {
  source                  = "./modules/appservice"
  app_service_plan_name   = var.app_service_plan_name
  app_service_name        = var.app_service_name
  resource_group_name     = var.resource_group_name
  resource_group_location = var.resource_group_location
}

module "storage_account_test" {
  source                  = "./modules/storageaccount"
  storage_account_name    = var.storage_account_name
  resource_group_name     = var.resource_group_name
  resource_group_location = var.resource_group_location
}

Second method – Pass variables on module call

With this approach you do not need to have variables.tf file and terraform.tfvars file inside your root module. You only need the definition as described above inside appservice and storageaccount folders (variables.tf).

variables.tf (appservice module)

variable "app_service_plan_name" {
    type        = string
    description = "App Service Plan name in Azure"
}

variable "app_service_name" {
    type = string
    description = "Name for the app service"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}

variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

variables.tf (storageaccount module)

variable "storage_account_name" {
    type        = string
    description = "Storage account name"
}
variable "resource_group_name" {
    type        = string
    description = "RG name in Azure"
}
variable "resource_group_location" {
    type        = string
    description = "RG location in Azure"
}

Then your main.tf file should be:

module "app_service_test" {
  source                  = "./modules/appservice"
  app_service_plan_name   = "ger-plan-test"
  app_service_name        = "ger-site-test"
  resource_group_location = "West Europe"
  resource_group_name     = "geralexgr-terraform-rg"
}

module "storage_account_test" {
  source                  = "./modules/storageaccount"
  storage_account_name    = "geralexgrsgv2"
  resource_group_name     = "geralexgr-terraform-rg"
  resource_group_location = "West Europe"
}
Posted on Leave a comment

Add log analytics workspace to Azure app service – Terraform

Most times you will need to store logs for your azure resources in order to troubleshoot when things do not work as expected. Diagnostic settings for an app service can be enabled from the pane under Monitoring.

Then you should configure the diagnostic settings that will point which logs should be forwarded.

You can choose from the available categories shown below.

Lets now discover how we can enable diagnostic settings for an app service using terraform.

Create a file for example diagnostic_settings.tf and apply. The below configuration will enable all diagnostic settings categories.

resource "azurerm_monitor_diagnostic_setting" "diag_settings" {
  name               = "diag-settings"
  target_resource_id = azurerm_windows_web_app.app_service1.id
  log_analytics_workspace_id = local.log_analytics_workspace_id
  
  log {
    category = "AppServiceHTTPLogs"
    enabled  = true

    retention_policy {
      enabled = false
    }
  }

    log {
    category = "AppServiceConsoleLogs"
    enabled  = true

    retention_policy {
      enabled = false
    }
  }

    log {
    category = "AppServiceAppLogs"
    enabled  = true

    retention_policy {
      enabled = false
    }
  }

    log {
    category = "AppServiceAuditLogs"
    enabled  = true

    retention_policy {
      enabled = false
    }
  }

    log {
    category = "AppServiceIPSecAuditLogs"
    enabled  = true

    retention_policy {
      enabled = false
    }
  }

     log {
    category = "AppServicePlatformLogs"
    enabled  = true

    retention_policy {
      enabled = false
    }
  }

  metric {
    category = "AllMetrics"

    retention_policy {
      enabled = false
      days = 30
    }
  }

}

You can also perform the same using a loop and a local variable in order to minimize code and make it more readable.

Assign a new variable inside your locals.tf file.

 log_analytics_log_categories     = ["AppServiceHTTPLogs", "AppServiceConsoleLogs","AppServiceAppLogs","AppServiceAuditLogs","AppServiceIPSecAuditLogs","AppServicePlatformLogs"]

Then perform terraform apply.

resource "azurerm_monitor_diagnostic_setting" "diag_settings" {
  name               = "diag-rule"
  target_resource_id = azurerm_windows_web_app.app_service1.id
  log_analytics_workspace_id = local.log_analytics_workspace_id
  
  dynamic "log" {
    iterator = entry
    for_each = local.log_analytics_log_categories
    content {
        category = entry.value
        enabled  = true

        retention_policy {
      enabled = false
        }
    }
   
  }

  metric {
    category = "AllMetrics"

    retention_policy {
      enabled = false
      days = 30
    }
  }

}

After applying terraform all the settings will be enabled.

Posted on 1 Comment

Enable Diagnostic settings for Azure App service using terraform loop

Imagine that you want to enable diagnostic settings for multiple app services on Azure using terraform. The required options can be located under Monitoring tab.

A appropriate rule option should be created to indicate where the logs should be sent. 

The available categories can be located below and I will instruct terraform to enable them all.

In order to accomplish that through terraform I used a loop. The depends_on keyword is used because firstly the app services should be created and then the diagnostic settings for them. Create a file like app_diagnostics.tf and place it inside your terraform working directory.

resource "azurerm_monitor_diagnostic_setting" "diag_settings_app" {
  depends_on = [ azurerm_windows_web_app.app_service1,azurerm_windows_web_app.app_service2 ]
  count = length(local.app_service_ids)
  name               = "diag-rule"
  target_resource_id = local.app_service_ids[count.index]
  log_analytics_workspace_id = local.log_analytics_workspace_id
  
  dynamic "log" {
    iterator = entry
    for_each = local.log_analytics_log_categories
    content {
        category = entry.value
        enabled  = true

        retention_policy {
      enabled = false
        }
    }
   
  }

  metric {
    category = "AllMetrics"

    retention_policy {
      enabled = false
      days = 30
    }
  }

}

Inside locals.tf I have created a variable that holds the app services ids, the log analytics workspace ID on which the logs will be sent and also the categories which I want to enable on Diagnostics. As shown on the first screenshot all the categories are selected.

locals {

 log_analytics_workspace_id = "/subscriptions/.../geralexgr-logs" 
 log_analytics_log_categories     = ["AppServiceHTTPLogs", "AppServiceConsoleLogs","AppServiceAppLogs","AppServiceAuditLogs","AppServiceIPSecAuditLogs","AppServicePlatformLogs"]

app_service_ids = [azurerm_windows_web_app.app_service1.id,azurerm_windows_web_app.app_service2.id]
}

As a result the loop will enable for every app service you add on app_service_ids each Diagnostic category placed on log_analytics_log_categories variable.