Skip to content

Commit 24f2a0f

Browse files
authored
feat: Add dedicated custom firewall rules module (#200)
1 parent 2f44790 commit 24f2a0f

File tree

11 files changed

+302
-0
lines changed

11 files changed

+302
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Then perform the following commands on the root folder:
9797
| auto\_create\_subnetworks | When set to true, the network is created in 'auto subnet mode' and it will create a subnet for each region automatically across the 10.128.0.0/9 address range. When set to false, the network is created in 'custom subnet mode' so the user can explicitly connect subnetwork resources. | `bool` | `false` | no |
9898
| delete\_default\_internet\_gateway\_routes | If set, ensure that all routes within the network specified whose names begin with 'default-route' and with a next hop of 'default-internet-gateway' are deleted | `bool` | `false` | no |
9999
| description | An optional description of this resource. The resource must be recreated to modify this field. | `string` | `""` | no |
100+
| firewall\_rules | List of firewall rules | `any` | `[]` | no |
100101
| mtu | The network MTU. Must be a value between 1460 and 1500 inclusive. If set to 0 (meaning MTU is unset), the network will default to 1460 automatically. | `number` | `0` | no |
101102
| network\_name | The name of the network being created | `any` | n/a | yes |
102103
| project\_id | The ID of the project where this VPC will be created | `any` | n/a | yes |

examples/secondary_ranges/main.tf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,28 @@ module "vpc-secondary-ranges" {
8484
},
8585
]
8686
}
87+
88+
firewall_rules = [
89+
{
90+
name = "allow-ssh-ingress"
91+
direction = "INGRESS"
92+
ranges = ["0.0.0.0/0"]
93+
allow = [{
94+
protocol = "tcp"
95+
ports = ["22"]
96+
}]
97+
log_config = {
98+
metadata = "INCLUDE_ALL_METADATA"
99+
}
100+
},
101+
{
102+
name = "deny-udp-egress"
103+
direction = "INGRESS"
104+
ranges = ["0.0.0.0/0"]
105+
deny = [{
106+
protocol = "udp"
107+
ports = null
108+
}]
109+
},
110+
]
87111
}

main.tf

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,32 @@ module "routes" {
5050
routes = var.routes
5151
module_depends_on = [module.subnets.subnets]
5252
}
53+
54+
/******************************************
55+
Firewall rules
56+
*****************************************/
57+
locals {
58+
rules = [
59+
for f in var.firewall_rules : {
60+
name = f.name
61+
direction = f.direction
62+
priority = lookup(f, "priority", null)
63+
description = lookup(f, "description", null)
64+
ranges = lookup(f, "ranges", null)
65+
source_tags = lookup(f, "source_tags", null)
66+
source_service_accounts = lookup(f, "source_service_accounts", null)
67+
target_tags = lookup(f, "target_tags", null)
68+
target_service_accounts = lookup(f, "target_service_accounts", null)
69+
allow = lookup(f, "allow", [])
70+
deny = lookup(f, "deny", [])
71+
log_config = lookup(f, "log_config", null)
72+
}
73+
]
74+
}
75+
76+
module "firewall_rules" {
77+
source = "./modules/firewall-rules"
78+
project_id = var.project_id
79+
network_name = module.vpc.network_name
80+
rules = local.rules
81+
}

modules/firewall-rules/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
terraform.tfvars

modules/firewall-rules/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Google Cloud VPC Firewall Rules
2+
3+
This module allows creation of custom VPC firewall rules.
4+
5+
## Usage
6+
7+
Basic usage of this module is as follows:
8+
9+
```hcl
10+
module "firewall_rules" {
11+
source = "terraform-google-modules/network/google//modules/firewall-rules"
12+
project_id = var.project_id
13+
network_name = module.vpc.network_name
14+
15+
rules = [{
16+
name = "allow-ssh-ingress"
17+
priority = null
18+
description = null
19+
direction = "INGRESS"
20+
ranges = ["0.0.0.0/0"]
21+
source = {
22+
tags = null
23+
service_accounts = null
24+
}
25+
target = {
26+
tags = null
27+
service_accounts = null
28+
}
29+
allow = [{
30+
protocol = "tcp"
31+
ports = ["22"]
32+
}]
33+
deny = []
34+
log_config = {
35+
metadata = "INCLUDE_ALL_METADATA"
36+
}
37+
}]
38+
}
39+
```
40+
41+
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
42+
## Inputs
43+
44+
| Name | Description | Type | Default | Required |
45+
|------|-------------|------|---------|:--------:|
46+
| network\_name | Name of the network this set of firewall rules applies to. | `any` | n/a | yes |
47+
| project\_id | Project id of the project that holds the network. | `any` | n/a | yes |
48+
| rules | List of custom rule definitions (refer to variables file for syntax). | <pre>list(object({<br> name = string<br> description = string<br> direction = string<br> priority = number<br> ranges = list(string)<br> source_tags = list(string)<br> source_service_accounts = list(string)<br> target_tags = list(string)<br> target_service_accounts = list(string)<br> allow = list(object({<br> protocol = string<br> ports = list(string)<br> }))<br> deny = list(object({<br> protocol = string<br> ports = list(string)<br> }))<br> log_config = object({<br> metadata = string<br> })<br> }))</pre> | `[]` | no |
49+
50+
## Outputs
51+
52+
| Name | Description |
53+
|------|-------------|
54+
| firewall\_rules | The created firewall rule resources |
55+
56+
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

