Access Management using Terraform and Microsoft Graph API Provider – Creating Break the glass account

Last week Hashicorp released an updated version of the Azure AD Provider which is built upon the Microsoft Graph API (and will be moving away from the AzureAD API which will be deprecated by Microsoft summer next year.

Therefore, I wanted to dive a bit into the Azure AD Provider and how you can use it to handle for instance access management to Azure AD Subscriptions, to combine the Azure AD and Azure provider to create groups/users/service principals and assign them to a subscription.

NOTE: Hashicorp has also mentioned that using the new Graph API will also open for other possibilities when it comes to automation of other resources in Azure such as Conditional Access, Security settings, and other settings within Azure.

Using Terraform against Azure AD and Azure Resource Manager can easily be managed using a single set of configuration files. So as an example, I have a backend file that defines my providers and information about where to connect.

NOTE: Both providers also support MSI meaning that you can use a managed VM in Azure which has an managed identity that can be used to connect to Azure AD and Azure Resource Manager. You can read more about it here –> Authenticating via Managed Identity | Guides | hashicorp/azuread | Terraform Registry

backend.tf (This just adds the latest version of Azure AD and Azure RM (also defines the random provider to create a random password for the BTG accounts) which can then be pushed to Vault for instance. 

terraform {
  required_providers {
    azuread = {
      source = "hashicorp/azuread"
      version = "1.5.0"
    }
    azurerm = {
      source = "hashicorp/azurerm"
    }
  }
}
provider "azuread" {
  tenant_id     = var.tenant_id
  client_secret = var.client_secret
  client_id     = var.client_id
}

provider "azurerm" {
  features {}
  tenant_id       = var.tenant_id
  subscription_id = var.subscription_id
  client_secret   = var.client_secret
  client_id       = var.client_id
}

provider "random" {}
resources.tf (will be used to create Azure AD Groups, some members and add group memberships to a subscription) This will be used to create break the glass accounts, add it to a group, then add the group to the subscription. 
## Create Azure AD Group used for Read Access ##

resource "azuread_group" "aadgroup-btg" {
  display_name = "aadbtg"
}
data "azuread_group" "data-btg" {
  display_name     = "aaadbtg"
  security_enabled = true
  depends_on       = [azuread_group.aadgroup-btg]
}

## Create Service Principals for access ## 
resource "random_password" "password" {
  length           = 32
  min_upper        = 4
  min_numeric      = 4
  special          = true
  override_special = "_%@"
}
resource "azuread_user" "aaabtg01" {
  user_principal_name = "[email protected]"
  display_name        = "Break The Glass"
  mail_nickname       = "aaabtg01"
  password            = "random_password.password.result"
}

data "azuread_user" "daabtg01" {
  user_principal_name = "[email protected]"
  depends_on          = [azuread_user.aaabtg01]
}
resource "azuread_group_member" "example" {
  group_object_id  = azuread_group.aadgroup-btg.id
  member_object_id = data.azuread_user.daabtg01.id
}
resource "azurerm_role_assignment" "example" {
  scope                = data.azurerm_subscription.primary.id
  role_definition_name = "Contributer"
  principal_id         = data.azuread_group.data-btg.object_id
  depends_on           = [data.azuread_group.data-btg]
}
The only thing missing now is the ability to define exclusion policies for the conditional access rules for instance. We can also define monitoring rules for the usage of these BTG accounts directly using Terraform as well to get alerted if someone is trying to use the BTG accounts.
This is referencing a Log Analytics workspace with Sentinel to define the Analytics Query.
resource "azurerm_resource_group" "example-ra" {
  name     = "example-resources2"
  location = "West Europe"
}

resource "azurerm_log_analytics_workspace" "example" {
  name                = "example-workspace"
  location            = azurerm_resource_group.example-ra.location
  resource_group_name = azurerm_resource_group.example-ra.name
  sku                 = "pergb2018"
}

resource "azurerm_log_analytics_solution" "la_sentinel" {
  solution_name         = "SecurityInsights"
  location              = azurerm_resource_group.example-ra.location
  resource_group_name   = azurerm_resource_group.example-ra.name
  workspace_resource_id = azurerm_log_analytics_workspace.example.id
  workspace_name        = azurerm_log_analytics_workspace.example.name
  plan {
    publisher = "Microsoft"
    product   = "OMSGallery/SecurityInsights"
  }
}
resource "azurerm_sentinel_alert_rule_scheduled" "example3" {
  name                       = "example"
  log_analytics_workspace_id = azurerm_log_analytics_solution.la_sentinel.workspace_resource_id
  display_name               = "example"
  severity                   = "High"
  tactics                    = ["InitialAccess"]
  query                      = <<QUERY
SigninLogs
| where UserPrincipalName == "[email protected]
| where Status.errorCode == 0
| extend AccountCustomEntity = Identity
| extend IPCustomEntity = IPAddress
| extend HostCustomEntity = SourceSystem
QUERY
}

Eureka!

 

 

 

 

 

 

 

 

 

 

Leave a Reply

Scroll to Top