Refactor VPC firewall module for Terraform 1.3 (#949)

* module and module tests/examples

* align blueprints and fast

* fix null ranges

* make ports optional

* tfdoc

* make rules optional defaulting to all protocols

* review comments

* last round of comments

* invert precedence of template variables

* add option to disable all default rules

* add option to disable all default rules

* split egress/ingress

* tests

* fix tests
This commit is contained in:
Ludovico Magnocavallo 2022-11-04 13:56:07 +01:00 committed by GitHub
parent b166938435
commit fae5654e33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 935 additions and 933 deletions

View File

@ -67,17 +67,16 @@ module "firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc.name
custom_rules = {
ingress_rules = {
image-builder-ingress-builder-vm = {
description = "Allow image builder vm ingress traffic"
direction = "INGRESS"
action = "allow"
sources = []
ranges = var.packer_source_cidrs
source_ranges = var.packer_source_cidrs
targets = [module.service-account-image-builder-vm.email]
use_service_accounts = true
rules = [{ protocol = "tcp", ports = [22, 5985, 5986] }]
extra_attributes = {}
rules = [{
protocol = "tcp"
ports = [22, 5985, 5986]
}]
}
}
}

View File

@ -66,24 +66,7 @@ module "landing-vpc" {
}
module "landing-vpc-firewall" {
source = "../../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
custom_rules = {
allow-ssh = {
description = "Allow SSH from IAP"
direction = "INGRESS"
action = "allow"
sources = []
ranges = ["35.235.240.0/20"]
targets = []
use_service_accounts = false
rules = [{ protocol = "tcp", ports = ["22"] }]
extra_attributes = {}
}
}
source = "../../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-vpc.name
}

View File

@ -128,11 +128,13 @@ module "vpc" {
}
module "firewall" {
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.project.project_id
network = module.vpc.0.name
admin_ranges = ["10.0.0.0/20"]
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.project.project_id
network = module.vpc.0.name
default_rules_config = {
admin_ranges = ["10.0.0.0/20"]
}
}
module "nat" {

View File

@ -59,10 +59,12 @@ module "vpc" {
}
module "vpc-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project-service.project_id
network = module.vpc.name
admin_ranges = [var.vpc_ip_cidr_range]
source = "../../../modules/net-vpc-firewall"
project_id = module.project-service.project_id
network = module.vpc.name
default_rules_config = {
admin_ranges = [var.vpc_ip_cidr_range]
}
}
###############################################################################

View File

@ -118,11 +118,13 @@ module "load-vpc" {
}
module "load-vpc-firewall" {
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.load-project.project_id
network = module.load-vpc.0.name
admin_ranges = ["10.10.0.0/24"]
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.load-project.project_id
network = module.load-vpc.0.name
default_rules_config = {
admin_ranges = ["10.10.0.0/24"]
}
}
module "load-nat" {

View File

@ -133,11 +133,13 @@ module "orch-vpc" {
}
module "orch-vpc-firewall" {
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.orch-project.project_id
network = module.orch-vpc.0.name
admin_ranges = ["10.10.0.0/24"]
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.orch-project.project_id
network = module.orch-vpc.0.name
default_rules_config = {
admin_ranges = ["10.10.0.0/24"]
}
}
module "orch-nat" {

View File

@ -142,11 +142,13 @@ module "transf-vpc" {
}
module "transf-vpc-firewall" {
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.transf-project.project_id
network = module.transf-vpc.0.name
admin_ranges = ["10.10.0.0/24"]
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.transf-project.project_id
network = module.transf-vpc.0.name
default_rules_config = {
admin_ranges = ["10.10.0.0/24"]
}
}
module "transf-nat" {

View File

@ -72,22 +72,19 @@ module "vpc" {
}
module "vpc-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc.name
admin_ranges = [var.vpc_config.ip_cidr_range]
custom_rules = {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc.name
default_rules_config = {
admin_ranges = [var.vpc_config.ip_cidr_range]
}
ingress_rules = {
#TODO Remove and rely on 'ssh' tag once terraform-provider-google/issues/9273 is fixed
("${var.prefix}-iap") = {
description = "Enable SSH from IAP on Notebooks."
direction = "INGRESS"
action = "allow"
sources = []
ranges = ["35.235.240.0/20"]
targets = ["notebook-instance"]
use_service_accounts = false
rules = [{ protocol = "tcp", ports = [22] }]
extra_attributes = {}
description = "Enable SSH from IAP on Notebooks."
source_ranges = ["35.235.240.0/20"]
targets = ["notebook-instance"]
rules = [{ protocol = "tcp", ports = [22] }]
}
}
}

View File

@ -27,11 +27,13 @@ module "vpc" {
}
module "vpc-firewall" {
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.project.project_id
network = module.vpc[0].name
admin_ranges = [var.vpc_subnet_range]
source = "../../../modules/net-vpc-firewall"
count = local.use_shared_vpc ? 0 : 1
project_id = module.project.project_id
network = module.vpc[0].name
default_rules_config = {
admin_ranges = [var.vpc_subnet_range]
}
}
module "nat" {

View File

@ -76,69 +76,52 @@ module "vpc" {
}
module "firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = local.vpc_project
network = local.network
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
custom_rules = {
source = "../../../modules/net-vpc-firewall"
project_id = local.vpc_project
network = local.network
default_rules_config = {
disabled = true
}
ingress_rules = {
"${local.prefix}allow-all-between-wsfc-nodes" = {
description = "Allow all between WSFC nodes"
direction = "INGRESS"
action = "allow"
sources = [module.compute-service-account.email]
targets = [module.compute-service-account.email]
ranges = []
use_service_accounts = true
rules = [
{ protocol = "tcp", ports = [] },
{ protocol = "udp", ports = [] },
{ protocol = "icmp", ports = [] }
{ protocol = "tcp" },
{ protocol = "udp" },
{ protocol = "icmp" }
]
extra_attributes = {}
}
"${local.prefix}allow-all-between-wsfc-witness" = {
description = "Allow all between WSFC witness nodes"
direction = "INGRESS"
action = "allow"
sources = [module.compute-service-account.email]
targets = [module.witness-service-account.email]
ranges = []
use_service_accounts = true
rules = [
{ protocol = "tcp", ports = [] },
{ protocol = "udp", ports = [] },
{ protocol = "icmp", ports = [] }
{ protocol = "tcp" },
{ protocol = "udp" },
{ protocol = "icmp" }
]
extra_attributes = {}
}
"${local.prefix}allow-sql-to-wsfc-nodes" = {
description = "Allow SQL connections to WSFC nodes"
direction = "INGRESS"
action = "allow"
sources = []
targets = [module.compute-service-account.email]
ranges = var.sql_client_cidrs
use_service_accounts = true
rules = [
{ protocol = "tcp", ports = [1433] },
]
extra_attributes = {}
}
"${local.prefix}allow-health-check-to-wsfc-nodes" = {
description = "Allow health checks to WSFC nodes"
direction = "INGRESS"
action = "allow"
sources = []
targets = [module.compute-service-account.email]
ranges = var.health_check_ranges
use_service_accounts = true
rules = [
{ protocol = "tcp", ports = [] },
{ protocol = "tcp" }
]
extra_attributes = {}
}
}
}

View File

@ -40,36 +40,36 @@ module "firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.host_project.project_id
network = module.svpc.name
custom_rules = merge({ allow-mesh = {
description = "Allow "
direction = "INGRESS"
action = "allow"
sources = []
ranges = [for k, v in var.clusters_config : v.pods_cidr_block]
targets = [for k, v in var.clusters_config : "${k}-node"]
use_service_accounts = false
rules = [{ protocol = "tcp", ports = null },
{ protocol = "udp", ports = null },
{ protocol = "icmp", ports = null },
{ protocol = "esp", ports = null },
{ protocol = "ah", ports = null },
{ protocol = "sctp", ports = null }]
extra_attributes = {
priority = 900
}
} },
{ for k, v in var.clusters_config : "allow-${k}-istio" => {
description = "Allow "
direction = "INGRESS"
action = "allow"
sources = []
ranges = [v.master_cidr_block]
targets = ["${k}-node"]
use_service_accounts = false
rules = [{ protocol = "tcp", ports = [8080, 15014, 15017] }]
extra_attributes = {
priority = 1000
ingress_rules = merge(
{
allow-mesh = {
description = "Allow mesh."
priority = 900
source_ranges = [
for k, v in var.clusters_config : v.pods_cidr_block
]
targets = [
for k, v in var.clusters_config : "${k}-node"
]
rules = [
{ protocol = "tcp" },
{ protocol = "udp" },
{ protocol = "icmp" },
{ protocol = "esp" },
{ protocol = "ah" },
{ protocol = "sctp" }
]
}
},
{
for k, v in var.clusters_config : "allow-${k}-istio" => {
description = "Allow istio."
source_ranges = [v.master_cidr_block]
targets = ["${k}-node"]
rules = [{
protocol = "tcp"
ports = [8080, 15014, 15017]
}]
}
}
)

View File

@ -74,17 +74,18 @@ module "firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project-host.project_id
network = module.vpc.name
custom_rules = {
ingress_rules = {
allow-ingress-squid = {
description = "Allow squid ingress traffic"
direction = "INGRESS"
action = "allow"
sources = []
ranges = [var.cidrs.apps, "35.191.0.0/16", "130.211.0.0/22"]
description = "Allow squid ingress traffic"
source_ranges = [
var.cidrs.apps, "35.191.0.0/16", "130.211.0.0/22"
]
targets = [module.service-account-squid.email]
use_service_accounts = true
rules = [{ protocol = "tcp", ports = [3128] }]
extra_attributes = {}
rules = [{
protocol = "tcp"
ports = [3128]
}]
}
}
}

View File

@ -69,10 +69,12 @@ module "nat-hub" {
}
module "vpc-hub-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.vpc-hub.name
admin_ranges = values(var.ip_ranges)
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.vpc-hub.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
}
}
################################################################################
@ -93,10 +95,12 @@ module "vpc-spoke-1" {
}
module "vpc-spoke-1-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-spoke-1.name
admin_ranges = values(var.ip_ranges)
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-spoke-1.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
}
}
module "nat-spoke-1" {
@ -138,10 +142,12 @@ module "vpc-spoke-2" {
}
module "vpc-spoke-2-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-spoke-2.name
admin_ranges = values(var.ip_ranges)
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-spoke-2.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
}
}
module "nat-spoke-2" {

View File

@ -39,10 +39,12 @@ module "dev-vpc" {
}
module "dev-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.dev-vpc.name
admin_ranges = values(var.ip_ranges)
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.dev-vpc.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
}
}
module "dev-dns-peering" {

View File

@ -39,10 +39,12 @@ module "landing-vpc" {
}
module "landing-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.landing-vpc.name
admin_ranges = values(var.ip_ranges)
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.landing-vpc.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
}
}
module "landing-dns-zone" {

View File

@ -39,10 +39,12 @@ module "prod-vpc" {
}
module "prod-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.prod-vpc.name
admin_ranges = values(var.ip_ranges)
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.prod-vpc.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
}
}
module "prod-dns-peering" {

View File

@ -35,11 +35,13 @@ module "vpc-left" {
}
module "firewall-left" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-left.name
admin_ranges = values(var.ip_ranges)
ssh_source_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"]
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-left.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
ssh_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"]
}
}
module "nat-left" {

View File

@ -46,11 +46,13 @@ module "vpc-right" {
}
module "firewall-right" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-right.name
admin_ranges = values(var.ip_ranges)
ssh_source_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"]
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc-right.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
ssh_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"]
}
}
module "nat-right" {

View File

@ -161,28 +161,22 @@ module "firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc.name
custom_rules = {
ingress_rules = {
format("%sallow-http-to-proxy-cluster", var.prefix) = {
description = "Allow Nginx HTTP(S) ingress traffic"
direction = "INGRESS"
action = "allow"
sources = []
ranges = [var.cidrs[var.subnetwork], "35.191.0.0/16", "130.211.0.0/22"]
description = "Allow Nginx HTTP(S) ingress traffic"
source_ranges = [
var.cidrs[var.subnetwork], "35.191.0.0/16", "130.211.0.0/22"
]
targets = [module.service-account-proxy.email]
use_service_accounts = true
rules = [{ protocol = "tcp", ports = [80, 443] }]
extra_attributes = {}
}
format("%sallow-iap-ssh", var.prefix) = {
description = "Allow Nginx SSH traffic from IAP"
direction = "INGRESS"
action = "allow"
sources = []
ranges = ["35.235.240.0/20"]
source_ranges = ["35.235.240.0/20"]
targets = [module.service-account-proxy.email]
use_service_accounts = true
rules = [{ protocol = "tcp", ports = [22] }]
extra_attributes = {}
}
}
}

View File

@ -69,11 +69,13 @@ module "vpc" {
}
module "vpc-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.vpc.name
admin_ranges = values(var.ip_ranges)
ssh_source_ranges = var.ssh_source_ranges
source = "../../../modules/net-vpc-firewall"
project_id = var.project_id
network = module.vpc.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
ssh_ranges = var.ssh_source_ranges
}
}
module "vpn1" {

View File

@ -130,10 +130,12 @@ module "vpc-shared" {
}
module "vpc-shared-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.project-host.project_id
network = module.vpc-shared.name
admin_ranges = values(var.ip_ranges)
source = "../../../modules/net-vpc-firewall"
project_id = module.project-host.project_id
network = module.vpc-shared.name
default_rules_config = {
admin_ranges = values(var.ip_ranges)
}
}
module "nat" {

View File

@ -12,18 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
map(include('firewall_rule'))
egress: map(include('firewall_rule'), required=False)
ingress: map(include('firewall_rule'), required=False)
---
firewall_rule:
description: str()
direction: enum("INGRESS", "EGRESS")
action: enum("allow", "deny")
sources: list(str())
ranges: list(str())
targets: list(str())
use_service_accounts: bool()
rules: list(include('rule'))
deny: bool(required=False)
description: str(required=False)
destination_ranges: list(str(), required=False)
disabled: bool(required=False)
# enable_logging:
# include_metadata: bool(required=False)
priority: int(required=False)
source_ranges: list(str(), required=False)
sources: list(str(), required=False)
targets: list(str(), required=False)
use_service_accounts: bool(required=False)
rules: list(include('rule'), required=False)
---
rule:
protocol: enum("tcp", "udp", "all")
protocol: str()
ports: list(num())

View File

@ -1,27 +1,21 @@
# skip boilerplate check
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
direction: INGRESS
action: allow
sources:
- composer-worker
targets:
- composer-worker
use_service_accounts: false
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
direction: INGRESS
action: allow
sources:
- dataflow
targets:
- dataflow
use_service_accounts: false
rules:
- protocol: tcp
ports: [12345, 12346]
ingress:
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
sources:
- composer-worker
targets:
- composer-worker
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
sources:
- dataflow
targets:
- dataflow
rules:
- protocol: tcp
ports: [12345, 12346]

View File

@ -1,29 +1,19 @@
# skip boilerplate check
allow-hc-nva-ssh-trusted:
description: "Allow traffic from Google healthchecks to NVA appliances"
direction: INGRESS
action: allow
sources: []
ranges:
- $healthchecks
targets: []
use_service_accounts: false
rules:
- protocol: tcp
ports:
- 22
allow-onprem-probes-trusted-example:
description: "Allow traffic from onprem probes"
direction: INGRESS
action: allow
sources: []
ranges:
- $onprem_probes
targets: []
use_service_accounts: false
rules:
- protocol: tcp
ports:
- 12345
ingress:
allow-hc-nva-ssh-trusted:
description: "Allow traffic from Google healthchecks to NVA appliances"
source_ranges:
- healthchecks
rules:
- protocol: tcp
ports:
- 22
allow-onprem-probes-trusted-example:
description: "Allow traffic from onprem probes"
source_ranges:
- onprem_probes
rules:
- protocol: tcp
ports:
- 12345

View File

@ -1,15 +1,11 @@
# skip boilerplate check
allow-hc-nva-ssh-untrusted:
description: "Allow traffic from Google healthchecks to NVA appliances"
direction: INGRESS
action: allow
sources: []
ranges:
- $healthchecks
targets: []
use_service_accounts: false
rules:
- protocol: tcp
ports:
- 22
ingress:
allow-hc-nva-ssh-untrusted:
description: "Allow traffic from Google healthchecks to NVA appliances"
source_ranges:
- healthchecks
rules:
- protocol: tcp
ports:
- 22

View File

@ -57,15 +57,16 @@ module "landing-untrusted-vpc" {
}
module "landing-untrusted-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-untrusted-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/landing-untrusted"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-untrusted-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/landing-untrusted"
}
}
# NAT
@ -123,13 +124,14 @@ module "landing-trusted-vpc" {
}
module "landing-trusted-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-trusted-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/landing-trusted"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-trusted-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/landing-trusted"
}
}

