Merge pull request #208 from terraform-google-modules/averbuks-fw-yaml
Added FW-Yaml module for distributed-firewall network example.
This commit is contained in:
commit
1d9290c74a
|
@ -0,0 +1,147 @@
|
||||||
|
# Google Cloud VPC Firewall - Yaml
|
||||||
|
|
||||||
|
This module allows creation and management of different types of firewall rules by defining them in well formatted `yaml` files.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
### Terraform code
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
module "prod-firewall" {
|
||||||
|
source = "./modules/net-vpc-firewall-yaml"
|
||||||
|
project_id = "my-prod-project"
|
||||||
|
network = "my-prod-network"
|
||||||
|
config_path = "./prod"
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
# tftest:skip
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Structure
|
||||||
|
|
||||||
|
```bash
|
||||||
|
├── dev
|
||||||
|
│ ├── core
|
||||||
|
│ │ └── common-rules.yaml
|
||||||
|
│ ├── team-a
|
||||||
|
│ │ ├── databases.yaml
|
||||||
|
│ │ └── webb-app-a.yaml
|
||||||
|
│ └── team-b
|
||||||
|
│ ├── backend.yaml
|
||||||
|
│ └── frontend.yaml
|
||||||
|
└── prod
|
||||||
|
├── core
|
||||||
|
│ └── common-rules.yaml
|
||||||
|
├── team-a
|
||||||
|
│ ├── databases.yaml
|
||||||
|
│ └── webb-app-a.yaml
|
||||||
|
└── team-b
|
||||||
|
├── backend.yaml
|
||||||
|
└── frontend.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rule definition format and structure
|
||||||
|
|
||||||
|
Firewall rules configuration should be placed in a set of yaml files in a folder/s. Firewall rule entry structure is following:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
rule-name: # descriptive name, naming convention is adjusted by the module
|
||||||
|
allow: # `allow` or `deny`
|
||||||
|
- 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`
|
||||||
|
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
|
||||||
|
destination_ranges: # list of destination ranges, should be specified only for `EGRESS` rule
|
||||||
|
- 0.0.0.0/0
|
||||||
|
source_tags: ['some-tag'] # list of source tags, should be specified only for `INGRESS` rule
|
||||||
|
source_service_accounts: # list of source service accounts, should be specified only for `INGRESS` rule, can not be specified together with `source_tags` or `target_tags`
|
||||||
|
- myapp@myproject-id.iam.gserviceaccount.com
|
||||||
|
target_tags: ['some-tag'] # list of target tags
|
||||||
|
target_service_accounts: # list of target service accounts, , can not be specified together with `source_tags` or `target_tags`
|
||||||
|
- myapp@myproject-id.iam.gserviceaccount.com
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Firewall rules example yaml configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat ./prod/core-network/common-rules.yaml
|
||||||
|
# allow ingress from GCLB to all instances in the network
|
||||||
|
lb-health-checks:
|
||||||
|
allow:
|
||||||
|
- ports: []
|
||||||
|
protocol: tcp
|
||||||
|
direction: INGRESS
|
||||||
|
priority: 1001
|
||||||
|
source_ranges:
|
||||||
|
- 35.191.0.0/16
|
||||||
|
- 130.211.0.0/22
|
||||||
|
|
||||||
|
# deny all egress
|
||||||
|
deny-all:
|
||||||
|
deny:
|
||||||
|
- ports: []
|
||||||
|
protocol: all
|
||||||
|
direction: EGRESS
|
||||||
|
priority: 65535
|
||||||
|
destination_ranges:
|
||||||
|
- 0.0.0.0/0
|
||||||
|
|
||||||
|
cat ./dev/team-a/web-app-a.yaml
|
||||||
|
# Myapp egress
|
||||||
|
web-app-a-egress:
|
||||||
|
allow:
|
||||||
|
- ports: [443]
|
||||||
|
protocol: tcp
|
||||||
|
direction: EGRESS
|
||||||
|
destination_ranges:
|
||||||
|
- 192.168.0.0/24
|
||||||
|
target_service_accounts:
|
||||||
|
- myapp@myproject-id.iam.gserviceaccount.com
|
||||||
|
# Myapp ingress
|
||||||
|
web-app-a-ingress:
|
||||||
|
allow:
|
||||||
|
- ports: [1234]
|
||||||
|
protocol: tcp
|
||||||
|
direction: INGRESS
|
||||||
|
source_service_accounts:
|
||||||
|
- frontend-sa@myproject-id.iam.gserviceaccount.com
|
||||||
|
target_service_accounts:
|
||||||
|
- web-app-a@myproject-id.iam.gserviceaccount.com
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- BEGIN TFDOC -->
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
| 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> | ✓ | |
|
||||||
|
| 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({ metadata = string })">object({...})</code> | | <code title="">null</code> |
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
| name | description | sensitive |
|
||||||
|
|---|---|:---:|
|
||||||
|
| egress_allow_rules | Egress rules with allow blocks. | |
|
||||||
|
| egress_deny_rules | Egress rules with allow blocks. | |
|
||||||
|
| ingress_allow_rules | Ingress rules with allow blocks. | |
|
||||||
|
| ingress_deny_rules | Ingress rules with deny blocks. | |
|
||||||
|
<!-- END TFDOC -->
|
|
@ -0,0 +1,100 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
locals {
|
||||||
|
firewall_rules = merge(
|
||||||
|
[
|
||||||
|
for config_file in fileset("${path.root}/${var.config_path}", "**/*.yaml") :
|
||||||
|
try(yamldecode(file("${path.root}/${var.config_path}/${config_file}")), {})
|
||||||
|
]...
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "time_static" "timestamp" {
|
||||||
|
for_each = local.firewall_rules
|
||||||
|
triggers = {
|
||||||
|
name = md5(jsonencode(each.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_compute_firewall" "rules" {
|
||||||
|
for_each = local.firewall_rules
|
||||||
|
project = var.project_id
|
||||||
|
name = format(
|
||||||
|
"fwr-%s-%s-%s-%s",
|
||||||
|
var.network,
|
||||||
|
(try(each.value.target_service_accounts, null) != null ? "sac" : try(each.value.target_tags, null) != null ? "vpc" : "all"),
|
||||||
|
substr(lower(each.value.direction), 0, 1),
|
||||||
|
each.key
|
||||||
|
)
|
||||||
|
description = format(
|
||||||
|
"%s rule in network %s for %s created at %s",
|
||||||
|
each.value.direction,
|
||||||
|
var.network,
|
||||||
|
each.key,
|
||||||
|
time_static.timestamp[each.key].rfc3339
|
||||||
|
)
|
||||||
|
|
||||||
|
network = var.network
|
||||||
|
direction = each.value.direction
|
||||||
|
priority = try(each.value.priority, 1000)
|
||||||
|
disabled = try(each.value.disabled, null)
|
||||||
|
|
||||||
|
source_ranges = try(each.value.source_ranges, each.value.direction == "INGRESS" ? [] : null)
|
||||||
|
source_tags = try(each.value.source_tags, null)
|
||||||
|
source_service_accounts = try(each.value.source_service_accounts, null)
|
||||||
|
|
||||||
|
destination_ranges = try(each.value.destination_ranges, each.value.direction == "EGRESS" ? [] : null)
|
||||||
|
target_tags = try(each.value.target_tags, null)
|
||||||
|
target_service_accounts = try(each.value.target_service_accounts, null)
|
||||||
|
|
||||||
|
dynamic "allow" {
|
||||||
|
for_each = { for block in try(each.value.allow, []) :
|
||||||
|
"${block.protocol}-${join("-", block.ports)}" => {
|
||||||
|
ports = [for port in block.ports : tostring(port)]
|
||||||
|
protocol = block.protocol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content {
|
||||||
|
protocol = allow.value.protocol
|
||||||
|
ports = allow.value.ports
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic "deny" {
|
||||||
|
for_each = { for block in try(each.value.deny, []) :
|
||||||
|
"${block.protocol}-${join("-", block.ports)}" => {
|
||||||
|
ports = [for port in block.ports : tostring(port)]
|
||||||
|
protocol = block.protocol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content {
|
||||||
|
protocol = deny.value.protocol
|
||||||
|
ports = deny.value.ports
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic "log_config" {
|
||||||
|
for_each = var.log_config != null ? [""] : []
|
||||||
|
content {
|
||||||
|
metadata = var.log_config.metadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
create_before_destroy = true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* 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 "network" {
|
||||||
|
description = "Name of the network this set of firewall rules applies to."
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "project_id" {
|
||||||
|
description = "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 "log_config" {
|
||||||
|
description = "Log configuration. Possible values for `metadata` are `EXCLUDE_ALL_METADATA` and `INCLUDE_ALL_METADATA`. Set to `null` for disabling firewall logging."
|
||||||
|
type = object({
|
||||||
|
metadata = string
|
||||||
|
})
|
||||||
|
default = null
|
||||||
|
}
|
|
@ -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
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
terraform {
|
||||||
|
required_version = ">= 0.13.3"
|
||||||
|
}
|
Loading…
Reference in New Issue