modules/firewall-rules/main.tf

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
resource "google_compute_firewall" "rules" {
18+
for_each = { for r in var.rules : "${r.name}" => r }
19+
name = each.value.name
20+
description = each.value.description
21+
direction = each.value.direction
22+
network = var.network_name
23+
project = var.project_id
24+
source_ranges = each.value.direction == "INGRESS" ? each.value.ranges : null
25+
destination_ranges = each.value.direction == "EGRESS" ? each.value.ranges : null
26+
source_tags = each.value.source_tags
27+
source_service_accounts = each.value.source_service_accounts
28+
target_tags = each.value.target_tags
29+
target_service_accounts = each.value.target_service_accounts
30+
priority = each.value.priority
31+
32+
dynamic "log_config" {
33+
for_each = lookup(each.value, "log_config") == null ? [] : [each.value.log_config]
34+
content {
35+
metadata = log_config.value.metadata
36+
}
37+
}
38+
39+
dynamic "allow" {
40+
for_each = lookup(each.value, "allow", [])
41+
content {
42+
protocol = allow.value.protocol
43+
ports = lookup(allow.value, "ports", null)
44+
}
45+
}
46+
47+
dynamic "deny" {
48+
for_each = lookup(each.value, "deny", [])
49+
content {
50+
protocol = deny.value.protocol
51+
ports = lookup(deny.value, "ports", null)
52+
}
53+
}
54+
}

modules/firewall-rules/outputs.tf

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
output "firewall_rules" {
18+
value = google_compute_firewall.rules
19+
description = "The created firewall rule resources"
20+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
variable "project_id" {
18+
description = "Project id of the project that holds the network."
19+
}
20+
21+
variable "network_name" {
22+
description = "Name of the network this set of firewall rules applies to."
23+
}
24+
25+
variable "rules" {
26+
description = "List of custom rule definitions (refer to variables file for syntax)."
27+
default = []
28+
type = list(object({
29+
name = string
30+
description = string
31+
direction = string
32+
priority = number
33+
ranges = list(string)
34+
source_tags = list(string)
35+
source_service_accounts = list(string)
36+
target_tags = list(string)
37+
target_service_accounts = list(string)
38+
allow = list(object({
39+
protocol = string
40+
ports = list(string)
41+
}))
42+
deny = list(object({
43+
protocol = string
44+
ports = list(string)
45+
}))
46+
log_config = object({
47+
metadata = string
48+
})
49+
}))
50+
}

modules/firewall-rules/versions.tf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
terraform {
18+
required_version = ">=0.12.6, <0.14"
19+
required_providers {
20+
google = "<4.0,>= 2.12"
21+
}
22+
}

test/integration/secondary_ranges/controls/gcloud.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,43 @@
9898
expect(data).not_to include("secondaryIpRanges")
9999
end
100100
end
101+
102+
describe command("gcloud compute firewall-rules describe allow-ssh-ingress --project=#{project_id} --format=json") do
103+
its(:exit_status) { should eq 0 }
104+
its(:stderr) { should eq '' }
105+
106+
let(:data) do
107+
if subject.exit_status == 0
108+
JSON.parse(subject.stdout)
109+
else
110+
{}
111+
end
112+
end
113+
114+
it "should have the correct allow rules" do
115+
expect(data["allowed"][0]).to include(
116+
"IPProtocol" => "tcp",
117+
"ports" => ["22"]
118+
)
119+
end
120+
end
121+
122+
describe command("gcloud compute firewall-rules describe deny-udp-egress --project=#{project_id} --format=json") do
123+
its(:exit_status) { should eq 0 }
124+
its(:stderr) { should eq '' }
125+
126+
let(:data) do
127+
if subject.exit_status == 0
128+
JSON.parse(subject.stdout)
129+
else
130+
{}
131+
end
132+
end
133+
134+
it "should have the correct allow rules" do
135+
expect(data["denied"][0]).to include(
136+
"IPProtocol" => "udp",
137+
)
138+
end
139+
end
101140
end

0 commit comments

Comments
 (0)