TerraformでセットアップされたAzureのリソースをTerraformモジュールに移動してみました。
普通にvariableをInputするようなところは割愛して、リソースによって何か特徴のあるところをいくつか例を紹介したいと思います。
Storage Account
resource "azurerm_storage_account" "azfiles" {
name = "${var.sa_name}"
.
.
.
}
resource "azurerm_storage_share" "share" {
for_each = var.shares
name = each.key
storage_account_name = azurerm_storage_account.azfiles.name
quota = each.value
depends_on = [
azurerm_storage_account.azfiles
]
}
variable "shares" {
type = map(string)
}
Azure FileのShareを複数作る場合はvariableでMapを作りそこでKey,ValueでShareの名前とQuotaのサイズを設定します。Modulesでは以下のように設定します。
module "storage" {
source = "modules/sa/azfiles"
sa_name = "${local.sa_name}"
.
.
.
shares = {
share1 = 512
share2 = 1024
}
}
これでQuotaが512GBのshare1と1024GBのshare2ができます。
Containers
Azure Blob Storageで複数のContainersをセットアップする場合は、VariablesでListを使用します。
resource "azurerm_storage_account" "blob_nfs" {
name = "${var.name}"
resource_group_name = "${var.resource_group_name}"
.
.
}
resource "azurerm_storage_container" "container" {
for_each = toset(var.containers)
name = each.value
storage_account_name = azurerm_storage_account.blob_nfs.name
container_access_type = "private"
}
variable "containers" {
type = list(string)
}
こんな感じでListのVariablesを設定して、Modulesでは以下のように呼び出します。
module "nfs" {
source = "modules/modules/blob_nfs"
name = "mystorage"
.
.
containers = ["container1","container2"]
}
とするとmystorage
にcontainer1
、container2
が作成されます。
Endpoint
リソースによってはPrivate Endpointが必要な場合もあります。
resource "azurerm_private_endpoint" "endpoint" {
count = var.pe_name == null ? 0 : 1
name = "${var.pe_name}"
location = "${var.location}"
resource_group_name = "${var.resource_group_name}"
.
.
}
とするとpe_name
が存在する場合のだけ作成して、ない場合はendpointを作らないようにもできます。
WAF
resource "azurerm_web_application_firewall_policy" "policy" {
name = "${var.policy_name}"
resource_group_name = "${var.resource_group_name}"
location = "${var.location}"
.
.
.
custom_rules {
name = "${var.customrule_name}"
priority = var.customrule_priority
rule_type = "${var.customrule_type}"
dynamic match_conditions {
for_each = var.match_conditions
content {
match_variables {
variable_name = "${match_conditions.value.variable_name}"
selector = "${match_conditions.value.selector}"
}
operator = "${match_conditions.value.operator}"
negation_condition = false
match_values = ["${match_conditions.value.match_values}"]
}
}
action = "${var.customrule_action}"
}
custom_rules
自身も複数ある場合もありますが、custom_rules
のなかのmatch_variables
が複数ある場合の例です。dynamic match_conditions
とすることによってfor_each
をattributeで展開しています。
これはdynamic
を使用してcontent{}
の中でmatch_conditions.value.variable_name
などとすることでVariableの値を取っています。
variable "match_conditions" {
type = list(object({
variable_name = string
selector = optional(string, "")
operator = string
match_values = string
}))
}
Variable自体はこのように設定すればObjectのListとして利用できます。
match_conditions = [
{
variable_name = "RequestUri"
operator = "Contains"
match_values = "/test/abc"
},
{
variable_name = "RemoteAddr"
operator = "IPMatch"
match_values = "123.45.67.89"
}
とかすると特定のIPアドレスから特定のPathへのアクセスを許可するルールができます。
また、WAFのルールで例外を設けるときなどvariableでlistの中にlistを作ります。
managed_rules {
managed_rule_set {
type = "OWASP"
version = "3.2"
dynamic rule_group_override {
for_each = var.rule_group_override
content{
rule_group_name = "${rule_group_override.value.rule_group_name}"
dynamic rule {
for_each = rule_group_override.value.rule_ids
content {
id = "${rule.value}"
enabled = false
}
}
}
}
}
}
variable "rule_group_override" {
type = list(object({
rule_group_name = string
rule_ids = list(string)
}))
}
モジュール側では以下のように設定すると、指定したWAFルールに例外が設定されます。
rule_group_override = [
{
rule_group_name = "REQUEST-920-PROTOCOL-ENFORCEMENT"
rule_ids = ["942260","942430"]
},
{
rule_group_name = "REQUEST-941-APPLICATION-ATTACK-XSS"
rule_ids = ["942110","942430"]
}
]
その他
モジュールにしても、複数のtfファイルで管理することもできます。
modules
├── appgw
├── main.tf
├── variables.tf
├── region1.tf
├── region2.tf
例えば、異なるリージョンでの差分が多い場合、変数で対応するより別のファイルで設定することも可能です。
resource "azurerm_application_gateway" "region1" {
count = var.location == "region1" ? 1 : 0
name = "${var.appgw_name}"
.
.
resource "azurerm_application_gateway" "region2" {
count = var.location == "region2" ? 1 : 0
name = "${var.appgw_name}"
.
.
module "appgw" {
source = "modules/appgw"
location = "region1"
}
このようにすると、var.location
変数がregion1
の場合だけazurerm_application_gateway.region1
が作成されるようにすることも可能です。ただし、このように条件を入れてリソースを作成するとazurerm_application_gateway.region1[0]
と配列になって作成されます。
main.tf
にはどちらのリージョンでも共通に作られるリソースを入れておくと、まとめて管理できます。
既存のリソースをモジュールに移動
すでにリソースをTerraformで作成している場合は、moved
を使うと、Stateをモジュールに移動できます。
moved {
from = azurerm_kubernetes_cluster.aks
to = module.aks_qa.azurerm_kubernetes_cluster.aks
}
まとめ
このようにmoved
を使って既存のリソースをモジュールに移動できます。
この場合、リソース自体は何も変更行われず、Terraformのステートだけが、モジュールに移動します。
terraform state list
とすると、リソースがモジュールに移動していることが確認できます。
terraform state list
module.storage.azurerm_storage_account.azfiles
module.nfs.azurerm_storage_account.blob_nfs
...
...