The Perfect Duo? (Testing Azure and Terraform Capabilities)
Tags: terraform, azure, devops
Published: 2023-04-11 15:19:07

What better way to learn a new skill than to practice? Terraform is easily the best IaC application. Using it, I've created and deployed Azure resources like Kubernetes clusters, Active Directory and Security groups, CI/CD solutions using Azure DevOps, and Virtual Machine instances. It has been super easy to learn!

Terraform is similar to Azure Resource Management (ARM) templates, which I am familiar with and have completed a couple projects using it. However, Terraform is useful as it allows you to configure infrastructure across multiple cloud platforms. Most companies don't just use one cloud providers as one might have a resource that better than the other and vice versa. For example, Azure Active Directory is the arguably the best solution for identity and access management while AWS can be a better solution for IaaS. This is where Terraform comes in handy!

## General Steps 

Creating resources and solutions using Terraform is pretty straightforward. Each solution was deployed using these steps.

1.Create the respective providers, main, variables, outputs files, and service principal credentials.

 * providers: specifies cloud provider used 
 * main: specifies the parameters for my resources  
 * variables: specifies the variables for our parameters like the resource group location. These are parameter values that start with *var* in my main file. 
 * outputs: specifies output variables 
 * service principal credentials: specifies my service principal app id and password as I choose to use a least privilege model to protect my subscriptions and its resources

2.Using Azure CloudShell, I created and applied my Terraform execution plan. 

```
terraform plan -out main.tfplan
terraform apply main.tfplan

```

3.Test the results! 

*Note: code are only samples of what was used and resources have additional parameters that were included in my Terraform files. You can find the complete code in my Github repo.* 

## End to End Governance (Azure DevOps and Terraform)

In this project, designed an end to end governance solution for a scenario where a construction company called Kay Inc is working on the construction of a new hospital.  

Kay Inc has various departments: Structural Design, Project Management, and IT (or superadmins). Each department has:
* a team that develops solutions to make some aspects of the department more efficient. For example, a function application that automatically uploads published drawings from the design team to a Cosmos DB to be used and tracked by the project management dept. 
* an admin team that creates and manages management groups, subscriptions, RBAC, Policies, etc.

**Active Directory and IAM:** I created three Active Directory groups for each department: a group for the entire department and two separate groups for the developer team with DevOps and ARM Contributor roles and admin team with ARM Owner and DevOps Project Administrator roles. The IT department only has one AD group with "superadmin" privileges.

The construction project is broken down into 5 projects groups: one for each department, one for the entire company, and a collaborative space. 

### To implement my solution, I...

I created a DevOps Organization and PAT to configure the environment then created the DevOps projects, AD group assignments, and service connections for the company. 
 


**1. Configuring the AD groups** 
```
resource "azuread_group" "groups" {
  for_each                = var.groups
  display_name            = "kayinc-${each.value}-${local.suffix}"
  prevent_duplicate_names = true
  security_enabled        = true
}

```
**2. Configuring the DevOps projects** and enabling their necessary features 

``` 
resource "azuredevops_project" "team_projects" {
  for_each        = var.projects
  name            = each.value.name
  description     = each.value.description
  visibility      = "private"
  version_control = "Git"

  features = {
    repositories = "enabled"
    pipelines    = "enabled"
    artifacts    = "disabled"
    boards       = "disabled"
    testplans    = "disabled"
  }
}
```
**3. Configuring Security Group Assignments** for each project with their assigned permissions and dependencies

```
module "ado_team_permissions" {
  for_each       = var.projects
  source         = "./modules/azure-devops-permissions"
  ado_project_id = azuredevops_project.team_projects["${each.value.team}"].id
  team_aad_id    = azuread_group.groups["${each.value.team}_devs"].id   # Receives 'Contributor' Permissions
  admin_aad_id   = azuread_group.groups["${each.value.team}_admins"].id # Receives 'Project Administrator' Permissions

  depends_on = [
    azuread_group.groups,
    azuredevops_project.team_projects
  ]
}
```


## Creating a Kubernetes cluster using AKS

In this task, I created a AKS cluster and configured Container Insights to manage my Kubernetes environment using Terraform. 

**1. Create an AKS cluster** specifying node pool parameters including the number of nodes 
  
```
resource "azurerm_kubernetes_cluster" "k8s" {
  location            = azurerm_resource_group.rg.location
  name                = var.cluster_name
  resource_group_name = azurerm_resource_group.rg.name
  dns_prefix          = var.dns_prefix
  tags                = {
    Environment = "Development"
  }

default_node_pool {
    name       = "agentpool"
    vm_size    = "Standard_D2_v2"
    node_count = var.agent_count
  }

```

**2. Configure Container Insights** to monitor the health and performance of my cluster

```
resource "azurerm_log_analytics_solution" "test" {
  location              = azurerm_log_analytics_workspace.test.location
  resource_group_name   = azurerm_resource_group.rg.name
  solution_name         = "ContainerInsights"
  workspace_name        = azurerm_log_analytics_workspace.test.name
  workspace_resource_id = azurerm_log_analytics_workspace.test.id

  plan {
    product   = "OMSGallery/ContainerInsights"
    publisher = "Microsoft"
  }
}
```



## Virtual Machine Scale Sets from a custom Packer image

Azure Virtual Machine Scale Sets automate the deployment of Virtual Machine instances based on specified parameters to decrease latency and increase availability. 

**1. Configuring the VM image** by creating a resource group, service principal, and the Packer template file to a Packer image.

```
az group create -n kayPackerimages -l eastus

az ad sp create-for-rbac --role Contributor --scopes /subscriptions/kayssub1234 --query "{client_id: appId, client_secret: password, tenant_id: tenant }"

packer build ubuntu.json
```
Packer image file is a json file that include my Azure credentials, os type, image sku and location, etc. 
 
**2. Create a Virtual Network, subnet, and loadbalancer**
 
```
resource "azurerm_virtual_network" "vmss" {
  name                = "vmss-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = var.location
  resource_group_name = azurerm_resource_group.vmss.name
  tags = var.tags
}

resource "azurerm_subnet" "vmss" {
  name                 = "vmss-subnet"
  resource_group_name  = azurerm_resource_group.vmss.name
  virtual_network_name = azurerm_virtual_network.vmss.name
  address_prefixes       = ["10.0.2.0/24"]
}

resource "azurerm_lb" "vmss" {
  name                = "vmss-lb"
  location            = var.location
  resource_group_name = azurerm_resource_group.vmss.name

  frontend_ip_configuration {
    name                 = "PublicIPAddress"
    public_ip_address_id = azurerm_public_ip.vmss.id
  }

  tags = var.tags
}
```

**2. Create my virtual machine** using the Packer image  

```
data "azurerm_image" "image" {
  name                = var.packer_image_name
  resource_group_name = data.azurerm_resource_group.image.name
}
```

Of course I did not start with these more complicated tasks. I first practiced configuring simple solutions like:
* an Azure CosmosDB
* Azure Virtual Machines 
* resource groups