diff --git a/README.md b/README.md new file mode 100644 index 0000000..43ec45b --- /dev/null +++ b/README.md @@ -0,0 +1,127 @@ +# Ncloud ACG Terraform module + +## Module Usage + +You can manage ACGs using ACG module. But you can also manage ACGs within VPC module ([terraform-ncloud-modules/vpc/ncloud](https://registry.terraform.io/modules/terraform-ncloud-modules/vpc/ncloud)). The latter way is a little easier. + +### `main.tf` + +#### The ACG module support only multiple ACGs. +``` hcl +module "access_control_groups" { + source = "./terraform-ncloud-acg" + + // Required + access_control_groups = [for acg in var.access_control_groups : + { + name = acg.name + description = acg.description + vpc_id = module.vpc.vpc.id // see "vpc_id reference scenario" below + inbound_rules = acg.inbound_rules + outbound_rules = acg.outbound_rules + } + ] +} +``` + +### vpc_id reference scenario + +with single VPC module (terraform-ncloud-modules/vpc/ncloud) +``` hcl +//variable +# vpc_name = "vpc-sample" (comment out) + +//module +vpc_id = module.vpc.vpc.id +``` + +with multiple VPC module (terraform-ncloud-modules/vpc/ncloud) +``` hcl +//variable +vpc_name = "vpc-sample" + +//module +vpc_id = module.vpcs[acg.vpc_name].vpc.id +``` + +or you can just type vpc_id manually +``` hcl +//variable +# vpc_name = "vpc-sample" (comment out) +vpc_id = "25322" (add new) + +//module +vpc_id = acg.vpc_id +``` + + + +## Variable Declaration + +### `terraform.tfvars` +You can create `terraform.tfvars` and refer to the sample below to write variable specifications. +``` hcl + +// Optional, Allow multiple +// You can manage ACG within the VPC module (terraform-ncloud-modules/vpc/ncloud) +// The order of writing inbound_rules & outbound_rules is as follows. +// [protocol, ip_block|source_access_control_group, port_range, description] +access_control_groups = [ + { + name = string + description = string + vpc_name = string // see "vpc_id reference scenario" above + inbound_rules = [ + [ + string, // TCP | UDP | ICMP + string, // CIDR | AccessControlGroupName + integer|string, // PortNumber(22) | PortRange(1-65535) + string + ] + ] + outbound_rules = [] // same as above + } +] + +``` + + +#### Example +``` hcl +access_control_groups = [ + { + name = "acg-sample-public" + description = "ACG for public servers" + vpc_name = "vpc-sample" + inbound_rules = [ + ["TCP", "0.0.0.0/0", 22, "SSH allow form any"] + ] + outbound_rules = [ + ["TCP", "0.0.0.0/0", "1-65535", "All allow to any"], + ["UDP", "0.0.0.0/0", "1-65535", "All allow to any"] + ] + }, + { + name = "acg-sample-private" + description = "ACG for private servers" + vpc_name = "vpc-sample" + inbound_rules = [ + ["TCP", "acg-sample-public", 22, "SSH allow form acg-sample-public"] + ] + outbound_rules = [ + ["TCP", "0.0.0.0/0", "1-65535", "All allow to any"], + ["UDP", "0.0.0.0/0", "1-65535", "All allow to any"] + ] + } +] + + +``` + +### `variable.tf` +You also need to create `variable.tf` to enable `terraform.tfvars` +``` hcl +variable "access_control_groups" {} +``` + + diff --git a/init.tf b/init.tf new file mode 100644 index 0000000..8686001 --- /dev/null +++ b/init.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + ncloud = { + source = "NaverCloudPlatform/ncloud" + } + } +} \ No newline at end of file diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..12d6adf --- /dev/null +++ b/main.tf @@ -0,0 +1,68 @@ +resource "ncloud_access_control_group" "acgs" { + for_each = { for acg in var.access_control_groups: acg.name => acg } + + name = each.value.name + description = each.value.description + vpc_no = each.value.vpc_id +} + +locals { + acgs = { for acg_key, acg_value in ncloud_access_control_group.acgs : acg_key => + merge(acg_value, { + inbound_rules = [for rule in var.access_control_groups[index(var.access_control_groups.*.name, acg_key)].inbound_rules : + { + protocol = rule[0] + ip_block = (can(regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}\\/[0-9]{1,2}$", rule[1])) + ? rule[1] : null + ) + source_access_control_group_no = (can(regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}\\/[0-9]{1,2}$", rule[1])) + ? null : ncloud_access_control_group.acgs[rule[1]].id + ) + port_range = rule[2] + description = rule[3] + } + ] + outbound_rules = [for rule in var.access_control_groups[index(var.access_control_groups.*.name, acg_key)].outbound_rules : + { + protocol = rule[0] + ip_block = (can(regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}\\/[0-9]{1,2}$", rule[1])) + ? rule[1] : null + ) + source_access_control_group_no = (can(regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}\\/[0-9]{1,2}$", rule[1])) + ? null : ncloud_access_control_group.acgs[rule[1]].id + ) + port_range = rule[2] + description = rule[3] + } + ] + }) + } +} + +resource "ncloud_access_control_group_rule" "acg_rules" { + for_each = local.acgs + + access_control_group_no = each.value.id + + dynamic "inbound" { + for_each = each.value.inbound_rules + content { + protocol = inbound.value.protocol + port_range = inbound.value.port_range + ip_block = inbound.value.ip_block + source_access_control_group_no = inbound.value.source_access_control_group_no + description = inbound.value.description + } + } + + dynamic "outbound" { + for_each = each.value.outbound_rules + content { + protocol = outbound.value.protocol + port_range = outbound.value.port_range + ip_block = outbound.value.ip_block + source_access_control_group_no = outbound.value.source_access_control_group_no + description = outbound.value.description + } + } +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..9ac30d5 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,3 @@ +output "acgs" { + value = ncloud_access_control_group.acgs +} \ No newline at end of file diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..f27374d --- /dev/null +++ b/variables.tf @@ -0,0 +1,4 @@ +variable "access_control_groups" { + description = "(Required) See the description in the readme" + type = list(any) +} \ No newline at end of file