Network firewall policy module (#1232)
* validated, untested * tested * typo in README
This commit is contained in:
committed by
GitHub
parent
b3e0f4e5f3
commit
45c12e233b
@@ -30,7 +30,7 @@ The current list of modules supports most of the core foundational and networkin
|
||||
Currently available modules:
|
||||
|
||||
- **foundational** - [billing budget](./modules/billing-budget), [Cloud Identity group](./modules/cloud-identity-group/), [folder](./modules/folder), [service accounts](./modules/iam-service-account), [logging bucket](./modules/logging-bucket), [organization](./modules/organization), [project](./modules/project), [projects-data-source](./modules/projects-data-source)
|
||||
- **networking** - [DNS](./modules/dns), [Cloud Endpoints](./modules/endpoints), [address reservation](./modules/net-address), [NAT](./modules/net-cloudnat), [Global Load Balancer (classic)](./modules/net-glb/), [L4 ILB](./modules/net-ilb), [L7 ILB](./modules/net-ilb-l7), [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [VPN static](./modules/net-vpn-static), [Service Directory](./modules/service-directory)
|
||||
- **networking** - [DNS](./modules/dns), [Cloud Endpoints](./modules/endpoints), [address reservation](./modules/net-address), [NAT](./modules/net-cloudnat), [Global Load Balancer (classic)](./modules/net-glb/), [L4 ILB](./modules/net-ilb), [L7 ILB](./modules/net-ilb-l7), [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC firewall policy](./modules/net-vpc-firewall-policy), [VPC peering](./modules/net-vpc-peering), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [VPN static](./modules/net-vpn-static), [Service Directory](./modules/service-directory)
|
||||
- **compute** - [VM/VM group](./modules/compute-vm), [MIG](./modules/compute-mig), [COS container](./modules/cloud-config-container/cos-generic-metadata/) (coredns, mysql, onprem, squid), [GKE cluster](./modules/gke-cluster), [GKE hub](./modules/gke-hub), [GKE nodepool](./modules/gke-nodepool)
|
||||
- **data** - [BigQuery dataset](./modules/bigquery-dataset), [Bigtable instance](./modules/bigtable-instance), [Cloud SQL instance](./modules/cloudsql-instance), [Data Catalog Policy Tag](./modules/data-catalog-policy-tag), [Datafusion](./modules/datafusion), [Dataproc](./modules/dataproc), [GCS](./modules/gcs), [Pub/Sub](./modules/pubsub)
|
||||
- **development** - [API Gateway](./modules/api-gateway), [Apigee](./modules/apigee), [Artifact Registry](./modules/artifact-registry), [Container Registry](./modules/container-registry), [Cloud Source Repository](./modules/source-repository)
|
||||
|
||||
@@ -50,6 +50,7 @@ These modules are used in the examples included in this repository. If you are u
|
||||
- [L7 ILB](./net-ilb-l7)
|
||||
- [VPC](./net-vpc)
|
||||
- [VPC firewall](./net-vpc-firewall)
|
||||
- [VPC firewall policy](./net-vpc-firewall-policy)
|
||||
- [VPC peering](./net-vpc-peering)
|
||||
- [VPN dynamic](./net-vpn-dynamic)
|
||||
- [HA VPN](./net-vpn-ha)
|
||||
|
||||
72
modules/net-vpc-firewall-policy/README.md
Normal file
72
modules/net-vpc-firewall-policy/README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Google Cloud Network Firewall Policies
|
||||
|
||||
This module allows creation and management of a [global](https://cloud.google.com/vpc/docs/network-firewall-policies) or [regional](https://cloud.google.com/vpc/docs/regional-firewall-policies) network firewall policy, including its associations and rules.
|
||||
|
||||
The module interface deviates slightly from the [`net-vpc-firewall`](../net-vpc-firewall/) module since the underlying resources and API objects are different.
|
||||
|
||||
It 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.
|
||||
|
||||
A factory implementation will be added in a subsequent release.
|
||||
|
||||
## Example
|
||||
|
||||
```hcl
|
||||
module "firewall-policy" {
|
||||
source = "./fabric/modules/net-vpc-firewall-policy"
|
||||
name = "test-1"
|
||||
project_id = "my-project"
|
||||
# specify a region to create and manage a regional policy
|
||||
# region = "europe-west8"
|
||||
target_vpcs = [
|
||||
"projects/my-project/global/networks/shared-vpc"
|
||||
]
|
||||
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
|
||||
match = {
|
||||
source_ranges = ["10.1.1.0/24"]
|
||||
}
|
||||
}
|
||||
ssh = {
|
||||
priority = 1002
|
||||
match = {
|
||||
source_ranges = ["10.0.0.0/8"]
|
||||
# source_tags = ["tagValues/123456"]
|
||||
layer4_configs = [{ protocol = "tcp", ports = ["22"] }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=6
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [name](variables.tf#L98) | Policy name. | <code>string</code> | ✓ | |
|
||||
| [project_id](variables.tf#L104) | Project id of the project that holds the network. | <code>string</code> | ✓ | |
|
||||
| [description](variables.tf#L17) | Policy description. | <code>string</code> | | <code>null</code> |
|
||||
| [egress_rules](variables.tf#L23) | List of egress rule definitions, action can be 'allow', 'deny', 'goto_next'. The match.layer4configs map is in protocol => optional [ports] format. | <code title="map(object({ priority = number action = optional(string, "deny") description = optional(string) disabled = optional(bool, false) enable_logging = optional(bool) target_service_accounts = optional(list(string)) target_tags = optional(list(string)) match = object({ destination_ranges = optional(list(string)) source_ranges = optional(list(string)) source_tags = optional(list(string)) layer4_configs = optional(list(object({ protocol = optional(string, "all") ports = optional(list(string)) })), [{}]) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [ingress_rules](variables.tf#L60) | List of ingress rule definitions, action can be 'allow', 'deny', 'goto_next'. | <code title="map(object({ priority = number action = optional(string, "allow") description = optional(string) disabled = optional(bool, false) enable_logging = optional(bool) target_service_accounts = optional(list(string)) target_tags = optional(list(string)) match = object({ destination_ranges = optional(list(string)) source_ranges = optional(list(string)) source_tags = optional(list(string)) layer4_configs = optional(list(object({ protocol = optional(string, "all") ports = optional(list(string)) })), [{}]) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [region](variables.tf#L110) | Policy region. Leave null for global policy. | <code>string</code> | | <code>null</code> |
|
||||
| [target_vpcs](variables.tf#L116) | VPC ids to which this policy will be attached. | <code>list(string)</code> | | <code>[]</code> |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
150
modules/net-vpc-firewall-policy/main.tf
Normal file
150
modules/net-vpc-firewall-policy/main.tf
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
rules = merge(
|
||||
local._rules_egress, local._rules_ingress
|
||||
)
|
||||
_rules_egress = {
|
||||
for name, rule in merge(var.egress_rules) :
|
||||
name => merge(rule, { direction = "EGRESS" })
|
||||
}
|
||||
_rules_ingress = {
|
||||
for name, rule in merge(var.ingress_rules) :
|
||||
name => merge(rule, { direction = "INGRESS" })
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# global policy #
|
||||
###############################################################################
|
||||
|
||||
resource "google_compute_network_firewall_policy" "default" {
|
||||
count = var.region == null ? 1 : 0
|
||||
project = var.project_id
|
||||
name = var.name
|
||||
description = var.description
|
||||
}
|
||||
|
||||
resource "google_compute_network_firewall_policy_association" "default" {
|
||||
for_each = toset(var.region == null ? var.target_vpcs : [])
|
||||
project = var.project_id
|
||||
name = "${var.name}-${reverse(split("/", each.key))[0]}"
|
||||
attachment_target = each.key
|
||||
firewall_policy = google_compute_network_firewall_policy.default.0.name
|
||||
}
|
||||
|
||||
resource "google_compute_network_firewall_policy_rule" "default" {
|
||||
provider = google-beta
|
||||
for_each = var.region == null ? local.rules : {}
|
||||
project = var.project_id
|
||||
firewall_policy = google_compute_network_firewall_policy.default.0.name
|
||||
rule_name = each.key
|
||||
action = each.value.action
|
||||
description = each.value.description
|
||||
direction = each.value.direction
|
||||
disabled = each.value.disabled
|
||||
enable_logging = each.value.enable_logging
|
||||
priority = each.value.priority
|
||||
target_service_accounts = each.value.target_service_accounts
|
||||
match {
|
||||
dest_ip_ranges = each.value.match.destination_ranges
|
||||
src_ip_ranges = each.value.match.source_ranges
|
||||
dynamic "layer4_configs" {
|
||||
for_each = each.value.match.layer4_configs
|
||||
content {
|
||||
ip_protocol = layer4_configs.value.protocol
|
||||
ports = layer4_configs.value.ports
|
||||
}
|
||||
}
|
||||
dynamic "src_secure_tags" {
|
||||
for_each = toset(coalesce(each.value.match.source_tags, []))
|
||||
content {
|
||||
name = src_secure_tags.key
|
||||
}
|
||||
}
|
||||
}
|
||||
dynamic "target_secure_tags" {
|
||||
for_each = toset(
|
||||
each.value.target_tags == null ? [] : each.value.target_tags
|
||||
)
|
||||
content {
|
||||
name = target_secure_tags.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# regional policy #
|
||||
###############################################################################
|
||||
|
||||
resource "google_compute_region_network_firewall_policy" "default" {
|
||||
count = var.region != null ? 1 : 0
|
||||
project = var.project_id
|
||||
name = var.name
|
||||
description = var.description
|
||||
region = var.region
|
||||
}
|
||||
|
||||
resource "google_compute_region_network_firewall_policy_association" "default" {
|
||||
for_each = toset(var.region != null ? var.target_vpcs : [])
|
||||
project = var.project_id
|
||||
name = "${var.name}-${reverse(split("/", each.key))[0]}"
|
||||
region = var.region
|
||||
attachment_target = each.key
|
||||
firewall_policy = google_compute_region_network_firewall_policy.default.0.name
|
||||
}
|
||||
|
||||
resource "google_compute_region_network_firewall_policy_rule" "default" {
|
||||
provider = google-beta
|
||||
for_each = var.region != null ? local.rules : {}
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
firewall_policy = google_compute_region_network_firewall_policy.default.0.name
|
||||
rule_name = each.key
|
||||
action = each.value.action
|
||||
description = each.value.description
|
||||
direction = each.value.direction
|
||||
disabled = each.value.disabled
|
||||
enable_logging = each.value.enable_logging
|
||||
priority = each.value.priority
|
||||
target_service_accounts = each.value.target_service_accounts
|
||||
match {
|
||||
dest_ip_ranges = each.value.match.destination_ranges
|
||||
src_ip_ranges = each.value.match.source_ranges
|
||||
dynamic "layer4_configs" {
|
||||
for_each = each.value.match.layer4_configs
|
||||
content {
|
||||
ip_protocol = layer4_configs.value.protocol
|
||||
ports = layer4_configs.value.ports
|
||||
}
|
||||
}
|
||||
dynamic "src_secure_tags" {
|
||||
for_each = toset(coalesce(each.value.match.source_tags, []))
|
||||
content {
|
||||
name = src_secure_tags.key
|
||||
}
|
||||
}
|
||||
}
|
||||
dynamic "target_secure_tags" {
|
||||
for_each = toset(
|
||||
each.value.target_tags == null ? [] : each.value.target_tags
|
||||
)
|
||||
content {
|
||||
name = target_secure_tags.value
|
||||
}
|
||||
}
|
||||
}
|
||||
121
modules/net-vpc-firewall-policy/variables.tf
Normal file
121
modules/net-vpc-firewall-policy/variables.tf
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "description" {
|
||||
description = "Policy description."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "egress_rules" {
|
||||
description = "List of egress rule definitions, action can be 'allow', 'deny', 'goto_next'. The match.layer4configs map is in protocol => optional [ports] format."
|
||||
type = map(object({
|
||||
priority = number
|
||||
action = optional(string, "deny")
|
||||
description = optional(string)
|
||||
disabled = optional(bool, false)
|
||||
enable_logging = optional(bool)
|
||||
target_service_accounts = optional(list(string))
|
||||
target_tags = optional(list(string))
|
||||
match = object({
|
||||
destination_ranges = optional(list(string))
|
||||
source_ranges = optional(list(string))
|
||||
source_tags = optional(list(string))
|
||||
layer4_configs = optional(list(object({
|
||||
protocol = optional(string, "all")
|
||||
ports = optional(list(string))
|
||||
})), [{}])
|
||||
})
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in var.egress_rules : v.match.destination_ranges != null
|
||||
])
|
||||
error_message = "Engress rules need destination ranges."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in var.egress_rules :
|
||||
contains(["allow", "deny", "goto_next"], v.action)
|
||||
])
|
||||
error_message = "Action can only be one of 'allow', 'deny', 'goto_next'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "ingress_rules" {
|
||||
description = "List of ingress rule definitions, action can be 'allow', 'deny', 'goto_next'."
|
||||
type = map(object({
|
||||
priority = number
|
||||
action = optional(string, "allow")
|
||||
description = optional(string)
|
||||
disabled = optional(bool, false)
|
||||
enable_logging = optional(bool)
|
||||
target_service_accounts = optional(list(string))
|
||||
target_tags = optional(list(string))
|
||||
match = object({
|
||||
destination_ranges = optional(list(string))
|
||||
source_ranges = optional(list(string))
|
||||
source_tags = optional(list(string))
|
||||
layer4_configs = optional(list(object({
|
||||
protocol = optional(string, "all")
|
||||
ports = optional(list(string))
|
||||
})), [{}])
|
||||
})
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in var.ingress_rules :
|
||||
v.match.source_ranges != null || v.match.source_tags != null
|
||||
])
|
||||
error_message = "Ingress rules need source ranges or tags."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in var.ingress_rules :
|
||||
contains(["allow", "deny", "goto_next"], v.action)
|
||||
])
|
||||
error_message = "Action can only be one of 'allow', 'deny', 'goto_next'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "name" {
|
||||
description = "Policy name."
|
||||
type = string
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "Project id of the project that holds the network."
|
||||
type = string
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "Policy region. Leave null for global policy."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "target_vpcs" {
|
||||
description = "VPC ids to which this policy will be attached."
|
||||
type = list(string)
|
||||
default = []
|
||||
nullable = false
|
||||
}
|
||||
29
modules/net-vpc-firewall-policy/versions.tf
Normal file
29
modules/net-vpc-firewall-policy/versions.tf
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.3.1"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 4.55.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 4.55.0" # tftest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user