feat: Decenrtalized firewall management example added.

This commit is contained in:
averbukh 2021-07-26 09:22:40 +02:00
parent 1c6707b982
commit c0aab69bb7
19 changed files with 528 additions and 26 deletions

View File

@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
- add support for VPC-SC perimeters in Data Foundation end to end example
- fix `vpc-sc` module
- new networking example showing how to use [Private Service Connect to call a Cloud Function from on-premises](networking/private-cloud-function-from-onprem/)
- new networking example showing how to organize [decentralized firewall](networking/decentralized-firewall/) management on GCP
## [5.0.0] - 2021-06-17

View File

@ -17,7 +17,7 @@ The examples in this repository are split in several main sections: **foundation
Currently available examples:
- **foundations** - [single level hierarchy](./foundations/environments/) (environments), [multiple level hierarchy](./foundations/business-units/) (business units + environments)
- **networking** - [hub and spoke via peering](./networking/hub-and-spoke-peering/), [hub and spoke via VPN](./networking/hub-and-spoke-vpn/), [DNS and Google Private Access for on-premises](./networking/onprem-google-access-dns/), [Shared VPC with GKE support](./networking/shared-vpc-gke/), [ILB as next hop](./networking/ilb-next-hop)
- **networking** - [hub and spoke via peering](./networking/hub-and-spoke-peering/), [hub and spoke via VPN](./networking/hub-and-spoke-vpn/), [DNS and Google Private Access for on-premises](./networking/onprem-google-access-dns/), [Shared VPC with GKE support](./networking/shared-vpc-gke/), [ILB as next hop](./networking/ilb-next-hop), [decentralized firewall](./networking/decentralized-firewall)
- **data solutions** - [GCE/GCS CMEK via centralized Cloud KMS](./data-solutions/cmek-via-centralized-kms/), [Cloud Storage to Bigquery with Cloud Dataflow](./data-solutions/gcs-to-bq-with-dataflow/)
- **cloud operations** - [Resource tracking and remediation via Cloud Asset feeds](.//cloud-operations/asset-inventory-feed-remediation), [Granular Cloud DNS IAM via Service Directory](./cloud-operations/dns-fine-grained-iam), [Granular Cloud DNS IAM for Shared VPC](./cloud-operations/dns-shared-vpc), [Compute Engine quota monitoring](./cloud-operations/quota-monitoring), [Scheduled Cloud Asset Inventory Export to Bigquery](./cloud-operations/scheduled-asset-inventory-export-bq)
- **third party solutions** - [OpenShift cluster on Shared VPC](./third-party-solutions/openshift)

View File

@ -4,7 +4,7 @@ This module allows creation and management of different types of firewall rules
Yaml abstraction for FW rules can simplify users onboarding and also makes rules definition simpler and clearer comparing to HCL.
Nested folder structure for yaml configurations is supported, which allows better and structured code management.
Nested folder structure for yaml configurations is supported, which allows better and structured code management for multiple teams and environments.
## Example
@ -12,20 +12,29 @@ Nested folder structure for yaml configurations is supported, which allows bette
```hcl
module "prod-firewall" {
source = "./modules/net-vpc-firewall-yaml"
project_id = "my-prod-project"
network = "my-prod-network"
config_path = "./prod"
source = "./modules/net-vpc-firewall-yaml"
project_id = "my-prod-project"
network = "my-prod-network"
config_directories = [
"./prod",
"./common"
]
log_config = {
metadata = "INCLUDE_ALL_METADATA"
}
}
module "dev-firewall" {
source = "./modules/net-vpc-firewall-yaml"
project_id = "my-dev-project"
network = "my-dev-network"
config_path = "./dev"
source = "./modules/net-vpc-firewall-yaml"
project_id = "my-dev-project"
network = "my-dev-network"
config_directories = [
"./prod",
"./common"
]
}
# tftest:skip
```
@ -33,9 +42,11 @@ module "dev-firewall" {
### Configuration Structure
```bash
├── common
│ ├── default-egress.yaml
│   ├── lb-rules.yaml
│   └── iap-ingress.yaml
├── dev
│   ├── core
│   │   └── common-rules.yaml
│   ├── team-a
│   │   ├── databases.yaml
│   │   └── webb-app-a.yaml
@ -43,8 +54,6 @@ module "dev-firewall" {
│   ├── backend.yaml
│   └── frontend.yaml
└── prod
├── core
│   └── common-rules.yaml
├── team-a
│   ├── databases.yaml
│   └── webb-app-a.yaml
@ -63,7 +72,7 @@ rule-name: # descriptive name, naming convention is adjusted by the module
- ports: ['443', '80'] # ports for a specific protocol, keep empty list `[]` for all ports
protocol: tcp # protocol, put `all` for any protocol
direction: EGRESS # EGRESS or INGRESS
disabled: false # `false` or `true`, FW rule is disabled when `true`, default value is `true`
disabled: false # `false` or `true`, FW rule is disabled when `true`, default value is `false`
priority: 1000 # rule priority value, default value is 1000
source_ranges: # list of source ranges, should be specified only for `INGRESS` rule
- 0.0.0.0/0
@ -131,7 +140,7 @@ web-app-a-ingress:
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| config_path | Path to a folder where firewall configs are stored in yaml format. Folder may include subfolders with configuration files. Files suffix must be `.yaml` | <code title="">string</code> | ✓ | |
| config_directories | List of paths to folders where firewall configs are stored in yaml format. Folder may include subfolders with configuration files. Files suffix must be `.yaml` | <code title="list&#40;string&#41;">list(string)</code> | ✓ | |
| network | Name of the network this set of firewall rules applies to. | <code title="">string</code> | ✓ | |
| project_id | Project Id. | <code title="">string</code> | ✓ | |
| *log_config* | Log configuration. Possible values for `metadata` are `EXCLUDE_ALL_METADATA` and `INCLUDE_ALL_METADATA`. Set to `null` for disabling firewall logging. | <code title="object&#40;&#123;&#10;metadata &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |

View File

@ -15,10 +15,23 @@
*/
locals {
firewall_rule_files = flatten(
[
for config_path in var.config_directories :
concat(
[
for config_file in fileset("${path.root}/${config_path}", "**/*.yaml") :
"${path.root}/${config_path}/${config_file}"
]
)
]
)
firewall_rules = merge(
[
for config_file in fileset("${path.root}/${var.config_path}", "**/*.yaml") :
try(yamldecode(file("${path.root}/${var.config_path}/${config_file}")), {})
for config_file in local.firewall_rule_files :
try(yamldecode(file(config_file)), {})
]...
)
}

View File

@ -18,7 +18,7 @@ output "ingress_allow_rules" {
description = "Ingress rules with allow blocks."
value = [
for rule in google_compute_firewall.rules :
rule.name if rule.direction == "INGRESS" && length(rule.allow) > 0
rule if rule.direction == "INGRESS" && length(rule.allow) > 0
]
}
@ -26,7 +26,7 @@ output "ingress_deny_rules" {
description = "Ingress rules with deny blocks."
value = [
for rule in google_compute_firewall.rules :
rule.name if rule.direction == "INGRESS" && length(rule.deny) > 0
rule if rule.direction == "INGRESS" && length(rule.deny) > 0
]
}
@ -34,7 +34,7 @@ output "egress_allow_rules" {
description = "Egress rules with allow blocks."
value = [
for rule in google_compute_firewall.rules :
rule.name if rule.direction == "EGRESS" && length(rule.allow) > 0
rule if rule.direction == "EGRESS" && length(rule.allow) > 0
]
}
@ -42,6 +42,6 @@ output "egress_deny_rules" {
description = "Egress rules with allow blocks."
value = [
for rule in google_compute_firewall.rules :
rule.name if rule.direction == "EGRESS" && length(rule.deny) > 0
rule if rule.direction == "EGRESS" && length(rule.deny) > 0
]
}

View File

@ -24,9 +24,9 @@ variable "project_id" {
type = string
}
variable "config_path" {
description = "Path to a folder where firewall configs are stored in yaml format. Folder may include subfolders with configuration files. Files suffix must be `.yaml`"
type = string
variable "config_directories" {
description = "List of paths to folders where firewall configs are stored in yaml format. Folder may include subfolders with configuration files. Files suffix must be `.yaml`"
type = list(string)
}
variable "log_config" {

View File

@ -40,4 +40,7 @@ It is meant to be used as a starting point for most Shared VPC configurations, a
### Calling a private Cloud Function from On-premises
<a href="./private-cloud-function-from-onprem/" title="Private Cloud Function from On-premises"><img src="./private-cloud-function-from-onprem/diagram.png" align="left" width="280px"></a> This [example](./private-cloud-function-from-onprem/) shows how to invoke a [private Google Cloud Function](https://cloud.google.com/functions/docs/networking/network-settings) from the on-prem environment via a [Private Service Connect endpoint](https://cloud.google.com/vpc/docs/private-service-connect#benefits-apis).
<a href="./private-cloud-function-from-onprem/" title="Private Cloud Function from On-premises"><img src="./private-cloud-function-from-onprem/diagram.png" align="left" width="280px"></a> This [example](./private-cloud-function-from-onprem/) shows how to invoke a [private Google Cloud Function](https://cloud.google.com/functions/docs/networking/network-settings) from the on-prem environment via a [Private Service Connect endpoint](https://cloud.google.com/vpc/docs/private-service-connect#benefits-apis).
### Decentralized firewall management
<a href="./decentralized-firewall/" title="Decentralized firewall management"><img src="./decentralized-firewall/diagram.png" align="left" width="280px"></a> This [example](./decentralized-firewall/) shows how a decentralized firewall management can be organized using [firewall-yaml](../modules/net-vpc-firewall-yaml) module.

View File

@ -0,0 +1,28 @@
# Decentralized firewall management
This sample shows how a decentralized firewall management can be organized using [firewall-yaml](../../modules/net-vpc-firewall-yaml) module.
This approach is a good fit when Shared VPCs are used across multiple application/infrastructure teams. A centrall repository keeps environment/team specific folders with firewall definitions in `yaml` format. This is the high level diagram:
![High-level diagram](diagram.png "High-level diagram")
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| billing_account_id | Billing account id used as default for new projects. | <code title="">string</code> | ✓ | |
| prefix | Prefix used for resources that need unique names. | <code title="">string</code> | ✓ | |
| root_node | Hierarchy node where projects will be created, 'organizations/org_id' or 'folders/folder_id'. | <code title="">string</code> | ✓ | |
| *ip_ranges* | Subnet IP CIDR ranges. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="&#123;&#10;prod &#61; &#34;10.0.16.0&#47;24&#34;&#10;dev &#61; &#34;10.0.32.0&#47;24&#34;&#10;&#125;">...</code> |
| *project_services* | Service APIs enabled by default in new projects. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="&#91;&#10;&#34;container.googleapis.com&#34;,&#10;&#34;stackdriver.googleapis.com&#34;,&#10;&#93;">...</code> |
| *region* | Region used. | <code title="">string</code> | | <code title="">europe-west1</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| fw_rules | Firewall rules. | |
| projects | Project ids. | |
| vpc | Shared VPCs. | |
<!-- END TFDOC -->

View File

@ -0,0 +1,20 @@
# Copyright 2021 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 {
backend "gcs" {
bucket = ""
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,43 @@
# Copyright 2021 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.
# Deny all egress (egress traffic is allowed by default)
deny-all:
deny:
- ports: []
protocol: all
direction: EGRESS
priority: 65535
destination_ranges:
- 0.0.0.0/0
# Allow access to GCP APIs via Private Google Access
# https://cloud.google.com/vpc/docs/access-apis-external-ip#config
gcp-pga-apis:
allow:
- ports: [443]
protocol: tcp
direction: EGRESS
priority: 500
destination_ranges:
- 199.36.153.8/30
# Allow egress to internal networks
internal-egress:
allow:
- ports: []
protocol: tcp
direction: EGRESS
destination_ranges:
- 10.0.0.0/16

View File

@ -0,0 +1,23 @@
# Copyright 2021 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.
# Access via SSH from IAP to all instancess https://cloud.google.com/iap/docs/using-tcp-forwarding#create-firewall-rule
iap-ssh-access:
allow:
- ports: [22]
protocol: tcp
direction: INGRESS
priority: 1001
source_ranges:
- 35.235.240.0/20

View File

@ -0,0 +1,24 @@
# Copyright 2021 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.
# Access from GCP LBs https://cloud.google.com/load-balancing/docs/https/#firewall_rules
lb-health-checks:
allow:
- ports: []
protocol: tcp
direction: INGRESS
priority: 1001
source_ranges:
- 35.191.0.0/16
- 130.211.0.0/22

View File

@ -0,0 +1,33 @@
# Copyright 2021 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.
# Allow traffic from the frontend VMs
app1-backend:
allow:
- ports: ['443', '80']
protocol: tcp
direction: INGRESS
source_tags: ['app1-frontend']
target_tags: ['app1-backend']
# Allow traffic to MySQL Servers from App1 backend
app1-db:
allow:
- ports: ['3306']
protocol: tcp
direction: INGRESS
source_tags: ['app1-backend']
target_tags: ['mysql-server']

View File

@ -0,0 +1,31 @@
# Copyright 2021 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.
# Allow traffic from app1 frontend
app2-backend:
allow:
- ports: ['443', '80']
protocol: tcp
direction: INGRESS
source_tags: ['app1-frontend']
target_tags: ['app2-backend']
# Allow traffic to MySQL servers from App2 backend
app2-db:
allow:
- ports: ['3306']
protocol: tcp
direction: INGRESS
source_tags: ['app2-backend']
target_tags: ['mysql-server']

View File

@ -0,0 +1,32 @@
# Copyright 2021 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.
# Allow traffic from the frontend VMs
app1-backend:
allow:
- ports: ['443', '80']
protocol: tcp
direction: INGRESS
source_tags: ['app1-frontend']
target_tags: ['app1-backend']
# Allow traffic to MySQL Servers from App1 backend
app1-db:
allow:
- ports: ['3306']
protocol: tcp
direction: INGRESS
source_tags: ['app1-backend']
target_tags: ['mysql-server']

View File

@ -0,0 +1,136 @@
# Copyright 2021 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.
###############################################################################
# Shared VPC Host projects #
###############################################################################
module "project-host-prod" {
source = "../../modules/project"
parent = var.root_node
billing_account = var.billing_account_id
prefix = var.prefix
name = "prod-host"
services = var.project_services
shared_vpc_host_config = {
enabled = true
service_projects = []
}
}
module "project-host-dev" {
source = "../../modules/project"
parent = var.root_node
billing_account = var.billing_account_id
prefix = var.prefix
name = "dev-host"
services = var.project_services
shared_vpc_host_config = {
enabled = true
service_projects = []
}
}
################################################################################
# Networking #
################################################################################
module "vpc-prod" {
source = "../../modules/net-vpc"
project_id = module.project-host-prod.project_id
name = "prod-vpc"
subnets = [
{
ip_cidr_range = var.ip_ranges.prod
name = "prod"
region = var.region
secondary_ip_range = {}
}
]
}
module "vpc-dev" {
source = "../../modules/net-vpc"
project_id = module.project-host-dev.project_id
name = "dev-vpc"
subnets = [
{
ip_cidr_range = var.ip_ranges.dev
name = "dev"
region = var.region
secondary_ip_range = {}
}
]
}
###############################################################################
# Private Google Access DNS #
###############################################################################
module "dns-api-prod" {
source = "../../modules/dns"
project_id = module.project-host-prod.project_id
type = "private"
name = "googleapis"
domain = "googleapis.com."
client_networks = [module.vpc-prod.self_link]
recordsets = [
{ name = "*", type = "CNAME", ttl = 300, records = ["private.googleapis.com."] },
]
}
module "dns-api-dev" {
source = "../../modules/dns"
project_id = module.project-host-dev.project_id
type = "private"
name = "googleapis"
domain = "googleapis.com."
client_networks = [module.vpc-dev.self_link]
recordsets = [
{ name = "*", type = "CNAME", ttl = 300, records = ["private.googleapis.com."] },
]
}
###############################################################################
# Distributed Firewall #
###############################################################################
module "vpc-firewall-prod" {
source = "../../modules/net-vpc-firewall-yaml"
project_id = module.project-host-prod.project_id
network = module.vpc-prod.name
config_directories = [
"./firewall/common",
"./firewall/prod"
]
# Enable Firewall Logging for the production fwl rules
log_config = {
metadata = "INCLUDE_ALL_METADATA"
}
}
module "vpc-firewall-dev" {
source = "../../modules/net-vpc-firewall-yaml"
project_id = module.project-host-dev.project_id
network = module.vpc-dev.name
config_directories = [
"./firewall/common",
"./firewall/dev"
]
}

View File

@ -0,0 +1,53 @@
# Copyright 2021 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.
output "projects" {
description = "Project ids."
value = {
prod-host = module.project-host-prod.project_id
dev-host = module.project-host-dev.project_id
}
}
output "vpc" {
description = "Shared VPCs."
value = {
prod = {
name = module.vpc-prod.name
subnets = module.vpc-prod.subnet_ips
}
dev = {
name = module.vpc-dev.name
subnets = module.vpc-dev.subnet_ips
}
}
}
output "fw_rules" {
description = "Firewall rules."
value = {
prod = {
ingress_allow_rules = module.vpc-firewall-prod.ingress_allow_rules
ingress_deny_rules = module.vpc-firewall-prod.ingress_deny_rules
egress_allow_rules = module.vpc-firewall-prod.egress_allow_rules
egress_deny_rules = module.vpc-firewall-prod.egress_deny_rules
}
dev = {
ingress_allow_rules = module.vpc-firewall-dev.ingress_allow_rules
ingress_deny_rules = module.vpc-firewall-dev.ingress_deny_rules
egress_allow_rules = module.vpc-firewall-dev.egress_allow_rules
egress_deny_rules = module.vpc-firewall-dev.egress_deny_rules
}
}
}

View File

@ -0,0 +1,53 @@
# Copyright 2021 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.
variable "billing_account_id" {
description = "Billing account id used as default for new projects."
type = string
}
variable "prefix" {
description = "Prefix used for resources that need unique names."
type = string
}
variable "region" {
description = "Region used."
type = string
default = "europe-west1"
}
variable "root_node" {
description = "Hierarchy node where projects will be created, 'organizations/org_id' or 'folders/folder_id'."
type = string
}
variable "ip_ranges" {
description = "Subnet IP CIDR ranges."
type = map(string)
default = {
prod = "10.0.16.0/24"
dev = "10.0.32.0/24"
}
}
variable "project_services" {
description = "Service APIs enabled by default in new projects."
type = list(string)
default = [
"container.googleapis.com",
"dns.googleapis.com",
"stackdriver.googleapis.com",
]
}