View File

@ -97,15 +97,16 @@ module "dev-spoke-vpc" {
}
module "dev-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/dev"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/dev"
}
}
module "peering-dev" {

View File

@ -97,15 +97,16 @@ module "prod-spoke-vpc" {
}
module "prod-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/prod"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/prod"
}
}
module "peering-prod" {

View File

@ -1,27 +1,21 @@
# skip boilerplate check
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
direction: INGRESS
action: allow
sources:
- composer-worker
targets:
- composer-worker
use_service_accounts: false
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
direction: INGRESS
action: allow
sources:
- dataflow
targets:
- dataflow
use_service_accounts: false
rules:
- protocol: tcp
ports: [12345, 12346]
ingress:
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
sources:
- composer-worker
targets:
- composer-worker
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
sources:
- dataflow
targets:
- dataflow
rules:
- protocol: tcp
ports: [12345, 12346]

View File

@ -1,15 +1,11 @@
# skip boilerplate check
allow-onprem-probes-example:
description: "Allow traffic from onprem probes"
direction: INGRESS
action: allow
sources: []
ranges:
- $onprem_probes
targets: []
use_service_accounts: false
rules:
- protocol: tcp
ports:
- 12345
ingress:
allow-onprem-probes-example:
description: "Allow traffic from onprem probes"
source_ranges:
- onprem_probes
rules:
- protocol: tcp
ports:
- 12345

View File

@ -67,15 +67,16 @@ module "landing-vpc" {
}
module "landing-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/landing"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/landing"
}
}
module "landing-nat-ew1" {

View File

@ -67,15 +67,16 @@ module "dev-spoke-vpc" {
}
module "dev-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/dev"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/dev"
}
}
module "dev-spoke-cloudnat" {

View File

@ -67,15 +67,16 @@ module "prod-spoke-vpc" {
}
module "prod-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/prod"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/prod"
}
}
module "prod-spoke-cloudnat" {

View File

@ -1,27 +1,17 @@
# skip boilerplate check
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
direction: INGRESS
action: allow
sources: []
ranges: ["0.0.0.0/0"]
targets:
- composer-worker
use_service_accounts: false
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
direction: INGRESS
action: allow
sources: []
ranges: ["0.0.0.0/0"]
targets:
- dataflow
use_service_accounts: false
rules:
- protocol: tcp
ports: [12345, 12346]
ingress:
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
targets:
- composer-worker
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
targets:
- dataflow
rules:
- protocol: tcp
ports: [12345, 12346]

View File

@ -66,15 +66,16 @@ module "dev-spoke-vpc" {
}
module "dev-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/dev"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/dev"
}
}
module "dev-spoke-cloudnat" {

View File

@ -66,15 +66,16 @@ module "prod-spoke-vpc" {
}
module "prod-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/prod"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/prod"
}
}
module "prod-spoke-cloudnat" {

View File

@ -1,27 +1,21 @@
# skip boilerplate check
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
direction: INGRESS
action: allow
sources:
- composer-worker
targets:
- composer-worker
use_service_accounts: false
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
direction: INGRESS
action: allow
sources:
- dataflow
targets:
- dataflow
use_service_accounts: false
rules:
- protocol: tcp
ports: [12345, 12346]
ingress:
ingress-allow-composer-nodes:
description: "Allow traffic to Composer nodes."
sources:
- composer-worker
targets:
- composer-worker
rules:
- protocol: tcp
ports: [80, 443, 3306, 3307]
ingress-allow-dataflow-load:
description: "Allow traffic to Dataflow nodes."
sources:
- dataflow
targets:
- dataflow
rules:
- protocol: tcp
ports: [12345, 12346]

View File

@ -1,15 +1,11 @@
# skip boilerplate check
allow-onprem-probes-example:
description: "Allow traffic from onprem probes"
direction: INGRESS
action: allow
sources: []
ranges:
- $onprem_probes
targets: []
use_service_accounts: false
rules:
- protocol: tcp
ports:
- 12345
ingress:
allow-onprem-probes-example:
description: "Allow traffic from onprem probes"
source_ranges:
- onprem_probes
rules:
- protocol: tcp
ports:
- 12345

View File

@ -67,15 +67,16 @@ module "landing-vpc" {
}
module "landing-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/landing"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.landing-project.project_id
network = module.landing-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/landing"
}
}
module "landing-nat-ew1" {

View File

@ -67,15 +67,16 @@ module "dev-spoke-vpc" {
}
module "dev-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/dev"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.dev-spoke-project.project_id
network = module.dev-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/dev"
}
}
module "dev-spoke-cloudnat" {

View File

@ -67,15 +67,16 @@ module "prod-spoke-vpc" {
}
module "prod-spoke-firewall" {
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
data_folder = "${var.data_dir}/firewall-rules/prod"
cidr_template_file = "${var.data_dir}/cidrs.yaml"
source = "../../../modules/net-vpc-firewall"
project_id = module.prod-spoke-project.project_id
network = module.prod-spoke-vpc.name
default_rules_config = {
disabled = true
}
factories_config = {
cidr_tpl_file = "${var.data_dir}/cidrs.yaml"
rules_folder = "${var.data_dir}/firewall-rules/prod"
}
}
module "prod-spoke-cloudnat" {

View File

@ -178,50 +178,28 @@ module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = module.project.project_id
network = module.vpc.name
custom_rules = {
ingress_rules = {
allow-mesh = {
description = "Allow mesh"
direction = "INGRESS"
action = "allow"
sources = []
ranges = ["10.1.0.0/16", "10.3.0.0/16"]
targets = ["cluster-1-node", "cluster-2-node"]
use_service_accounts = false
rules = [{ protocol = "tcp", ports = null },
{ protocol = "udp", ports = null },
{ protocol = "icmp", ports = null },
{ protocol = "esp", ports = null },
{ protocol = "ah", ports = null },
{ protocol = "sctp", ports = null }]
extra_attributes = {
priority = 900
}
},
description = "Allow mesh"
priority = 900
source_ranges = ["10.1.0.0/16", "10.3.0.0/16"]
targets = ["cluster-1-node", "cluster-2-node"]
},
"allow-cluster-1-istio" = {
description = "Allow istio sidecar injection, istioctl version and istioctl ps"
direction = "INGRESS"
action = "allow"
sources = []
ranges = [ "192.168.1.0/28" ]
targets = ["cluster-1-node"]
use_service_accounts = false
rules = [{ protocol = "tcp", ports = [8080, 15014, 15017] }]
extra_attributes = {
priority = 1000
}
description = "Allow istio sidecar injection, istioctl version and istioctl ps"
source_ranges = ["192.168.1.0/28"]
targets = ["cluster-1-node"]
rules = [
{ protocol = "tcp", ports = [8080, 15014, 15017] }
]
},
"allow-cluster-2-istio" = {
description = "Allow istio sidecar injection, istioctl version and istioctl ps"
direction = "INGRESS"
action = "allow"
sources = []
ranges = [ "192.168.2.0/28" ]
targets = ["cluster-2-node"]
use_service_accounts = false
rules = [{ protocol = "tcp", ports = [8080, 15014, 15017] }]
extra_attributes = {
priority = 1000
}
description = "Allow istio sidecar injection, istioctl version and istioctl ps"
source_ranges = ["192.168.2.0/28"]
targets = ["cluster-2-node"]
rules = [
{ protocol = "tcp", ports = [8080, 15014, 15017] }
]
}
}
}

View File

@ -2,11 +2,10 @@
This module allows creation and management of different types of firewall rules for a single VPC network:
- blanket ingress rules based on IP ranges that allow all traffic via the `admin_ranges` variable
- simplified tag-based ingress rules for the HTTP, HTTPS and SSH protocols via the `xxx_source_ranges` variables; HTTP and HTTPS tags match those set by the console via the "Allow HTTP(S) traffic" instance flags
- custom rules via the `custom_rules` variables
- custom rules via the `egress_rules` and `ingress_rules` variables
- optional predefined rules that simplify prototyping via the `default_rules_config` variable
The simplified tag-based rules are enabled by default, set to the ranges of the GCP health checkers for HTTP/HTTPS, and the IAP forwarders for SSH. To disable them set the corresponding variables to empty lists.
The predefined rules are enabled by default and set to the ranges of the GCP health checkers for HTTP/HTTPS, and the IAP forwarders for SSH. See the relevant section below on how to configure or disable them.
## Examples
@ -16,10 +15,12 @@ This is often useful for prototyping or testing infrastructure, allowing open in
```hcl
module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
admin_ranges = ["10.0.0.0/8"]
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
default_rules_config = {
admin_ranges = ["10.0.0.0/8"]
}
}
# tftest modules=1 resources=4
```
@ -28,68 +29,117 @@ module "firewall" {
This is an example of how to define custom rules, with a sample rule allowing open ingress for the NTP protocol to instances with the `ntp-svc` tag.
```hcl
module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
admin_ranges = ["10.0.0.0/8"]
custom_rules = {
ntp-svc = {
description = "NTP service."
direction = "INGRESS"
action = "allow"
sources = []
ranges = ["0.0.0.0/0"]
targets = ["ntp-svc"]
use_service_accounts = false
rules = [{ protocol = "udp", ports = [123] }]
extra_attributes = {}
}
}
}
# tftest modules=1 resources=5
```
Some implicit defaults are used in the rules variable types and can be controlled by explicitly setting specific attributes:
### No predefined rules
If you don't want any predefined rules set `admin_ranges`, `http_source_ranges`, `https_source_ranges` and `ssh_source_ranges` to an empty list.
- action is controlled via the `deny` attribute which defaults to `true` for egress and `false` for ingress
- priority defaults to `1000`
- destination ranges (for egress) and source ranges (for ingress) default to `["0.0.0.0/0"]` if not explicitly set
- rules default to all protocols if not set
```hcl
module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
admin_ranges = []
http_source_ranges = []
https_source_ranges = []
ssh_source_ranges = []
custom_rules = {
allow-https = {
description = "Allow HTTPS from internal networks."
direction = "INGRESS"
action = "allow"
sources = []
ranges = ["rfc1918"]
targets = []
use_service_accounts = false
rules = [{ protocol = "tcp", ports = [443] }]
extra_attributes = {}
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
default_rules_config = {
admin_ranges = ["10.0.0.0/8"]
}
egress_rules = {
# implicit `deny` action
allow-egress-rfc1918 = {
description = "Allow egress to RFC 1918 ranges."
destination_ranges = [
"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"
]
# implicit { protocol = "all" } rule
}
deny-egress-all = {
description = "Block egress."
# implicit ["0.0.0.0/0"] destination ranges
# implicit { protocol = "all" } rule
}
}
ingress_rules = {
# implicit `allow` action
allow-ingress-ntp = {
description = "Allow NTP service based on tag."
source_ranges = ["0.0.0.0/0"]
targets = ["ntp-svc"]
rules = [{ protocol = "udp", ports = [123] }]
}
}
}
# tftest modules=1 resources=1
# tftest modules=1 resources=7
```
### Controlling or turning off default rules
Predefined rules can be controlled or turned off via the `default_rules_config` variable.
#### Overriding default tags and ranges
Each protocol rule has a default set of tags and ranges:
- the health check range and the `http-server`/`https-server` tag for HTTP/HTTPS, matching tags set via GCP console flags on GCE instances
- the IAP forwarders range and `ssh` tag for SSH
Default tags and ranges can be overridden for each protocol, like shown here for SSH:
```hcl
module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
default_rules_config = {
ssh_ranges = ["10.0.0.0/8"]
ssh_rags = ["ssh-default"]
}
}
# tftest modules=1 resources=3
```
#### Disabling predefined rules
Default rules can be disabled individually by specifying an empty set of ranges:
```hcl
module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
default_rules_config = {
ssh_ranges = []
}
}
# tftest modules=1 resources=2
```
Or the entire set of rules can be disabled via the `disabled` attribute:
```hcl
module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
default_rules_config = {
disabled = true
}
}
# tftest modules=0 resources=0
```
### Rules Factory
The module includes a rules factory (see [Resource Factories](../../blueprints/factories/)) for the massive creation of rules leveraging YaML configuration files. Each configuration file can optionally contain more than one rule which a structure that reflects the `custom_rules` variable.
```hcl
module "firewall" {
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
source = "./fabric/modules/net-vpc-firewall"
project_id = "my-project"
network = "my-network"
factories_config = {
}
data_folder = "config/firewall"
cidr_template_file = "config/cidr_template.yaml"
}
@ -100,13 +150,9 @@ module "firewall" {
# ./config/firewall/load_balancers.yaml
allow-healthchecks:
description: Allow ingress from healthchecks.
direction: INGRESS
action: allow
sources: []
ranges:
- $healthchecks
- healthchecks
targets: ["lb-backends"]
use_service_accounts: false
rules:
- protocol: tcp
ports:
@ -129,26 +175,19 @@ healthchecks:
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [network](variables.tf#L80) | Name of the network this set of firewall rules applies to. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L85) | Project id of the project that holds the network. | <code>string</code> | ✓ | |
| [admin_ranges](variables.tf#L17) | IP CIDR ranges that have complete access to all subnets. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [cidr_template_file](variables.tf#L23) | Path for optional file containing name->cidr_list map to be used by the rules factory. | <code>string</code> | | <code>null</code> |
| [custom_rules](variables.tf#L29) | List of custom rule definitions (refer to variables file for syntax). | <code title="map&#40;object&#40;&#123;&#10; description &#61; string&#10; direction &#61; string&#10; action &#61; string &#35; &#40;allow&#124;deny&#41;&#10; ranges &#61; list&#40;string&#41;&#10; sources &#61; list&#40;string&#41;&#10; targets &#61; list&#40;string&#41;&#10; use_service_accounts &#61; bool&#10; rules &#61; list&#40;object&#40;&#123;&#10; protocol &#61; string&#10; ports &#61; list&#40;string&#41;&#10; &#125;&#41;&#41;&#10; extra_attributes &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [data_folder](variables.tf#L48) | Path for optional folder containing firewall rules defined as YaML objects used by the rules factory. | <code>string</code> | | <code>null</code> |
| [http_source_ranges](variables.tf#L54) | List of IP CIDR ranges for tag-based HTTP rule, defaults to the health checkers ranges. | <code>list&#40;string&#41;</code> | | <code>&#91;&#34;35.191.0.0&#47;16&#34;, &#34;130.211.0.0&#47;22&#34;, &#34;209.85.152.0&#47;22&#34;, &#34;209.85.204.0&#47;22&#34;&#93;</code> |
| [https_source_ranges](variables.tf#L60) | List of IP CIDR ranges for tag-based HTTPS rule, defaults to the health checkers ranges. | <code>list&#40;string&#41;</code> | | <code>&#91;&#34;35.191.0.0&#47;16&#34;, &#34;130.211.0.0&#47;22&#34;, &#34;209.85.152.0&#47;22&#34;, &#34;209.85.204.0&#47;22&#34;&#93;</code> |
| [named_ranges](variables.tf#L66) | Names that can be used of valid values for the `ranges` field of `custom_rules`. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code title="&#123;&#10; any &#61; &#91;&#34;0.0.0.0&#47;0&#34;&#93;&#10; dns-forwarders &#61; &#91;&#34;35.199.192.0&#47;19&#34;&#93;&#10; health-checkers &#61; &#91;&#34;35.191.0.0&#47;16&#34;, &#34;130.211.0.0&#47;22&#34;, &#34;209.85.152.0&#47;22&#34;, &#34;209.85.204.0&#47;22&#34;&#93;&#10; iap-forwarders &#61; &#91;&#34;35.235.240.0&#47;20&#34;&#93;&#10; private-googleapis &#61; &#91;&#34;199.36.153.8&#47;30&#34;&#93;&#10; restricted-googleapis &#61; &#91;&#34;199.36.153.4&#47;30&#34;&#93;&#10; rfc1918 &#61; &#91;&#34;10.0.0.0&#47;8&#34;, &#34;172.16.0.0&#47;12&#34;, &#34;192.168.0.0&#47;16&#34;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [ssh_source_ranges](variables.tf#L90) | List of IP CIDR ranges for tag-based SSH rule, defaults to the IAP forwarders range. | <code>list&#40;string&#41;</code> | | <code>&#91;&#34;35.235.240.0&#47;20&#34;&#93;</code> |
| [network](variables.tf#L109) | Name of the network this set of firewall rules applies to. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L114) | Project id of the project that holds the network. | <code>string</code> | ✓ | |
| [default_rules_config](variables.tf#L17) | Optionally created convenience rules. Set the variable or individual members to null to disable. | <code title="object&#40;&#123;&#10; admin_ranges &#61; optional&#40;list&#40;string&#41;&#41;&#10; disabled &#61; optional&#40;bool, false&#41;&#10; http_ranges &#61; optional&#40;list&#40;string&#41;, &#91;&#10; &#34;35.191.0.0&#47;16&#34;, &#34;130.211.0.0&#47;22&#34;, &#34;209.85.152.0&#47;22&#34;, &#34;209.85.204.0&#47;22&#34;&#93;&#10; &#41;&#10; http_tags &#61; optional&#40;list&#40;string&#41;, &#91;&#34;http-server&#34;&#93;&#41;&#10; https_ranges &#61; optional&#40;list&#40;string&#41;, &#91;&#10; &#34;35.191.0.0&#47;16&#34;, &#34;130.211.0.0&#47;22&#34;, &#34;209.85.152.0&#47;22&#34;, &#34;209.85.204.0&#47;22&#34;&#93;&#10; &#41;&#10; https_tags &#61; optional&#40;list&#40;string&#41;, &#91;&#34;https-server&#34;&#93;&#41;&#10; ssh_ranges &#61; optional&#40;list&#40;string&#41;, &#91;&#34;35.235.240.0&#47;20&#34;&#93;&#41;&#10; ssh_tags &#61; optional&#40;list&#40;string&#41;, &#91;&#34;ssh&#34;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [egress_rules](variables.tf#L37) | List of egress rule definitions, default to deny action. | <code title="map&#40;object&#40;&#123;&#10; deny &#61; optional&#40;bool, true&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination_ranges &#61; optional&#40;list&#40;string&#41;&#41;&#10; disabled &#61; optional&#40;bool, false&#41;&#10; enable_logging &#61; optional&#40;object&#40;&#123;&#10; include_metadata &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; priority &#61; optional&#40;number, 1000&#41;&#10; sources &#61; optional&#40;list&#40;string&#41;&#41;&#10; targets &#61; optional&#40;list&#40;string&#41;&#41;&#10; use_service_accounts &#61; optional&#40;bool, false&#41;&#10; rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; protocol &#61; string&#10; ports &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;, &#91;&#123; protocol &#61; &#34;all&#34; &#125;&#93;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [factories_config](variables.tf#L83) | Paths to data files and folders that enable factory functionality. | <code title="object&#40;&#123;&#10; cidr_tpl_file &#61; optional&#40;string&#41;&#10; rules_folder &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [ingress_rules](variables.tf#L60) | List of ingress rule definitions, default to allow action. | <code title="map&#40;object&#40;&#123;&#10; deny &#61; optional&#40;bool, false&#41;&#10; description &#61; optional&#40;string&#41;&#10; disabled &#61; optional&#40;bool, false&#41;&#10; enable_logging &#61; optional&#40;object&#40;&#123;&#10; include_metadata &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; priority &#61; optional&#40;number, 1000&#41;&#10; source_ranges &#61; optional&#40;list&#40;string&#41;&#41;&#10; sources &#61; optional&#40;list&#40;string&#41;&#41;&#10; targets &#61; optional&#40;list&#40;string&#41;&#41;&#10; use_service_accounts &#61; optional&#40;bool, false&#41;&#10; rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; protocol &#61; string&#10; ports &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;, &#91;&#123; protocol &#61; &#34;all&#34; &#125;&#93;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [named_ranges](variables.tf#L92) | Define mapping of names to ranges that can be used in custom rules. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code title="&#123;&#10; any &#61; &#91;&#34;0.0.0.0&#47;0&#34;&#93;&#10; dns-forwarders &#61; &#91;&#34;35.199.192.0&#47;19&#34;&#93;&#10; health-checkers &#61; &#91;&#10; &#34;35.191.0.0&#47;16&#34;, &#34;130.211.0.0&#47;22&#34;, &#34;209.85.152.0&#47;22&#34;, &#34;209.85.204.0&#47;22&#34;&#10; &#93;&#10; iap-forwarders &#61; &#91;&#34;35.235.240.0&#47;20&#34;&#93;&#10; private-googleapis &#61; &#91;&#34;199.36.153.8&#47;30&#34;&#93;&#10; restricted-googleapis &#61; &#91;&#34;199.36.153.4&#47;30&#34;&#93;&#10; rfc1918 &#61; &#91;&#34;10.0.0.0&#47;8&#34;, &#34;172.16.0.0&#47;12&#34;, &#34;192.168.0.0&#47;16&#34;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| [admin_ranges](outputs.tf#L17) | Admin ranges data. | |
| [custom_egress_allow_rules](outputs.tf#L26) | Custom egress rules with allow blocks. | |
| [custom_egress_deny_rules](outputs.tf#L34) | Custom egress rules with allow blocks. | |
| [custom_ingress_allow_rules](outputs.tf#L42) | Custom ingress rules with allow blocks. | |
| [custom_ingress_deny_rules](outputs.tf#L50) | Custom ingress rules with deny blocks. | |
| [rules](outputs.tf#L58) | All google_compute_firewall resources created. | |
| [default_rules](outputs.tf#L17) | Default rule resources. | |
| [rules](outputs.tf#L27) | Custom rule resources. | |
<!-- END TFDOC -->

View File

@ -0,0 +1,77 @@
/**
* 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
*
* 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.
*/
# tfdoc:file:description Optional default rule resources.
locals {
default_rules = {
for k, v in var.default_rules_config :
k => var.default_rules_config.disabled == true || v == null ? [] : v
if k != "disabled"
}
}
resource "google_compute_firewall" "allow-admins" {
count = length(local.default_rules.admin_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-admins"
description = "Access from the admin subnet to all subnets."
network = var.network
project = var.project_id
source_ranges = local.default_rules.admin_ranges
allow { protocol = "all" }
}
resource "google_compute_firewall" "allow-tag-http" {
count = length(local.default_rules.http_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-tag-http"
description = "Allow http to machines with matching tags."
network = var.network
project = var.project_id
source_ranges = local.default_rules.http_ranges
target_tags = local.default_rules.http_tags
allow {
protocol = "tcp"
ports = ["80"]
}
}
resource "google_compute_firewall" "allow-tag-https" {
count = length(local.default_rules.https_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-tag-https"
description = "Allow http to machines with matching tags."
network = var.network
project = var.project_id
source_ranges = local.default_rules.https_ranges
target_tags = local.default_rules.https_tags
allow {
protocol = "tcp"
ports = ["443"]
}
}
resource "google_compute_firewall" "allow-tag-ssh" {
count = length(local.default_rules.ssh_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-tag-ssh"
description = "Allow SSH to machines with matching tags."
network = var.network
project = var.project_id
source_ranges = local.default_rules.ssh_ranges
target_tags = local.default_rules.ssh_tags
allow {
protocol = "tcp"
ports = ["22"]
}
}

View File

@ -15,149 +15,125 @@
*/
locals {
_custom_rules = {
for id, rule in var.custom_rules :
id => merge(rule, {
# make rules a map so we use it in a for_each
rules = { for index, ports in rule.rules : index => ports }
# lookup any named ranges references
ranges = flatten([
for range in rule.ranges :
try(var.named_ranges[range], range)
# define list of rule files
_factory_rule_files = [
for f in try(fileset(var.factories_config.rules_folder, "**/*.yaml"), []) :
"${var.factories_config.rules_folder}/${f}"
]
# decode rule files and account for optional attributes
_factory_rule_list = flatten([
for f in local._factory_rule_files : [
for direction, ruleset in yamldecode(file(f)) : [
for name, rule in ruleset : {
name = name
deny = try(rule.deny, false)
rules = try(rule.rules, [{ protocol = "all" }])
description = try(rule.description, null)
destination_ranges = try(rule.destination_ranges, null)
direction = upper(direction)
disabled = try(rule.disabled, null)
enable_logging = try(rule.enable_logging, null)
priority = try(rule.priority, 1000)
source_ranges = try(rule.source_ranges, null)
sources = try(rule.sources, null)
targets = try(rule.targets, null)
use_service_accounts = try(rule.use_service_accounts, false)
}
]
]
])
_factory_rules = {
for r in local._factory_rule_list : r.name => r
if contains(["EGRESS", "INGRESS"], r.direction)
}
_named_ranges = merge(
try(yamldecode(file(var.factories_config.cidr_tpl_file)), {}),
var.named_ranges
)
_rules = merge(
local._factory_rules, 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" })
}
# convert rules data to resource format and replace range template variables
rules = {
for name, rule in local._rules :
name => merge(rule, {
action = rule.deny == true ? "DENY" : "ALLOW"
destination_ranges = flatten([
for range in coalesce(try(rule.destination_ranges, null), []) :
try(local._named_ranges[range], range)
])
rules = { for k, v in rule.rules : k => v }
source_ranges = flatten([
for range in coalesce(try(rule.source_ranges, null), []) :
try(local._named_ranges[range], range)
])
})
}
cidrs = try({
for name, cidrs in yamldecode(file(var.cidr_template_file)) :
name => cidrs
}, {})
_factory_rules_raw = flatten([
for file in try(fileset(var.data_folder, "**/*.yaml"), []) : [
for key, ruleset in yamldecode(file("${var.data_folder}/${file}")) :
merge(ruleset, {
name = "${key}"
rules = { for index, ports in ruleset.rules : index => ports }
ranges = try(ruleset.ranges, null) == null ? null : flatten(
[for cidr in ruleset.ranges :
can(regex("^\\$", cidr))
? local.cidrs[trimprefix(cidr, "$")]
: [cidr]
])
extra_attributes = try(ruleset.extra_attributes, {})
})
]
])
_factory_rules = {
for d in local._factory_rules_raw : d["name"] => d
}
custom_rules = merge(local._custom_rules, local._factory_rules)
}
###############################################################################
# rules based on IP ranges
###############################################################################
resource "google_compute_firewall" "allow-admins" {
count = length(var.admin_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-admins"
description = "Access from the admin subnet to all subnets"
network = var.network
project = var.project_id
source_ranges = var.admin_ranges
allow { protocol = "all" }
}
###############################################################################
# rules based on tags
###############################################################################
resource "google_compute_firewall" "allow-tag-ssh" {
count = length(var.ssh_source_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-tag-ssh"
description = "Allow SSH to machines with the 'ssh' tag"
network = var.network
project = var.project_id
source_ranges = var.ssh_source_ranges
target_tags = ["ssh"]
allow {
protocol = "tcp"
ports = ["22"]
}
}
resource "google_compute_firewall" "allow-tag-http" {
count = length(var.http_source_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-tag-http"
description = "Allow HTTP to machines with the 'http-server' tag"
network = var.network
project = var.project_id
source_ranges = var.http_source_ranges
target_tags = ["http-server"]
allow {
protocol = "tcp"
ports = ["80"]
}
}
resource "google_compute_firewall" "allow-tag-https" {
count = length(var.https_source_ranges) > 0 ? 1 : 0
name = "${var.network}-ingress-tag-https"
description = "Allow HTTPS to machines with the 'https' tag"
network = var.network
project = var.project_id
source_ranges = var.https_source_ranges
target_tags = ["https-server"]
allow {
protocol = "tcp"
ports = ["443"]
}
}
################################################################################
# dynamic rules #
################################################################################
resource "google_compute_firewall" "custom-rules" {
# provider = "google-beta"
for_each = local.custom_rules
for_each = local.rules
project = var.project_id
network = var.network
name = each.key
description = each.value.description
direction = each.value.direction
network = var.network
project = var.project_id
source_ranges = (
each.value.direction == "INGRESS"
? coalesce(each.value.ranges, []) == [] ? ["0.0.0.0/0"] : each.value.ranges
: null
? (
coalesce(each.value.source_ranges, []) == []
? ["0.0.0.0/0"]
: each.value.source_ranges
) : null
)
destination_ranges = (
each.value.direction == "EGRESS"
? coalesce(each.value.ranges, []) == [] ? ["0.0.0.0/0"] : each.value.ranges
? (
coalesce(each.value.destination_ranges, []) == []
? ["0.0.0.0/0"]
: each.value.destination_ranges
) : null
)
source_tags = (
each.value.use_service_accounts || each.value.direction == "EGRESS"
? null
: each.value.sources
)
source_service_accounts = (
each.value.use_service_accounts && each.value.direction == "INGRESS"
? each.value.sources
: null
)
source_tags = each.value.use_service_accounts || each.value.direction == "EGRESS" ? null : each.value.sources
source_service_accounts = each.value.use_service_accounts && each.value.direction == "INGRESS" ? each.value.sources : null
target_tags = each.value.use_service_accounts ? null : each.value.targets
target_service_accounts = each.value.use_service_accounts ? each.value.targets : null
disabled = lookup(each.value.extra_attributes, "disabled", false)
priority = lookup(each.value.extra_attributes, "priority", 1000)
target_tags = (
each.value.use_service_accounts ? null : each.value.targets
)
target_service_accounts = (
each.value.use_service_accounts ? each.value.targets : null
)
disabled = each.value.disabled == true
priority = each.value.priority
dynamic "log_config" {
for_each = lookup(each.value.extra_attributes, "logging", null) != null ? [each.value.extra_attributes.logging] : []
iterator = logging_config
for_each = each.value.enable_logging == null ? [] : [""]
content {
metadata = logging_config.value
metadata = (
try(each.value.enable_logging.include_metadata, null) == true
? "INCLUDE_ALL_METADATA"
: "EXCLUDE_ALL_METADATA"
)
}
}
dynamic "deny" {
for_each = each.value.action == "deny" ? each.value.rules : {}
for_each = each.value.action == "DENY" ? each.value.rules : {}
iterator = rule
content {
protocol = rule.value.protocol
@ -166,8 +142,7 @@ resource "google_compute_firewall" "custom-rules" {
}
dynamic "allow" {
for_each = each.value.action == "allow" ? each.value.rules : {}
for_each = each.value.action == "ALLOW" ? each.value.rules : {}
iterator = rule
content {
protocol = rule.value.protocol

View File

@ -14,54 +14,17 @@
* limitations under the License.
*/
output "admin_ranges" {
description = "Admin ranges data."
output "default_rules" {
description = "Default rule resources."
value = {
enabled = length(var.admin_ranges) > 0
ranges = join(",", var.admin_ranges)
admin = try(google_compute_firewall.allow-admins, null)
http = try(google_compute_firewall.allow-tag-http, null)
https = try(google_compute_firewall.allow-tag-https, null)
ssh = try(google_compute_firewall.allow-tag-ssh, null)
}
}
output "custom_egress_allow_rules" {
description = "Custom egress rules with allow blocks."
value = [
for rule in google_compute_firewall.custom-rules :
rule.name if rule.direction == "EGRESS" && try(length(rule.allow), 0) > 0
]
}
output "custom_egress_deny_rules" {
description = "Custom egress rules with allow blocks."
value = [
for rule in google_compute_firewall.custom-rules :
rule.name if rule.direction == "EGRESS" && try(length(rule.deny), 0) > 0
]
}
output "custom_ingress_allow_rules" {
description = "Custom ingress rules with allow blocks."
value = [
for rule in google_compute_firewall.custom-rules :
rule.name if rule.direction == "INGRESS" && try(length(rule.allow), 0) > 0
]
}
output "custom_ingress_deny_rules" {
description = "Custom ingress rules with deny blocks."
value = [
for rule in google_compute_firewall.custom-rules :
rule.name if rule.direction == "INGRESS" && try(length(rule.deny), 0) > 0
]
}
output "rules" {
description = "All google_compute_firewall resources created."
value = merge(
google_compute_firewall.custom-rules,
try({ (google_compute_firewall.allow-admins.0.name) = google_compute_firewall.allow-admins.0 }, {}),
try({ (google_compute_firewall.allow-tag-ssh.0.name) = google_compute_firewall.allow-tag-ssh.0 }, {}),
try({ (google_compute_firewall.allow-tag-http.0.name) = google_compute_firewall.allow-tag-http.0 }, {}),
try({ (google_compute_firewall.allow-tag-https.0.name) = google_compute_firewall.allow-tag-https.0 }, {})
)
description = "Custom rule resources."
value = google_compute_firewall.custom-rules
}

View File

@ -14,67 +14,96 @@
* limitations under the License.
*/
variable "admin_ranges" {
description = "IP CIDR ranges that have complete access to all subnets."
type = list(string)
default = []
variable "default_rules_config" {
description = "Optionally created convenience rules. Set the variable or individual members to null to disable."
type = object({
admin_ranges = optional(list(string))
disabled = optional(bool, false)
http_ranges = optional(list(string), [
"35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
)
http_tags = optional(list(string), ["http-server"])
https_ranges = optional(list(string), [
"35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
)
https_tags = optional(list(string), ["https-server"])
ssh_ranges = optional(list(string), ["35.235.240.0/20"])
ssh_tags = optional(list(string), ["ssh"])
})
default = {}
nullable = false
}
variable "cidr_template_file" {
description = "Path for optional file containing name->cidr_list map to be used by the rules factory."
type = string
default = null
}
variable "custom_rules" {
description = "List of custom rule definitions (refer to variables file for syntax)."
variable "egress_rules" {
description = "List of egress rule definitions, default to deny action."
type = map(object({
description = string
direction = string
action = string # (allow|deny)
ranges = list(string)
sources = list(string)
targets = list(string)
use_service_accounts = bool
rules = list(object({
protocol = string
ports = list(string)
deny = optional(bool, true)
description = optional(string)
destination_ranges = optional(list(string))
disabled = optional(bool, false)
enable_logging = optional(object({
include_metadata = optional(bool)
}))
extra_attributes = map(string)
priority = optional(number, 1000)
sources = optional(list(string))
targets = optional(list(string))
use_service_accounts = optional(bool, false)
rules = optional(list(object({
protocol = string
ports = optional(list(string))
})), [{ protocol = "all" }])
}))
default = {}
default = {}
nullable = false
}
variable "data_folder" {
description = "Path for optional folder containing firewall rules defined as YaML objects used by the rules factory."
type = string
default = null
variable "ingress_rules" {
description = "List of ingress rule definitions, default to allow action."
type = map(object({
deny = optional(bool, false)
description = optional(string)
disabled = optional(bool, false)
enable_logging = optional(object({
include_metadata = optional(bool)
}))
priority = optional(number, 1000)
source_ranges = optional(list(string))
sources = optional(list(string))
targets = optional(list(string))
use_service_accounts = optional(bool, false)
rules = optional(list(object({
protocol = string
ports = optional(list(string))
})), [{ protocol = "all" }])
}))
default = {}
nullable = false
}
variable "http_source_ranges" {
description = "List of IP CIDR ranges for tag-based HTTP rule, defaults to the health checkers ranges."
type = list(string)
default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
}
variable "https_source_ranges" {
description = "List of IP CIDR ranges for tag-based HTTPS rule, defaults to the health checkers ranges."
type = list(string)
default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
variable "factories_config" {
description = "Paths to data files and folders that enable factory functionality."
type = object({
cidr_tpl_file = optional(string)
rules_folder = string
})
default = null
}
variable "named_ranges" {
description = "Names that can be used of valid values for the `ranges` field of `custom_rules`."
description = "Define mapping of names to ranges that can be used in custom rules."
type = map(list(string))
default = {
any = ["0.0.0.0/0"]
dns-forwarders = ["35.199.192.0/19"]
health-checkers = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
any = ["0.0.0.0/0"]
dns-forwarders = ["35.199.192.0/19"]
health-checkers = [
"35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"
]
iap-forwarders = ["35.235.240.0/20"]
private-googleapis = ["199.36.153.8/30"]
restricted-googleapis = ["199.36.153.4/30"]
rfc1918 = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
}
nullable = false
}
variable "network" {
@ -86,10 +115,3 @@ variable "project_id" {
description = "Project id of the project that holds the network."
type = string
}
variable "ssh_source_ranges" {
description = "List of IP CIDR ranges for tag-based SSH rule, defaults to the IAP forwarders range."
type = list(string)
default = ["35.235.240.0/20"]
}

View File

@ -14,12 +14,11 @@
import os
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 4
assert len(resources) == 18
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 4
assert len(resources) == 20

View File

@ -28,8 +28,8 @@ BASEDIR = os.path.dirname(os.path.dirname(__file__))
def _plan_runner():
"Returns a function to run Terraform plan on a fixture."
def run_plan(fixture_path=None, targets=None, refresh=True, tmpdir=True,
**tf_vars):
def run_plan(fixture_path=None, extra_files=None, tf_var_file=None,
targets=None, refresh=True, tmpdir=True, **tf_vars):
"Runs Terraform plan and returns parsed output."
if fixture_path is None:
# find out the fixture directory from the caller's directory
@ -46,9 +46,9 @@ def _plan_runner():
shutil.copytree(fixture_path, tmp_path, dirs_exist_ok=True)
tf = tftest.TerraformTest(tmp_path if tmpdir else fixture_path, BASEDIR,
os.environ.get('TERRAFORM', 'terraform'))
tf.setup(upgrade=True)
plan = tf.plan(output=True, refresh=refresh, tf_vars=tf_vars,
targets=targets)
tf.setup(extra_files=extra_files, upgrade=True)
plan = tf.plan(output=True, refresh=refresh, tf_var_file=tf_var_file,
tf_vars=tf_vars, targets=targets)
return plan
return run_plan
@ -58,9 +58,11 @@ def _plan_runner():
def plan_runner(_plan_runner):
"Returns a function to run Terraform plan on a module fixture."
def run_plan(fixture_path=None, targets=None, **tf_vars):
def run_plan(fixture_path=None, extra_files=None, tf_var_file=None,
targets=None, **tf_vars):
"Runs Terraform plan and returns plan and module resources."
plan = _plan_runner(fixture_path, targets=targets, **tf_vars)
plan = _plan_runner(fixture_path, extra_files=extra_files,
tf_var_file=tf_var_file, targets=targets, **tf_vars)
# skip the fixture
root_module = plan.root_module['child_modules'][0]
return plan, root_module['resources']

View File

@ -12,17 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
allow-healthchecks:
description: Allow ingress from healthchecks.
direction: INGRESS
action: allow
sources: []
ranges:
- $healthchecks
targets: ["lb-backends"]
use_service_accounts: false
rules:
- protocol: tcp
ports:
- 80
- 443
ingress:
allow-healthchecks:
description: Allow ingress from healthchecks.
source_ranges:
- healthchecks
targets: ["lb-backends"]
rules:
- protocol: tcp
ports:
- 80
- 443

View File

@ -15,14 +15,11 @@
*/
module "firewall" {
source = "../../../../modules/net-vpc-firewall"
project_id = var.project_id
network = var.network
admin_ranges = var.admin_ranges
http_source_ranges = var.http_source_ranges
https_source_ranges = var.https_source_ranges
ssh_source_ranges = var.ssh_source_ranges
custom_rules = var.custom_rules
data_folder = var.data_folder
cidr_template_file = var.cidr_template_file
source = "../../../../modules/net-vpc-firewall"
project_id = "test-project"
network = "test-vpc"
default_rules_config = var.default_rules_config
egress_rules = var.egress_rules
ingress_rules = var.ingress_rules
factories_config = var.factories_config
}

View File

@ -0,0 +1,22 @@
egress_rules = {
allow-egress-rfc1918 = {
description = "Allow egress to RFC 1918 ranges."
is_egress = true
destination_ranges = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
}
deny-egress-all = {
description = "Block egress."
is_deny = true
is_egress = true
}
}
ingress_rules = {
allow-ingress-ntp = {
description = "Allow NTP service based on tag."
targets = ["ntp-svc"]
rules = [{ protocol = "udp", ports = [123] }]
}
}
default_rules_config = {
disabled = true
}

View File

@ -14,84 +14,38 @@
* limitations under the License.
*/
variable "admin_ranges" {
description = "IP CIDR ranges that have complete access to all subnets."
type = list(string)
default = []
}
/**
* 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
*
* 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 "cidr_template_file" {
description = "Path for optional file containing name->cidr_list map to be used by the rules factory."
type = string
default = null
}
variable "custom_rules" {
description = "List of custom rule definitions (refer to variables file for syntax)."
type = map(object({
description = string
direction = string
action = string # (allow|deny)
ranges = list(string)
sources = list(string)
targets = list(string)
use_service_accounts = bool
rules = list(object({
protocol = string
ports = list(string)
}))
extra_attributes = map(string)
}))
variable "default_rules_config" {
type = any
default = {}
}
variable "data_folder" {
description = "Path for optional folder containing firewall rules defined as YaML objects used by the rules factory."
type = string
default = null
variable "egress_rules" {
type = any
default = {}
}
variable "http_source_ranges" {
description = "List of IP CIDR ranges for tag-based HTTP rule, defaults to the health checkers ranges."
type = list(string)
default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
variable "factories_config" {
type = any
default = null
}
variable "https_source_ranges" {
description = "List of IP CIDR ranges for tag-based HTTPS rule, defaults to the health checkers ranges."
type = list(string)
default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
variable "ingress_rules" {
type = any
default = {}
}
variable "named_ranges" {
description = "Names that can be used of valid values for the `ranges` field of `custom_rules`."
type = map(list(string))
default = {
any = ["0.0.0.0/0"]
dns-forwarders = ["35.199.192.0/19"]
health-checkers = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"]
iap-forwarders = ["35.235.240.0/20"]
private-googleapis = ["199.36.153.8/30"]
restricted-googleapis = ["199.36.153.4/30"]
rfc1918 = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
}
}
variable "network" {
description = "Name of the network this set of firewall rules applies to."
type = string
default = "vpc"
}
variable "project_id" {
description = "Project id of the project that holds the network."
type = string
default = "project"
}
variable "ssh_source_ranges" {
description = "List of IP CIDR ranges for tag-based SSH rule, defaults to the IAP forwarders range."
type = list(string)
default = ["35.235.240.0/20"]
}

View File

@ -12,27 +12,48 @@
# See the License for the specific language governing permissions and
# limitations under the License.
def test_vpc_firewall_simple(plan_runner):
"Test vpc with no extra options."
import pytest
def test_defaults(plan_runner):
"Test variable defaults."
_, resources = plan_runner()
assert len(resources) == 3
assert set([r['type'] for r in resources]) == set(
['google_compute_firewall'])
assert set([r['values']['name'] for r in resources]) == set(
['vpc-ingress-tag-http', 'vpc-ingress-tag-https', 'vpc-ingress-tag-ssh'])
assert set([r['values']['project'] for r in resources]) == set(['project'])
assert set([r['values']['network'] for r in resources]) == set(['vpc'])
assert set([r['type'] for r in resources]) == set(['google_compute_firewall'])
assert set([r['values']['name'] for r in resources]) == set([
'test-vpc-ingress-tag-http', 'test-vpc-ingress-tag-https',
'test-vpc-ingress-tag-ssh'
])
assert set([r['values']['project'] for r in resources
]) == set(['test-project'])
assert set([r['values']['network'] for r in resources]) == set(['test-vpc'])
def test_vpc_firewall_factory(plan_runner):
"Test shared vpc variables."
_, resources = plan_runner(
data_folder="config/firewall",
cidr_template_file="config/cidr_template.yaml"
)
def test_rules(plan_runner):
"Test custom rules."
tfvars = 'test.rules.tfvars'
_, resources = plan_runner(extra_files=[tfvars], tf_var_file=tfvars)
assert len(resources) == 3
rules = {r['index']: r['values'] for r in resources}
rule = rules['allow-ingress-ntp']
assert rule['source_ranges'] == ['0.0.0.0/0']
assert rule['allow'] == [{'ports': ['123'], 'protocol': 'udp'}]
rule = rules['deny-egress-all']
assert rule['destination_ranges'] == ['0.0.0.0/0']
assert rule['deny'] == [{'ports': [], 'protocol': 'all'}]
def test_factory(plan_runner):
"Test factory."
factories_config = '''{
cidr_tpl_file = "config/cidr_template.yaml"
rules_folder = "config/firewall"
}'''
_, resources = plan_runner(factories_config=factories_config)
assert len(resources) == 4
factory_rule = [r for r in resources if r["values"]
["name"] == "allow-healthchecks"][0]["values"]
factory_rule = [
r for r in resources if r["values"]["name"] == "allow-healthchecks"
][0]["values"]
assert set(factory_rule["source_ranges"]) == set(
["130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22", "35.191.0.0/16"])
assert set(factory_rule["target_tags"]) == set(["lb-backends"])