531 lines
17 KiB
Markdown
531 lines
17 KiB
Markdown
# Firewall Policies
|
|
|
|
This module allows creation and management of two different firewall policy types:
|
|
|
|
- a [hierarchical policy](https://cloud.google.com/firewall/docs/firewall-policies) in a folder or organization, or
|
|
- a [global](https://cloud.google.com/vpc/docs/network-firewall-policies) or [regional](https://cloud.google.com/vpc/docs/regional-firewall-policies) network policy
|
|
|
|
The module also manages policy rules via code or a factory, and optional policy attachments. The interface deviates slightly from the [`net-vpc-firewall`](../net-vpc-firewall/) module since the underlying resources and API objects are different.
|
|
|
|
The module also makes fewer assumptions about implicit defaults, only using one to set `match.layer4_configs` to `[{ protocol = "all" }]` if no explicit set of protocols and ports has been specified.
|
|
|
|
<!-- BEGIN TOC -->
|
|
- [Examples](#examples)
|
|
- [Hierarchical Policy](#hierarchical-policy)
|
|
- [Global Network policy](#global-network-policy)
|
|
- [Regional Network policy](#regional-network-policy)
|
|
- [Packet Mirroring Rules](#packet-mirroring-rules)
|
|
- [Packet Mirroring Rules](#packet-mirroring-rules)
|
|
- [Factory](#factory)
|
|
- [Firewall Rule Factory Schema](#firewall-rule-factory-schema)
|
|
- [Dynamic Rule Matching](#dynamic-rule-matching)
|
|
- [Ingress Rules](#ingress-rules)
|
|
- [Egress Rules](#egress-rules)
|
|
- [Rule-Level Mappings](#rule-level-mappings)
|
|
- [Variables](#variables)
|
|
- [Outputs](#outputs)
|
|
<!-- END TOC -->
|
|
|
|
## Examples
|
|
|
|
### Hierarchical Policy
|
|
|
|
```hcl
|
|
module "firewall-policy" {
|
|
source = "./fabric/modules/net-firewall-policy"
|
|
name = "test-1"
|
|
parent_id = "folders/1234567890"
|
|
attachments = {
|
|
test = "folders/4567890123"
|
|
}
|
|
egress_rules = {
|
|
smtp = {
|
|
priority = 900
|
|
match = {
|
|
destination_ranges = ["0.0.0.0/0"]
|
|
layer4_configs = [{ protocol = "tcp", ports = ["25"] }]
|
|
}
|
|
}
|
|
}
|
|
ingress_rules = {
|
|
icmp = {
|
|
priority = 1000
|
|
match = {
|
|
source_ranges = ["0.0.0.0/0"]
|
|
layer4_configs = [{ protocol = "icmp" }]
|
|
}
|
|
}
|
|
mgmt = {
|
|
priority = 1001
|
|
enable_logging = true
|
|
match = {
|
|
source_ranges = ["10.1.1.0/24"]
|
|
}
|
|
}
|
|
ssh = {
|
|
priority = 1002
|
|
enable_logging = true
|
|
match = {
|
|
source_ranges = ["10.0.0.0/8"]
|
|
source_tags = ["tagValues/123456"]
|
|
layer4_configs = [{ protocol = "tcp", ports = ["22"] }]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=1 resources=6 inventory=hierarchical.yaml
|
|
```
|
|
|
|
### Global Network policy
|
|
|
|
```hcl
|
|
module "vpc" {
|
|
source = "./fabric/modules/net-vpc"
|
|
project_id = "my-project"
|
|
name = "my-network"
|
|
}
|
|
|
|
module "firewall-policy" {
|
|
source = "./fabric/modules/net-firewall-policy"
|
|
name = "test-1"
|
|
parent_id = "my-project"
|
|
region = "global"
|
|
attachments = {
|
|
my-vpc = module.vpc.self_link
|
|
}
|
|
egress_rules = {
|
|
smtp = {
|
|
priority = 900
|
|
match = {
|
|
destination_ranges = ["0.0.0.0/0"]
|
|
layer4_configs = [{ protocol = "tcp", ports = ["25"] }]
|
|
}
|
|
}
|
|
}
|
|
ingress_rules = {
|
|
icmp = {
|
|
priority = 1000
|
|
match = {
|
|
source_ranges = ["0.0.0.0/0"]
|
|
layer4_configs = [{ protocol = "icmp" }]
|
|
}
|
|
}
|
|
mgmt = {
|
|
priority = 1001
|
|
enable_logging = true
|
|
match = {
|
|
source_ranges = ["10.1.1.0/24"]
|
|
}
|
|
}
|
|
ssh = {
|
|
priority = 1002
|
|
enable_logging = true
|
|
match = {
|
|
source_ranges = ["10.0.0.0/8"]
|
|
# source_tags = ["tagValues/123456"]
|
|
layer4_configs = [{ protocol = "tcp", ports = ["22"] }]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=2 resources=10 inventory=global-net.yaml
|
|
```
|
|
|
|
### Regional Network policy
|
|
|
|
```hcl
|
|
module "vpc" {
|
|
source = "./fabric/modules/net-vpc"
|
|
project_id = "my-project"
|
|
name = "my-network"
|
|
}
|
|
|
|
module "firewall-policy" {
|
|
source = "./fabric/modules/net-firewall-policy"
|
|
name = "test-1"
|
|
parent_id = "my-project"
|
|
region = "europe-west8"
|
|
attachments = {
|
|
my-vpc = module.vpc.self_link
|
|
}
|
|
egress_rules = {
|
|
smtp = {
|
|
priority = 900
|
|
match = {
|
|
destination_ranges = ["0.0.0.0/0"]
|
|
layer4_configs = [{ protocol = "tcp", ports = ["25"] }]
|
|
}
|
|
}
|
|
}
|
|
ingress_rules = {
|
|
icmp = {
|
|
priority = 1000
|
|
match = {
|
|
source_ranges = ["0.0.0.0/0"]
|
|
layer4_configs = [{ protocol = "icmp" }]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=2 resources=8 inventory=regional-net.yaml
|
|
```
|
|
|
|
### Packet Mirroring Rules
|
|
|
|
### Packet Mirroring Rules
|
|
|
|
Packet mirroring rules can be defined using the `ingress_mirroring_rules` and `egress_mirroring_rules` variables. This is supported only for Global Network Policies.
|
|
|
|
```hcl
|
|
resource "google_network_security_security_profile" "default" {
|
|
provider = google-beta
|
|
name = "sec-profile"
|
|
parent = var.organization_id
|
|
type = "CUSTOM_MIRRORING"
|
|
|
|
custom_mirroring_profile {
|
|
mirroring_endpoint_group = "xxx"
|
|
}
|
|
}
|
|
|
|
resource "google_network_security_security_profile_group" "default" {
|
|
provider = google-beta
|
|
name = "sec-profile-group"
|
|
parent = var.organization_id
|
|
custom_mirroring_profile = google_network_security_security_profile.default.id
|
|
}
|
|
|
|
|
|
module "firewall-policy" {
|
|
source = "./fabric/modules/net-firewall-policy"
|
|
name = "test-mirroring"
|
|
parent_id = "my-project"
|
|
region = "global"
|
|
attachments = {
|
|
my-vpc = var.vpc.self_link
|
|
}
|
|
security_profile_group_ids = {
|
|
my-spg = "//networksecurity.googleapis.com/${google_network_security_security_profile_group.default.id}"
|
|
}
|
|
ingress_mirroring_rules = {
|
|
rule-1 = {
|
|
priority = 1000
|
|
action = "mirror"
|
|
description = "Mirror all traffic"
|
|
match = {
|
|
source_ranges = ["0.0.0.0/0"]
|
|
layer4_configs = [
|
|
{ protocol = "tcp", ports = ["80", "443"] }
|
|
]
|
|
}
|
|
security_profile_group = "//networksecurity.googleapis.com/${google_network_security_security_profile_group.default.id}"
|
|
}
|
|
}
|
|
}
|
|
# tftest inventory=mirroring.yaml
|
|
```
|
|
|
|
### Factory
|
|
|
|
Similarly to other modules, a rules factory is also included here to allow route management via descriptive configuration files.
|
|
|
|
Factory configuration is via three optional attributes in the `rules_factory_config` variable:
|
|
|
|
- `cidr_file_path` specifying the path to a mapping of logical names to CIDR ranges, used for source and destination ranges in rules when available
|
|
- `egress_rules_file_path` specifying the path to the egress rules file
|
|
- `ingress_rules_file_path` specifying the path to the ingress rules file
|
|
- `ingress_mirroring_rules_file_path` specifying the path to the mirroring rules file
|
|
- `egress_mirroring_rules_file_path` specifying the path to the mirroring rules file
|
|
|
|
Factory rules are merged with rules declared in code, with the latter taking precedence where both use the same key.
|
|
Also, the factory applies implicit defaults: `action` defaults to `deny` for egress and `allow` for ingress, while omitting `layer4_configs` makes the rule match all protocols.
|
|
|
|
This is an example of a simple factory:
|
|
|
|
```hcl
|
|
module "firewall-policy" {
|
|
source = "./fabric/modules/net-firewall-policy"
|
|
name = "test-1"
|
|
parent_id = "folders/1234567890"
|
|
attachments = {
|
|
test = "folders/4567890123"
|
|
}
|
|
ingress_rules = {
|
|
ssh = {
|
|
priority = 1002
|
|
match = {
|
|
source_ranges = ["10.0.0.0/8"]
|
|
layer4_configs = [{ protocol = "tcp", ports = ["22"] }]
|
|
}
|
|
}
|
|
}
|
|
factories_config = {
|
|
cidr_file_path = "configs/cidrs.yaml"
|
|
egress_rules_file_path = "configs/egress.yaml"
|
|
ingress_rules_file_path = "configs/ingress.yaml"
|
|
}
|
|
}
|
|
# tftest modules=1 resources=6 files=cidrs,egress,ingress inventory=factory.yaml
|
|
```
|
|
|
|
```yaml
|
|
rfc1918:
|
|
- 10.0.0.0/8
|
|
- 172.16.0.0/12
|
|
- 192.168.0.0/24
|
|
gke-nodes-range:
|
|
- 10.0.1.0/24
|
|
# tftest-file id=cidrs path=configs/cidrs.yaml
|
|
```
|
|
|
|
```yaml
|
|
smtp:
|
|
priority: 900
|
|
match:
|
|
destination_ranges:
|
|
- rfc1918
|
|
layer4_configs:
|
|
- protocol: tcp
|
|
ports:
|
|
- 25
|
|
# tftest-file id=egress path=configs/egress.yaml schema=firewall-policy-rules.schema.json
|
|
```
|
|
|
|
```yaml
|
|
icmp:
|
|
priority: 1000
|
|
match:
|
|
source_ranges:
|
|
- 10.0.0.0/8
|
|
layer4_configs:
|
|
- protocol: icmp
|
|
issue-1995:
|
|
priority: 10020
|
|
description: Allow intra-cluster communication required by k8s networking model
|
|
enable_logging: true
|
|
target_service_accounts:
|
|
- sa-gke-cluster@burner-project.iam.gserviceaccount.com
|
|
match:
|
|
source_ranges:
|
|
- gke-nodes-range
|
|
layer4_configs:
|
|
- protocol: tcp
|
|
ports:
|
|
- 1-65535
|
|
- protocol: udp
|
|
ports:
|
|
- 1-65535
|
|
- protocol: icmp
|
|
# tftest-file id=ingress path=configs/ingress.yaml schema=firewall-policy-rules.schema.json
|
|
```
|
|
|
|
```yaml
|
|
icmp:
|
|
priority: 1000
|
|
match:
|
|
source_ranges:
|
|
- 10.0.0.0/8
|
|
layer4_configs:
|
|
- protocol: icmp
|
|
issue-1995:
|
|
priority: 10020
|
|
description: Allow intra-cluster communication required by k8s networking model
|
|
enable_logging: true
|
|
target_service_accounts:
|
|
- sa-gke-cluster@burner-project.iam.gserviceaccount.com
|
|
match:
|
|
source_ranges:
|
|
- gke-nodes-range
|
|
layer4_configs:
|
|
- protocol: tcp
|
|
ports:
|
|
- 1-65535
|
|
- protocol: udp
|
|
ports:
|
|
- 1-65535
|
|
- protocol: icmp
|
|
# tftest-file id=ingress path=configs/ingress.yaml schema=firewall-policy-rules.schema.json
|
|
```
|
|
|
|
You might need to reference external security profile groups in your firewall rules, using their Terraform ids. For example, `//networksecurity.googleapis.com/${google_network_security_security_profile_group.security_profile_group.id}`. To do so, list your security profile groups in the `security_profile_group_ids` map variable. Then reference them by key from your factories.
|
|
|
|
```hcl
|
|
module "vpc" {
|
|
source = "./fabric/modules/net-vpc"
|
|
project_id = "my-project"
|
|
name = "my-network"
|
|
}
|
|
|
|
resource "google_network_security_security_profile" "security_profile" {
|
|
name = "security-profile"
|
|
type = "THREAT_PREVENTION"
|
|
parent = var.organization_id
|
|
location = "global"
|
|
}
|
|
|
|
resource "google_network_security_security_profile_group" "security_profile_group" {
|
|
name = "security-profile-group"
|
|
parent = var.organization_id
|
|
location = "global"
|
|
description = "Sample security profile group."
|
|
threat_prevention_profile = google_network_security_security_profile.security_profile.id
|
|
}
|
|
|
|
resource "google_network_security_security_profile" "mirror_profile" {
|
|
provider = google-beta
|
|
name = "sec-profile"
|
|
parent = var.organization_id
|
|
type = "CUSTOM_MIRRORING"
|
|
|
|
custom_mirroring_profile {
|
|
mirroring_endpoint_group = "xxx"
|
|
}
|
|
}
|
|
|
|
resource "google_network_security_security_profile_group" "mirror_profile_group" {
|
|
provider = google-beta
|
|
name = "sec-profile-group"
|
|
parent = var.organization_id
|
|
custom_mirroring_profile = google_network_security_security_profile.mirror_profile.id
|
|
}
|
|
|
|
|
|
module "firewall-policy" {
|
|
source = "./fabric/modules/net-firewall-policy"
|
|
name = "fw-policy"
|
|
parent_id = "my-project"
|
|
security_profile_group_ids = {
|
|
http-sg = "//networksecurity.googleapis.com/${google_network_security_security_profile_group.security_profile_group.id}"
|
|
mirror-sg = "//networksecurity.googleapis.com/${google_network_security_security_profile_group.mirror_profile_group.id}"
|
|
}
|
|
attachments = {
|
|
my-vpc = module.vpc.self_link
|
|
}
|
|
factories_config = {
|
|
ingress_rules_file_path = "configs/ingress-spg.yaml"
|
|
ingress_mirroring_rules_file_path = "configs/mirror-spg.yaml"
|
|
}
|
|
}
|
|
# tftest modules=2 resources=11 files=ingress-spg,mirror-spg inventory=factory-spg.yaml
|
|
```
|
|
|
|
```yaml
|
|
# tftest-file id=ingress-spg path=configs/ingress-spg.yaml
|
|
http:
|
|
priority: 1000
|
|
action: apply_security_profile_group
|
|
security_profile_group: http-sg
|
|
match:
|
|
source_ranges:
|
|
- 10.0.0.0/8
|
|
layer4_configs:
|
|
- protocol: tcp
|
|
ports:
|
|
- 80
|
|
```
|
|
|
|
```yaml
|
|
# tftest-file id=mirror-spg path=configs/mirror-spg.yaml schema=firewall-policy-mirroring-rules.schema.json
|
|
mirror-ssh:
|
|
priority: 1000
|
|
action: mirror
|
|
security_profile_group: mirror-sg
|
|
match:
|
|
source_ranges:
|
|
- 10.0.0.0/8
|
|
layer4_configs:
|
|
- protocol: tcp
|
|
ports:
|
|
- 22
|
|
```
|
|
|
|
#### Firewall Rule Factory Schema
|
|
|
|
The following schema outlines all available fields for defining a rule within a factory YAML file. Use this as a reference, and note the inline comments for fields that apply only to specific policy types.
|
|
|
|
```yaml
|
|
rule-name:
|
|
priority:
|
|
action:
|
|
description:
|
|
disabled:
|
|
enable_logging:
|
|
security_profile_group: # Not for Regional policies
|
|
target_service_accounts: []
|
|
target_tags: []
|
|
target_resources: [] # For Hierarchical policies only
|
|
tls_inspect: # Not for Regional policies
|
|
match:
|
|
source_ranges: []
|
|
destination_ranges: []
|
|
source_tags: [] # Not for Hierarchical policies
|
|
threat_intelligences: []
|
|
fqdns: []
|
|
address_groups: []
|
|
region_codes: []
|
|
layer4_configs:
|
|
- protocol:
|
|
ports: []
|
|
```
|
|
|
|
### Dynamic Rule Matching
|
|
|
|
This module simplifies firewall rule creation by using generic, context-aware variables within the `match` block. Based on the rule's specified `direction` (`INGRESS` or `EGRESS`), the module maps these generic variables to the correct source- (`src_*`) or destination-specific (`dest_*`) arguments in the underlying resource.
|
|
|
|
The tables below provide a complete reference for these dynamic mappings.
|
|
|
|
#### Ingress Rules
|
|
|
|
`direction = "INGRESS"`
|
|
|
|
| Module Variable (`match.*`) | Mapped Resource Attribute |
|
|
| :--- | :--- |
|
|
| `address_groups` | `src_address_groups` |
|
|
| `fqdns` | `src_fqdns` |
|
|
| `region_codes` | `src_region_codes` |
|
|
| `source_tags` | `src_secure_tags` |
|
|
| `threat_intelligences` | `src_threat_intelligences` |
|
|
|
|
#### Egress Rules
|
|
|
|
`direction = "EGRESS"`
|
|
|
|
| Module Variable (`match.*`) | Mapped Resource Attribute |
|
|
| :--- | :--- |
|
|
| `address_groups` | `dest_address_groups` |
|
|
| `fqdns` | `dest_fqdns` |
|
|
| `region_codes` | `dest_region_codes` |
|
|
| `threat_intelligences` | `dest_threat_intelligences` |
|
|
|
|
#### Rule-Level Mappings
|
|
|
|
The following variable is defined at the top level of the rule (not within the `match` block) and is mapped directly, regardless of the rule's direction.
|
|
|
|
| Module Variable | Mapped Resource Attribute |
|
|
| :--- | :--- |
|
|
| `target_tags` | `target_secure_tags` |
|
|
<!-- BEGIN TFDOC -->
|
|
## Variables
|
|
|
|
| name | description | type | required | default |
|
|
|---|---|:---:|:---:|:---:|
|
|
| [name](variables.tf#L197) | Policy name. | <code>string</code> | ✓ | |
|
|
| [parent_id](variables.tf#L203) | Parent node where the policy will be created, `folders/nnn` or `organizations/nnn` for hierarchical policy, project id for a network policy. | <code>string</code> | ✓ | |
|
|
| [attachments](variables.tf#L17) | Ids of the resources to which this policy will be attached, in descriptive name => self link format. Specify folders or organization for hierarchical policy, VPCs for network policy. | <code>map(string)</code> | | <code>{}</code> |
|
|
| [context](variables.tf#L24) | Context-specific interpolations. | <code>object({…})</code> | | <code>{}</code> |
|
|
| [description](variables.tf#L40) | Policy description. | <code>string</code> | | <code>null</code> |
|
|
| [egress_mirroring_rules](variables.tf#L46) | List of egress packet mirroring rule definitions, action can be 'mirror', 'do_not_mirror', or 'goto_next'. | <code>map(object({…}))</code> | | <code>{}</code> |
|
|
| [egress_rules](variables.tf#L77) | List of egress rule definitions, action can be 'allow', 'deny', 'goto_next' or 'apply_security_profile_group'. The match.layer4configs map is in protocol => optional [ports] format. | <code>map(object({…}))</code> | | <code>{}</code> |
|
|
| [factories_config](variables.tf#L115) | Paths to folders for the optional factories. | <code>object({…})</code> | | <code>{}</code> |
|
|
| [ingress_mirroring_rules](variables.tf#L128) | List of ingress packet mirroring rule definitions, action can be 'mirror', 'do_not_mirror', or 'goto_next'. | <code>map(object({…}))</code> | | <code>{}</code> |
|
|
| [ingress_rules](variables.tf#L159) | List of ingress rule definitions, action can be 'allow', 'deny', 'goto_next' or 'apply_security_profile_group'. | <code>map(object({…}))</code> | | <code>{}</code> |
|
|
| [region](variables.tf#L209) | Policy region. Leave null for hierarchical policy, set to 'global' for a global network policy. | <code>string</code> | | <code>null</code> |
|
|
| [security_profile_group_ids](variables.tf#L215) | The optional security groups ids to be referenced in factories. | <code>map(string)</code> | | <code>{}</code> |
|
|
|
|
## Outputs
|
|
|
|
| name | description | sensitive |
|
|
|---|---|:---:|
|
|
| [id](outputs.tf#L17) | Fully qualified firewall policy id. | |
|
|
<!-- END TFDOC -->
|