An open API service indexing awesome lists of open source software.

https://github.com/govtechsg/terraform-aws-firewall

Terraform module to create an AWS Network Firewall
https://github.com/govtechsg/terraform-aws-firewall

aws terraform terraform-module terraform-modules

Last synced: 18 days ago
JSON representation

Terraform module to create an AWS Network Firewall

Awesome Lists containing this project

README

          

# terraform-aws-firewall
Terraform module to create an AWS Network Firewall with advanced rule management and automatic threat intelligence integration.

## Features

- **Automated Gitsir Integration**: Automatically pulls and applies IP and domain blocklists from Gitsir threat intelligence
- **Flexible Rule Management**: Support for custom IP blocks, domain blocks, and whitelisting
- **AWS Managed Rules**: Integration with AWS managed threat signature rules
- **Configurable Actions**: Support for strict/established drop and alert modes
- **CloudWatch Integration**: Comprehensive logging with configurable retention

## Usage

```hcl
module "firewall" {
name = "my-firewall"
description = "my firewall for this vpc"

# Cannot use vpc dependency as vpc will also depend on this
subnet_ids = [
"subnet-1a",
"subnet-1b",
"subnet-1c"
]

vpc_id = "vpc-xx"

# Enable automatic Gitsir threat intelligence (requires GitLab credentials)
enable_gitsir_ip_list = true
ci_api_v4_url = var.ci_api_v4_url # Set via TF_VAR_ci_api_v4_url
project_access_token = var.project_access_token # Set via TF_VAR_project_access_token

# Custom IP blocks - key names must be numeric for SID generation
blocked_ips = {
"1001" = {
capacity = 100
ips = ["192.168.1.100/32", "10.0.0.50/32"]
}
}

# Custom domain blocks
blocked_domains = {
"1002" = {
capacity = 50
domains = ["malicious-site.com", "spam-domain.org"]
}
}

# Whitelist outgoing traffic (HTTP/HTTPS and custom TCP)
whitelist_outgoing = {
http = {
"1003" = {
name = "allowed-web-traffic"
capacity = 100
port = 443
ips = []
domains = ["api.example.com", "cdn.example.com"]
}
}
tcp = {
"1004" = {
name = "custom-service"
capacity = 50
port = 8443
ips = ["203.0.113.10/32"]
domains = ["secure-service.example.com"]
}
}
}

# Alert rules for monitoring
alert_outgoing = {
"1005" = {
protocol = "tcp"
port = 22
message = "SSH outbound connection detected"
}
}

# Firewall behavior configuration
default_action = ["aws:alert_established"] # Options: aws:drop_strict, aws:drop_established, aws:alert_strict, aws:alert_established
enable_block_everything_by_default = false

# CloudWatch log group subscriptions
lg_filters = {
"gcsoc" = {
naming_suffix = "gcsoc-lg-filter"
role_arn = "arn:aws:iam::${get_aws_account_id()}:role/central-logging-cloudwatch-firehose-role"
filter_pattern = ""
destination_arn = "arn:aws:firehose:${local.common_vars.region}:${get_aws_account_id()}:deliverystream/clm-central-logging-firehose"
distribution = "ByLogStream"
}
}
}
```

### Gitsir Integration

The module automatically integrates with Gitsir threat intelligence to pull the latest IP and domain blocklists. This feature is controlled by the `enable_gitsir_ip_list` variable and requires GitLab API credentials.

**Required Environment Variables for Gitsir:**
```bash
export TF_VAR_ci_api_v4_url="https://sgts.gitlab-dedicated.com/api/v4"
export TF_VAR_project_access_token="your-gitlab-project-access-token"
```

The token requires:
- `read_api` scope
- At least `Reporter` role on the Gitsir project

## Requirements

| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | >= 0.13 |

## Providers

