Reputation: 325
I'm currently scripting some new Azure infrastructure in Terraform, and doing so using nested modules in order to make the management and deployment of the different sections of our infrastructure nice and confined.
I have created a module called global
that contains several shared resources (pretty much just azure resource groups and permissions) along with some azure ad lookups and currently client config. Having these in a central module seems to make sense to avoid code reuse and ensuring that they are handled consistently throughout the project.
However, I've noticed that when I run terraform destroy
from any module, all of the objects in the global module are marked to be destroyed. Is there a way to exclude the nested module from the destruction process?
Should I actually be placing the creation of the resources (which are exclusively resource groups and permissions applied to those resource groups) in my global module in a seperate, non-nested module, but then use a data module for my nested global module to look up their values etc?
Example code for the global module:-
data "azurerm_client_config" "current" {}
data "azurerm_subscription" "subscription_current" {}
data "azuread_group" "dba" {
name = "DBAs"
}
data "azuread_group" "bi-developer" {
name = "BIDevelopers"
}
## local variables
locals {
subscription_name = substr(lower("${data.azurerm_subscription.subscription_current.display_name}"),0,4)
tenant_id = data.azurerm_subscription.subscription_current.tenant_id
}
## Create resource group and add permission
resource "azurerm_resource_group" "data" {
name = "data"
location = var.location
tags = {
owner = "Data"
environment = local.subscription_name
}
}
resource "azurerm_role_assignment" "DBA_Data_Permission" {
scope = azurerm_resource_group.data.id
role_definition_name = var.permission_level
principal_id = data.azuread_group.dba.id
}
resource "azurerm_resource_group" "key-vault" {
name = "key-vault"
location = var.location
tags = {
owner = "techops"
environment = local.subscription_name
}
}
## Output Locals
output "subscription_name" {
value = local.subscription_name
}
output "tenant_id" {
value = local.tenant_id
}
output "object_id" {
value = data.azurerm_client_config.current.object_id
}
## Output Resource Groups
output "rg_data_id" {
value = azurerm_resource_group.data.id
}
output "rg_data_name" {
value = azurerm_resource_group.data.name
}
output "rg_key-vault_id" {
value = azurerm_resource_group.key-vault.id
}
output "rg_key-vault_name" {
value = azurerm_resource_group.key-vault.name
}
## Output Azure AD lookups
output "aad_dba_id" {
value = data.azuread_group.dba.id
}
output "aad_dba_name" {
value = data.azuread_group.dba.name
}
output "aad_bi-developer_id" {
value = data.azuread_group.bi-developer.id
}
output "aad_data-science_id" {
value = data.azuread_group.data-science.id
}
And example of the usage in one of my nested modules, to create database resources in this instance:-
module "global" {
source = "../global"
permission_level = var.permission_level
location = var.location
prefix = var.prefix
}
resource "azurerm_sql_server" "dwh" {
name = "${var.prefix}-dwh-${module.global.subscription_name}"
resource_group_name = module.global.rg_data_name
location = var.location
version = "12.0"
administrator_login = var.sql_login_name
administrator_login_password = var.sql_login_password
tags = {
environment = module.global.subscription_name
owner = "Data"
subscription = "${module.global.subscription_name}"
}
}
resource "azurerm_sql_active_directory_administrator" "dwh" {
server_name = azurerm_sql_server.dwh.name
resource_group_name = module.global.rg_data_name
login = module.global.aad_dba_name
tenant_id = module.global.tenant_id
object_id = module.global.aad_dba_id
}
resource "azurerm_mssql_elasticpool" "dwh-ep" {
name = "${var.prefix}-dwh-${module.global.subscription_name}"
resource_group_name = module.global.rg_data_name
location = var.location
server_name = azurerm_sql_server.dwh.name
max_size_gb = 1000
sku {
name = "GP_Gen5"
tier = "GeneralPurpose"
family = "Gen5"
capacity = 6
}
per_database_settings {
min_capacity = 0.25
max_capacity = 4
}
depends_on = [azurerm_sql_server.dwh,azurerm_sql_active_directory_administrator.dwh]
}
Then in a seperate module the following code to create a key vault, reusing some of the output from the global module:-
module "global" {
source = "../global"
permission_level = var.permission_level
location = var.location
prefix = var.prefix
}
resource "azurerm_key_vault" "data" {
name = "${var.prefix}-data-${module.global.subscription_name}"
location = var.location
resource_group_name = "${module.global.rg_key-vault_name}"
enabled_for_disk_encryption = true
tenant_id = module.global.tenant_id
sku_name = "standard"
tags = {
environment = module.global.subscription_name
owner = "data"
}
}
resource "azurerm_key_vault_access_policy" "data-bi-developer" {
key_vault_id = "${azurerm_key_vault.data.id}"
tenant_id = module.global.tenant_id
object_id = module.global.aad_bi-developer_id
certificate_permissions = ["get","list"]
key_permissions = ["get", "list"]
secret_permissions = ["get", "list"]
}
resource "azurerm_key_vault_access_policy" "data-admin" {
key_vault_id = "${azurerm_key_vault.data.id}"
tenant_id = module.global.tenant_id
object_id = "${module.global.object_id}"
certificate_permissions = [
"create",
"delete",
"deleteissuers",
"get",
"getissuers",
"import",
"list",
"listissuers",
"managecontacts",
"manageissuers",
"setissuers",
"update",
]
key_permissions = [
"backup",
"create",
"decrypt",
"delete",
"encrypt",
"get",
"import",
"list",
"purge",
"recover",
"restore",
"sign",
"unwrapKey",
"update",
"verify",
"wrapKey",
]
secret_permissions = [
"backup",
"delete",
"get",
"list",
"purge",
"recover",
"restore",
"set",
]
}
Upvotes: 1
Views: 616
Reputation: 325
OK, managed to work this out, essentially splitting the global module up into three modules; one to hold the resources that are not being created at all through terraform as lookups (e.g. subscription, azure ad etc), one to create the resource groups and apply permissions, and then one that is purely a data module to read the resource groups for other modules.
Upvotes: 1