From 2dc54adf488d825c7dc243efb59e20c27824be32 Mon Sep 17 00:00:00 2001 From: Byungjin Park Date: Thu, 10 Nov 2022 01:26:21 +0900 Subject: [PATCH 1/2] Add fms-dns-firewall-policy module --- .github/labeler.yaml | 2 + .github/labels.yaml | 4 +- modules/fms-dns-firewall-policy/README.md | 62 +++++++ modules/fms-dns-firewall-policy/main.tf | 92 +++++++++ modules/fms-dns-firewall-policy/outputs.tf | 43 +++++ .../fms-dns-firewall-policy/resource-group.tf | 31 ++++ modules/fms-dns-firewall-policy/variables.tf | 175 ++++++++++++++++++ modules/fms-dns-firewall-policy/versions.tf | 10 + 8 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 modules/fms-dns-firewall-policy/README.md create mode 100644 modules/fms-dns-firewall-policy/main.tf create mode 100644 modules/fms-dns-firewall-policy/outputs.tf create mode 100644 modules/fms-dns-firewall-policy/resource-group.tf create mode 100644 modules/fms-dns-firewall-policy/variables.tf create mode 100644 modules/fms-dns-firewall-policy/versions.tf diff --git a/.github/labeler.yaml b/.github/labeler.yaml index 527a33d..f1070a8 100644 --- a/.github/labeler.yaml +++ b/.github/labeler.yaml @@ -5,5 +5,7 @@ - modules/dns-firewall-rule-group/**/* ":floppy_disk: dns-firewall": - modules/dns-firewall/**/* +":floppy_disk: fms-dns-firewall-policy": +- modules/fms-dns-firewall-policy/**/* ":floppy_disk: network-firewall": - modules/network-firewall/**/* diff --git a/.github/labels.yaml b/.github/labels.yaml index 7222b50..728850f 100644 --- a/.github/labels.yaml +++ b/.github/labels.yaml @@ -13,7 +13,6 @@ - color: "0e8a16" description: "Extra attention is needed." name: ":fire: help wanted" - # Cancel - color: "b60205" description: "This issue or pull request already exists." @@ -49,6 +48,9 @@ - color: "fbca04" description: "This issue or pull request is related to dns-firewall module." name: ":floppy_disk: dns-firewall" +- color: "fbca04" + description: "This issue or pull request is related to fms-dns-firewall-policy module." + name: ":floppy_disk: fms-dns-firewall-policy" - color: "fbca04" description: "This issue or pull request is related to network-firewall module." name: ":floppy_disk: network-firewall" diff --git a/modules/fms-dns-firewall-policy/README.md b/modules/fms-dns-firewall-policy/README.md new file mode 100644 index 0000000..f3b7d83 --- /dev/null +++ b/modules/fms-dns-firewall-policy/README.md @@ -0,0 +1,62 @@ +# fms-policy + +This module creates following resources. + +- `aws_fms_policy` + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 4.36 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 4.33.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | + +## Resources + +| Name | Type | +|------|------| +| [aws_fms_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/fms_policy) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | (Required) The friendly name of the AWS Firewall Manager Policy. | `string` | n/a | yes | +| [pre\_rule\_groups](#input\_pre\_rule\_groups) | (Required) A list of rule groups to process first. Each item of `pre_rule_groups` block as defined below.
(Required) `priority` - The setting that determines the processing order of the rule group among the rule groups that you associate with the specified VPC. DNS Firewall filters VPC traffic starting from the rule group with the lowest numeric priority setting. Valid values for `priority` are between 1 and 99.
(Required) `rule_group` - The ID of the firewall rule group. |
list(object({
priority = number
rule_group = string
}))
| n/a | yes | +| [auto\_remediation\_enabled](#input\_auto\_remediation\_enabled) | (Optional) Indicate if the policy should be automatically applied to new resources. Defaults to `false`. | `bool` | `false` | no | +| [cascade\_deletion\_enabled](#input\_cascade\_deletion\_enabled) | (Optional) Whether to cleanup resources which is managed by the policy on deletion. Defaults to `true`.

If `true`, the request performs cleanup according to the policy type.

For AWS WAF and Shield Advanced policies, the cleanup does the following:
- Deletes rule groups created by AWS Firewall Manager
- Removes web ACLs from in-scope resources
- Deletes web ACLs that contain no rules or rule groups

For security group policies, the cleanup does the following for each security group in the policy:
- Disassociates the security group from in-scope resources
- Deletes the security group if it was created through Firewall Manager and if it's no longer associated with any resources through another policy

After the cleanup, in-scope resources are no longer protected by web ACLs in this policy. Protection of out-of-scope resources remains unchanged. | `bool` | `true` | no | +| [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | +| [organization\_filter](#input\_organization\_filter) | (Optional) A filter configuration to decide protections on resources based on the accounts and organization units. `organization_filter` block as defined below.
(Optional) `type` - Whether to include or exclude resources that contain `accounts` or `organization_units` from protections by this policy. Valid values are `WHITELIST` and `BLACKLIST`.
(Optional) `accounts` - A list of AWS Organization member accounts that you want to include or to exclude for this AWS FMS Policy.
(Optional) `organization_units` - A list of AWS Organization Units that you want to include or to exclude for this AWS FMS Policy. |
object({
type = optional(string, "WHITELIST")
accounts = optional(set(string), [])
organization_units = optional(set(string), [])
})
| `{}` | no | +| [post\_rule\_groups](#input\_post\_rule\_groups) | (Optional) A list of rule groups to process first. Each item of `post_rule_groups` block as defined below.
(Required) `priority` - The setting that determines the processing order of the rule group among the rule groups that you associate with the specified VPC. DNS Firewall filters VPC traffic starting from the rule group with the lowest numeric priority setting. Valid values for `priority` are between 9901 and 10000.
(Required) `rule_group` - The ID of the firewall rule group. |
list(object({
priority = number
rule_group = string
}))
| `[]` | no | +| [resource\_cleanup\_on\_leave\_enabled](#input\_resource\_cleanup\_on\_leave\_enabled) | (Optional) Whether Firewall Manager will automatically remove protections from resources that leave the policy scope and clean up resources that Firewall Manager is managing for accounts when those accounts leave policy scope. For example, Firewall Manager will disassociate a Firewall Manager managed web ACL from a protected customer resource when the customer resource leaves policy scope. Defaults to `false`. This option is not available for Shield Advanced or AWS WAF Classic policies. | `bool` | `false` | no | +| [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | +| [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | +| [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | +| [resource\_tags\_filter](#input\_resource\_tags\_filter) | (Optional) A filter configuration to decide protections on resources based on the resource tags. `resourcee_tags_filter` block as defined below.
(Optional) `type` - Whether to include or exclude resources that contain `tags` from protections by this policy. Valid values are `WHITELIST` and `BLACKLIST`.
(Optional) `tags` - A map of resource tags to filter resources. |
object({
type = optional(string, "WHITELIST")
tags = optional(map(string), {})
})
| `{}` | no | +| [resource\_types](#input\_resource\_types) | (Optional) A list of resource types to protect. | `list(string)` |
[
"AWS::EC2::VPC"
]
| no | +| [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [arn](#output\_arn) | The ARN of the AWS Firewall Manager Policy. | +| [attributes](#output\_attributes) | A set of attributes that applied to the AWS Firewall Manager Policy. | +| [id](#output\_id) | The ID of the AWS Firewall Manager Policy. | +| [name](#output\_name) | The name of the AWS Firewall Manager Policy. | +| [policy](#output\_policy) | The configuration of this policy. | +| [scope](#output\_scope) | The configuration of this policy scope. | + diff --git a/modules/fms-dns-firewall-policy/main.tf b/modules/fms-dns-firewall-policy/main.tf new file mode 100644 index 0000000..3f1e36c --- /dev/null +++ b/modules/fms-dns-firewall-policy/main.tf @@ -0,0 +1,92 @@ +locals { + metadata = { + package = "terraform-aws-firewall" + version = trimspace(file("${path.module}/../../VERSION")) + module = basename(path.module) + name = var.name + } + module_tags = var.module_tags_enabled ? { + "module.terraform.io/package" = local.metadata.package + "module.terraform.io/version" = local.metadata.version + "module.terraform.io/name" = local.metadata.module + "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" + "module.terraform.io/instance" = local.metadata.name + } : {} +} + +locals { + organization_filter_enabled = length(setunion( + var.organization_filter.accounts, + var.organization_filter.organization_units + )) > 0 +} + + +################################################### +# Security Policy for FMS (Firewall Manager) +################################################### + +# INFO: Not supported attributes +resource "aws_fms_policy" "this" { + name = var.name + + ## Policy + security_service_policy_data { + type = "DNS_FIREWALL" + + managed_service_data = jsonencode({ + type = "DNS_FIREWALL" + + preProcessRuleGroups = [ + for item in var.pre_rule_groups : { + priority = item.priority + ruleGroupId = item.rule_group + } + ] + postProcessRuleGroups = [ + for item in var.post_rule_groups : { + priority = item.priority + ruleGroupId = item.rule_group + } + ] + }) + } + + + ## Scope + resource_type = length(var.resource_types) == 1 ? var.resource_types[0] : null + resource_type_list = length(var.resource_types) > 1 ? var.resource_types : null + resource_tags = var.resource_tags_filter.tags + exclude_resource_tags = var.resource_tags_filter.type == "BLACKLIST" + + dynamic "include_map" { + for_each = (var.organization_filter.type == "WHITELIST" && local.organization_filter_enabled) ? ["go"] : [] + + content { + account = var.organization_filter.accounts + orgunit = var.organization_filter.organization_units + } + } + dynamic "exclude_map" { + for_each = (var.organization_filter.type == "BLACKLIST" && local.organization_filter_enabled) ? ["go"] : [] + + content { + account = var.organization_filter.accounts + orgunit = var.organization_filter.organization_units + } + } + + + ## Attributes + remediation_enabled = var.auto_remediation_enabled + delete_unused_fm_managed_resources = var.resource_cleanup_on_leave_enabled + delete_all_policy_resources = var.cascade_deletion_enabled + + tags = merge( + { + "Name" = local.metadata.name + }, + local.module_tags, + var.tags, + ) +} diff --git a/modules/fms-dns-firewall-policy/outputs.tf b/modules/fms-dns-firewall-policy/outputs.tf new file mode 100644 index 0000000..6c16cdd --- /dev/null +++ b/modules/fms-dns-firewall-policy/outputs.tf @@ -0,0 +1,43 @@ +output "arn" { + description = "The ARN of the AWS Firewall Manager Policy." + value = aws_fms_policy.this.arn +} + +output "id" { + description = "The ID of the AWS Firewall Manager Policy." + value = aws_fms_policy.this.id +} + +output "name" { + description = "The name of the AWS Firewall Manager Policy." + value = aws_fms_policy.this.name +} + +output "policy" { + description = "The configuration of this policy." + value = { + pre_rule_groups = var.pre_rule_groups + post_rule_groups = var.post_rule_groups + } +} + +output "scope" { + description = "The configuration of this policy scope." + value = { + resource_types = var.resource_types + resource_tags_filter = { + type = aws_fms_policy.this.exclude_resource_tags ? "BLACKLIST" : "WHITELIST" + tags = aws_fms_policy.this.resource_tags + } + organization_filter = var.organization_filter + } +} + +output "attributes" { + description = "A set of attributes that applied to the AWS Firewall Manager Policy." + value = { + auto_remediation_enabled = aws_fms_policy.this.remediation_enabled + resource_cleanup_on_leave_enabled = aws_fms_policy.this.delete_unused_fm_managed_resources + cascade_deletion_enabled = aws_fms_policy.this.delete_all_policy_resources + } +} diff --git a/modules/fms-dns-firewall-policy/resource-group.tf b/modules/fms-dns-firewall-policy/resource-group.tf new file mode 100644 index 0000000..7487ba0 --- /dev/null +++ b/modules/fms-dns-firewall-policy/resource-group.tf @@ -0,0 +1,31 @@ +locals { + resource_group_name = (var.resource_group_name != "" + ? var.resource_group_name + : join(".", [ + local.metadata.package, + local.metadata.module, + replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), + ]) + ) +} + + +module "resource_group" { + source = "tedilabs/misc/aws//modules/resource-group" + version = "~> 0.10.0" + + count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 + + name = local.resource_group_name + description = var.resource_group_description + + query = { + resource_tags = local.module_tags + } + + module_tags_enabled = false + tags = merge( + local.module_tags, + var.tags, + ) +} diff --git a/modules/fms-dns-firewall-policy/variables.tf b/modules/fms-dns-firewall-policy/variables.tf new file mode 100644 index 0000000..3393dc3 --- /dev/null +++ b/modules/fms-dns-firewall-policy/variables.tf @@ -0,0 +1,175 @@ +variable "name" { + description = "(Required) The friendly name of the AWS Firewall Manager Policy." + type = string +} + +variable "pre_rule_groups" { + description = < 0 + error_message = "The `pre_rule_groups` should have at least one rule group." + } + + validation { + condition = alltrue([ + for rule_group in var.pre_rule_groups : + rule_group.priority >= 1 && rule_group.priority <= 99 + ]) + error_message = "Valid values for `priority` are between 1 and 99." + } +} + +variable "post_rule_groups" { + description = <= 9901 && rule_group.priority <= 10000 + ]) + error_message = "Valid values for `priority` are between 9901 and 10000." + } +} + +variable "resource_types" { + description = "(Optional) A list of resource types to protect." + type = list(string) + default = ["AWS::EC2::VPC"] + nullable = false +} + +variable "resource_tags_filter" { + description = < Date: Thu, 10 Nov 2022 01:27:04 +0900 Subject: [PATCH 2/2] Add example for fms-dns-firewall-policy module --- examples/fms-dns-firewall-policy/main.tf | 145 +++++++++++++++++++ examples/fms-dns-firewall-policy/outputs.tf | 17 +++ examples/fms-dns-firewall-policy/versions.tf | 10 ++ 3 files changed, 172 insertions(+) create mode 100644 examples/fms-dns-firewall-policy/main.tf create mode 100644 examples/fms-dns-firewall-policy/outputs.tf create mode 100644 examples/fms-dns-firewall-policy/versions.tf diff --git a/examples/fms-dns-firewall-policy/main.tf b/examples/fms-dns-firewall-policy/main.tf new file mode 100644 index 0000000..df06465 --- /dev/null +++ b/examples/fms-dns-firewall-policy/main.tf @@ -0,0 +1,145 @@ +provider "aws" { + region = "us-east-1" +} + + +################################################### +# DNS Firewall Domain List +################################################### + +module "domain_list_blacklist" { + source = "../../modules/dns-firewall-domain-list" + # source = "tedilabs/firewall/aws//modules/dns-firewall-domain-list" + # version = "~> 0.1.0" + + name = "example-blacklist" + domains = [ + "example1.blacklist.com.", + "example2.blacklist.com.", + "example3.blacklist.com.", + ] + + tags = { + "project" = "terraform-aws-firewall-examples" + } +} + +module "domain_list_whitelist" { + source = "../../modules/dns-firewall-domain-list" + # source = "tedilabs/firewall/aws//modules/dns-firewall-domain-list" + # version = "~> 0.1.0" + + name = "example-whitelist" + domains = [ + "example1.whitelist.com.", + "example2.whitelist.com.", + "example3.whitelist.com.", + ] + + tags = { + "project" = "terraform-aws-firewall-examples" + } +} + + + +################################################### +# DNS Firewall Rule Group +################################################### + +module "rule_group_1" { + source = "../../modules/dns-firewall-rule-group" + # source = "tedilabs/firewall/aws//modules/dns-firewall-rule-group" + # version = "~> 0.1.0" + + name = "block-blacklist" + rules = [ + { + priority = 10 + name = "block-example" + domain_list = module.domain_list_blacklist.id + action = "BLOCK" + action_parameters = { + response = "OVERRIDE" + override = { + type = "CNAME" + value = "404.mycompany.com." + ttl = 60 + } + } + }, + ] + + tags = { + "project" = "terraform-aws-firewall-examples" + } +} + +module "rule_group_2" { + source = "../../modules/dns-firewall-rule-group" + # source = "tedilabs/firewall/aws//modules/dns-firewall-rule-group" + # version = "~> 0.1.0" + + name = "allow-whitelist" + rules = [ + { + priority = 10 + name = "allow-example" + domain_list = module.domain_list_whitelist.id + action = "ALLOW" + }, + ] + + tags = { + "project" = "terraform-aws-firewall-examples" + } +} + + +################################################### +# DNS Firewall +################################################### + +module "policy" { + source = "../../modules/fms-dns-firewall-policy" + # source = "tedilabs/firewall/aws//modules/fms-dns-firewall-policy" + # version = "~> 0.1.0" + + name = "dns-firewall-example" + + ## Policy + pre_rule_groups = [ + { + priority = 10 + rule_group = module.rule_group_2.id, + } + ] + post_rule_groups = [ + { + priority = 10000 + rule_group = module.rule_group_1.id, + } + ] + + ## Scope + resource_types = ["AWS::EC2::VPC"] + resource_tags_filter = { + type = "BLACKLIST" + tags = { + "Team" = "security" + } + } + organization_filter = { + type = "WHITELIST" + accounts = ["911145092815"] + } + + ## Attributes + auto_remediation_enabled = true + resource_cleanup_on_leave_enabled = true + cascade_deletion_enabled = true + + tags = { + "project" = "terraform-aws-firewall-examples" + } +} diff --git a/examples/fms-dns-firewall-policy/outputs.tf b/examples/fms-dns-firewall-policy/outputs.tf new file mode 100644 index 0000000..9c619f2 --- /dev/null +++ b/examples/fms-dns-firewall-policy/outputs.tf @@ -0,0 +1,17 @@ +output "domain_lists" { + value = { + blacklist = module.domain_list_blacklist + whitelist = module.domain_list_whitelist + } +} + +output "rule_group" { + value = [ + module.rule_group_1, + module.rule_group_2, + ] +} + +output "policy" { + value = module.policy +} diff --git a/examples/fms-dns-firewall-policy/versions.tf b/examples/fms-dns-firewall-policy/versions.tf new file mode 100644 index 0000000..3c3b4cf --- /dev/null +++ b/examples/fms-dns-firewall-policy/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.0" + } + } +}