| Name | Version |
|------|---------|
| [aws](#provider\_aws) | n/a |
| [http](#provider\_http) | n/a |
| [random](#provider\_random) | n/a |
| [terraform](#provider\_terraform) | n/a |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [aws_cloudwatch_log_group.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_cloudwatch_log_subscription_filter.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_subscription_filter) | resource |
| [aws_kms_alias.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
| [aws_kms_key.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
| [aws_networkfirewall_firewall.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_firewall) | resource |
| [aws_networkfirewall_firewall_policy.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_firewall_policy) | resource |
| [aws_networkfirewall_logging_configuration.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_logging_configuration) | resource |
| [aws_networkfirewall_rule_group.allow-outgoing-http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [aws_networkfirewall_rule_group.allow-outgoing-tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [aws_networkfirewall_rule_group.block-all-outgoing](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [aws_networkfirewall_rule_group.block-domains](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [aws_networkfirewall_rule_group.block-ips](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [aws_networkfirewall_rule_group.gitsir-domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [aws_networkfirewall_rule_group.gitsir-ip](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [aws_networkfirewall_rule_group.pretend-to-block-all-outgoing](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/networkfirewall_rule_group) | resource |
| [random_id.sid](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
| [terraform_data.gitsir_blocklist_ip](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [http_http.gitsir_blocklist_domain](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http) | data source |
| [http_http.gitsir_blocklist_ip](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http) | data source |
| [http_http.gitsir_blocklist_packages](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [alert\_outgoing](#input\_alert\_outgoing) | n/a |

map(object({
protocol = string
port = number
message = string
}))
| n/a | yes |
| [aws\_region](#input\_aws\_region) | Region which resources will be created in | `string` | `"ap-southeast-1"` | no |
| [blocked\_domains](#input\_blocked\_domains) | Domains to block (both ingress & egress), maximum capacity across all rules is 30000 |
map(object({
capacity = number
domains = list(string)
}))
| `{}` | no |
| [blocked\_ips](#input\_blocked\_ips) | Block all traffic from/to specific IPs, note that keys can only be numeric, and maximum capacity across all rules is 30000 |
map(object({
capacity = number
ips = list(string)
}))
| `{}` | no |
| [ci\_api\_v4\_url](#input\_ci\_api\_v4\_url) | GitLab API v4 root URL.
To supply to Terraform, set the environment variable TF\_VAR\_ci\_api\_v4\_url
to the value of the predefined CI/CD variable CI\_API\_V4\_URL.
See .gitlab-ci-example.yml for an example.
Hardcoding this value is also possible as it is unlikely to change, but not recommended. | `string` | n/a | yes |
| [cloudwatch\_log\_retention\_in\_days](#input\_cloudwatch\_log\_retention\_in\_days) | Specifies the number of days you want to retain log events in the specified log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653, and 0. If you select 0, the events in the log group are always retained and never expire. | `number` | `180` | no |
| [create\_network\_firewall](#input\_create\_network\_firewall) | toggle for creation of network firewall, set to false if you only want to create the firewall policy with this module | `bool` | `true` | no |
| [default\_action](#input\_default\_action) | Pick option(s) from `aws:drop_strict`, `aws:drop_established`, `aws:alert_strict`, `aws:alert_established`. Default to []. | `set(string)` | `[]` | no |
| [delete\_protection](#input\_delete\_protection) | Toggle to enable or disable deletion protection | `bool` | `true` | no |
| [enable\_block\_everything\_by\_default](#input\_enable\_block\_everything\_by\_default) | Creates rule that will block all traffic by default, and you will have to whitelist routes specifically to allow internet traffic | `bool` | `false` | no |
| [enable\_gitsir\_ip\_list](#input\_enable\_gitsir\_ip\_list) | Toggle to enable retrieval of gitsir IP list. | `bool` | `false` | no |
| [lg\_filters](#input\_lg\_filters) | Log group filters for Network Firewall |
map(object({
naming_suffix = string
role_arn = string
filter_pattern = string
destination_arn = string
distribution = string
}))
| `{}` | no |
| [name](#input\_name) | The name of the network firewall | `string` | n/a | yes |
| [project\_access\_token](#input\_project\_access\_token) | Your GitLab project access token (create if needed).
It requires the read\_api scope and at least the Reporter role. | `string` | n/a | yes |
| [subnet\_ids](#input\_subnet\_ids) | Subnets used to create network firewall. | `set(string)` | `[]` | no |
| [tags](#input\_tags) | A map of tags to add to all resources | `map(any)` | `{}` | no |
| [vpc\_id](#input\_vpc\_id) | n/a | `string` | `""` | no |
| [whitelist\_outgoing](#input\_whitelist\_outgoing) | IPs to allow (egress), note that keys can only be numeric, and maximum capacity across all rules is 30000, protocol can be IP/dns/http/etc. |
map(map(object({
name = string
capacity = number
port = number
ips = list(string)
domains = list(string)
})))
| `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| [firewall](#output\_firewall) | n/a |
| [firewall\_policy\_arn](#output\_firewall\_policy\_arn) | n/a |