Merge branch 'master' into sa-upload-crt
This commit is contained in:
23
tests/modules/net_vpc/fixture/data/factory-subnet.yaml
Normal file
23
tests/modules/net_vpc/fixture/data/factory-subnet.yaml
Normal 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
|
||||
#
|
||||
# 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.
|
||||
|
||||
region: europe-west1
|
||||
description: Sample description
|
||||
ip_cidr_range: 10.128.0.0/24
|
||||
private_ip_google_access: false
|
||||
iam_users: ["foobar@example.com"]
|
||||
iam_groups: ["lorem@example.com"]
|
||||
iam_service_accounts: ["foobar@project-id.iam.gserviceaccount.com"]
|
||||
secondary_ip_range:
|
||||
secondary-range-a: 192.168.128.0/24
|
||||
@@ -15,20 +15,21 @@
|
||||
*/
|
||||
|
||||
module "test" {
|
||||
source = "../../../../modules/net-vpc"
|
||||
project_id = var.project_id
|
||||
name = var.name
|
||||
iam = var.iam
|
||||
log_configs = var.log_configs
|
||||
log_config_defaults = var.log_config_defaults
|
||||
peering_config = var.peering_config
|
||||
routes = var.routes
|
||||
shared_vpc_host = var.shared_vpc_host
|
||||
shared_vpc_service_projects = var.shared_vpc_service_projects
|
||||
subnets = var.subnets
|
||||
subnet_descriptions = var.subnet_descriptions
|
||||
subnet_flow_logs = var.subnet_flow_logs
|
||||
subnet_private_access = var.subnet_private_access
|
||||
auto_create_subnetworks = var.auto_create_subnetworks
|
||||
private_service_networking_range = var.private_service_networking_range
|
||||
source = "../../../../modules/net-vpc"
|
||||
project_id = var.project_id
|
||||
name = var.name
|
||||
iam = var.iam
|
||||
log_configs = var.log_configs
|
||||
log_config_defaults = var.log_config_defaults
|
||||
peering_config = var.peering_config
|
||||
routes = var.routes
|
||||
shared_vpc_host = var.shared_vpc_host
|
||||
shared_vpc_service_projects = var.shared_vpc_service_projects
|
||||
subnets = var.subnets
|
||||
subnet_descriptions = var.subnet_descriptions
|
||||
subnet_flow_logs = var.subnet_flow_logs
|
||||
subnet_private_access = var.subnet_private_access
|
||||
auto_create_subnetworks = var.auto_create_subnetworks
|
||||
psn_ranges = var.psn_ranges
|
||||
data_folder = var.data_folder
|
||||
}
|
||||
|
||||
@@ -61,6 +61,11 @@ variable "peering_config" {
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "psn_ranges" {
|
||||
type = list(string)
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "routes" {
|
||||
type = map(object({
|
||||
dest_range = string
|
||||
@@ -125,3 +130,9 @@ variable "private_service_networking_range" {
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "data_folder" {
|
||||
description = "An optional folder containing the subnet configurations in YaML format."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
@@ -88,20 +88,3 @@ def test_vpc_routes(plan_runner):
|
||||
resource = [r for r in resources if r['values']
|
||||
['name'] == 'my-vpc-next-hop-test'][0]
|
||||
assert resource['values']['next_hop_%s' % next_hop_type]
|
||||
|
||||
|
||||
def test_vpc_psn(plan_runner):
|
||||
_, resources = plan_runner(
|
||||
FIXTURES_DIR, private_service_networking_range="10.10.0.0/16"
|
||||
)
|
||||
assert len(resources) == 3
|
||||
|
||||
address = [r["values"] for r in resources if r["type"] == "google_compute_global_address"][0]
|
||||
assert address["address"] == "10.10.0.0"
|
||||
assert address["address_type"] == "INTERNAL"
|
||||
assert address["prefix_length"] == 16
|
||||
assert address["purpose"] == "VPC_PEERING"
|
||||
|
||||
connection = [r["values"] for r in resources if r["type"] == "google_service_networking_connection"][0]
|
||||
assert connection["service"] == "servicenetworking.googleapis.com"
|
||||
assert connection["reserved_peering_ranges"] == ["my-vpc-google-psn"]
|
||||
|
||||
42
tests/modules/net_vpc/test_plan_psn.py
Normal file
42
tests/modules/net_vpc/test_plan_psn.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# 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.
|
||||
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import tftest
|
||||
|
||||
|
||||
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
|
||||
|
||||
|
||||
def test_single_range(plan_runner):
|
||||
"Test single PSN range."
|
||||
_, resources = plan_runner(FIXTURES_DIR, psn_ranges='["172.16.100.0/24"]')
|
||||
assert len(resources) == 3
|
||||
|
||||
|
||||
def test_multi_range(plan_runner):
|
||||
"Test multiple PSN ranges."
|
||||
_, resources = plan_runner(FIXTURES_DIR,
|
||||
psn_ranges='["172.16.100.0/24", "172.16.101.0/24"]')
|
||||
assert len(resources) == 4
|
||||
|
||||
|
||||
def test_validation(plan_runner):
|
||||
"Test PSN variable validation."
|
||||
try:
|
||||
plan_runner(FIXTURES_DIR, psn_ranges='["foobar"]')
|
||||
except tftest.TerraformTestError as e:
|
||||
assert 'Invalid value for variable' in e.args[0]
|
||||
@@ -29,6 +29,19 @@ _VAR_SUBNETS = (
|
||||
']'
|
||||
)
|
||||
|
||||
_VAR_DATA_FOLDER = "data"
|
||||
|
||||
|
||||
def test_subnet_factory(plan_runner):
|
||||
"Test subnet factory."
|
||||
_, resources = plan_runner(FIXTURES_DIR, data_folder=_VAR_DATA_FOLDER)
|
||||
assert len(resources) == 3
|
||||
subnets = [r['values']
|
||||
for r in resources if r['type'] == 'google_compute_subnetwork']
|
||||
assert set(s['name'] for s in subnets) == set(
|
||||
['factory-subnet'])
|
||||
assert set(len(s['secondary_ip_range']) for s in subnets) == set([1])
|
||||
|
||||
|
||||
def test_subnets_simple(plan_runner):
|
||||
"Test subnets variable."
|
||||
@@ -58,9 +71,9 @@ def test_subnet_log_configs(plan_runner):
|
||||
for r in resources:
|
||||
if r['type'] != 'google_compute_subnetwork':
|
||||
continue
|
||||
flow_logs[r['values']['name']] = [{key: config[key] for key in config.keys()
|
||||
& {'aggregation_interval', 'flow_sampling', 'metadata'}}
|
||||
for config in r['values']['log_config']]
|
||||
flow_logs[r['values']['name']] = [{key: config[key] for key in config.keys()
|
||||
& {'aggregation_interval', 'flow_sampling', 'metadata'}}
|
||||
for config in r['values']['log_config']]
|
||||
assert flow_logs == {
|
||||
# enable, override one default option
|
||||
'a': [{
|
||||
|
||||
13
tests/modules/net_vpc_firewall/__init__.py
Normal file
13
tests/modules/net_vpc_firewall/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,19 @@
|
||||
# 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.
|
||||
|
||||
healthchecks:
|
||||
- 35.191.0.0/16
|
||||
- 130.211.0.0/22
|
||||
- 209.85.152.0/22
|
||||
- 209.85.204.0/22
|
||||
@@ -0,0 +1,28 @@
|
||||
# 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.
|
||||
|
||||
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
|
||||
28
tests/modules/net_vpc_firewall/fixture/main.tf
Normal file
28
tests/modules/net_vpc_firewall/fixture/main.tf
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
97
tests/modules/net_vpc_firewall/fixture/variables.tf
Normal file
97
tests/modules/net_vpc_firewall/fixture/variables.tf
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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 "admin_ranges" {
|
||||
description = "IP CIDR ranges that have complete access to all subnets."
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
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)
|
||||
}))
|
||||
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 "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 "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"]
|
||||
}
|
||||
|
||||
44
tests/modules/net_vpc_firewall/test_plan.py
Normal file
44
tests/modules/net_vpc_firewall/test_plan.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# 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.
|
||||
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
|
||||
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
|
||||
|
||||
|
||||
def test_vpc_firewall_simple(plan_runner):
|
||||
"Test vpc with no extra options."
|
||||
_, resources = plan_runner(FIXTURES_DIR)
|
||||
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'])
|
||||
|
||||
|
||||
def test_vpc_firewall_factory(plan_runner):
|
||||
"Test shared vpc variables."
|
||||
_, resources = plan_runner(
|
||||
FIXTURES_DIR, data_folder="config/firewall", cidr_template_file="config/cidr_template.yaml")
|
||||
assert len(resources) == 4
|
||||
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"])
|
||||
18
tests/modules/organization/fixture/data/firewall-cidrs.yaml
Normal file
18
tests/modules/organization/fixture/data/firewall-cidrs.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
|
||||
rfc1918:
|
||||
- 10.0.0.0/8
|
||||
- 172.168.0.0/12
|
||||
- 192.168.0.0/16
|
||||
37
tests/modules/organization/fixture/data/firewall-rules.yaml
Normal file
37
tests/modules/organization/fixture/data/firewall-rules.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
# 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.
|
||||
|
||||
allow-admins:
|
||||
description: Access from the admin subnet to all subnets
|
||||
direction: INGRESS
|
||||
action: allow
|
||||
priority: 1000
|
||||
ranges:
|
||||
- $rfc1918
|
||||
ports:
|
||||
all: []
|
||||
target_resources: null
|
||||
enable_logging: false
|
||||
|
||||
allow-ssh-from-iap:
|
||||
description: Enable SSH from IAP
|
||||
direction: INGRESS
|
||||
action: allow
|
||||
priority: 1002
|
||||
ranges:
|
||||
- 35.235.240.0/20
|
||||
ports:
|
||||
tcp: ["22"]
|
||||
target_resources: null
|
||||
enable_logging: false
|
||||
@@ -27,6 +27,7 @@ module "test" {
|
||||
policy_list = var.policy_list
|
||||
firewall_policies = var.firewall_policies
|
||||
firewall_policy_attachments = var.firewall_policy_attachments
|
||||
firewall_policy_factory = var.firewall_policy_factory
|
||||
logging_sinks = var.logging_sinks
|
||||
logging_exclusions = var.logging_exclusions
|
||||
}
|
||||
|
||||
@@ -79,14 +79,24 @@ variable "firewall_policy_attachments" {
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "firewall_policy_factory" {
|
||||
type = object({
|
||||
cidr_file = string
|
||||
policy_name = string
|
||||
rules_file = string
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "logging_sinks" {
|
||||
type = map(object({
|
||||
destination = string
|
||||
type = string
|
||||
filter = string
|
||||
iam = bool
|
||||
include_children = bool
|
||||
exclusions = map(string)
|
||||
destination = string
|
||||
type = string
|
||||
filter = string
|
||||
iam = bool
|
||||
include_children = bool
|
||||
bq_partitioned_table = bool
|
||||
exclusions = map(string)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
@@ -110,78 +110,3 @@ def test_policy_list(plan_runner):
|
||||
assert values[1]['list_policy'][0]['deny'] == [
|
||||
{'all': False, 'values': ["bar"]}]
|
||||
assert values[2]['restore_policy'] == [{'default': True}]
|
||||
|
||||
|
||||
def test_firweall_policy(plan_runner):
|
||||
"Test boolean folder policy."
|
||||
policy = """
|
||||
{
|
||||
policy1 = {
|
||||
allow-ingress = {
|
||||
description = ""
|
||||
direction = "INGRESS"
|
||||
action = "allow"
|
||||
priority = 100
|
||||
ranges = ["10.0.0.0/8"]
|
||||
ports = {
|
||||
tcp = ["22"]
|
||||
}
|
||||
target_service_accounts = null
|
||||
target_resources = null
|
||||
logging = false
|
||||
}
|
||||
deny-egress = {
|
||||
description = ""
|
||||
direction = "EGRESS"
|
||||
action = "deny"
|
||||
priority = 200
|
||||
ranges = ["192.168.0.0/24"]
|
||||
ports = {
|
||||
tcp = ["443"]
|
||||
}
|
||||
target_service_accounts = null
|
||||
target_resources = null
|
||||
logging = false
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
attachment = '{ iap_policy = "policy1" }'
|
||||
_, resources = plan_runner(FIXTURES_DIR, firewall_policies=policy,
|
||||
firewall_policy_attachments=attachment)
|
||||
assert len(resources) == 4
|
||||
|
||||
policies = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy']
|
||||
assert len(policies) == 1
|
||||
|
||||
rules = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy_rule']
|
||||
assert len(rules) == 2
|
||||
|
||||
rule_values = []
|
||||
for rule in rules:
|
||||
name = rule['name']
|
||||
index = rule['index']
|
||||
action = rule['values']['action']
|
||||
direction = rule['values']['direction']
|
||||
priority = rule['values']['priority']
|
||||
config = rule['values']['match']
|
||||
assert len(config) == 1
|
||||
config = config[0]['config']
|
||||
rule_values.append((name, index, action, direction, priority, config))
|
||||
|
||||
assert sorted(rule_values) == sorted([
|
||||
('rule', 'policy1-allow-ingress', 'allow', 'INGRESS', 100, [
|
||||
{
|
||||
'dest_ip_ranges': None,
|
||||
'layer4_config': [{'ip_protocol': 'tcp', 'ports': ['22']}],
|
||||
'src_ip_ranges': ['10.0.0.0/8']
|
||||
}]),
|
||||
('rule', 'policy1-deny-egress', 'deny', 'EGRESS', 200, [
|
||||
{
|
||||
'dest_ip_ranges': ['192.168.0.0/24'],
|
||||
'layer4_config': [{'ip_protocol': 'tcp', 'ports': ['443']}],
|
||||
'src_ip_ranges': None
|
||||
}])
|
||||
])
|
||||
|
||||
137
tests/modules/organization/test_plan_firewall.py
Normal file
137
tests/modules/organization/test_plan_firewall.py
Normal file
@@ -0,0 +1,137 @@
|
||||
# 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.
|
||||
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
|
||||
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
|
||||
|
||||
_FACTORY = '''
|
||||
{
|
||||
cidr_file = "data/firewall-cidrs.yaml"
|
||||
policy_name = "factory-1"
|
||||
rules_file = "data/firewall-rules.yaml"
|
||||
}
|
||||
'''
|
||||
_POLICIES = '''
|
||||
{
|
||||
policy1 = {
|
||||
allow-ingress = {
|
||||
description = ""
|
||||
direction = "INGRESS"
|
||||
action = "allow"
|
||||
priority = 100
|
||||
ranges = ["10.0.0.0/8"]
|
||||
ports = {
|
||||
tcp = ["22"]
|
||||
}
|
||||
target_service_accounts = null
|
||||
target_resources = null
|
||||
logging = false
|
||||
}
|
||||
deny-egress = {
|
||||
description = ""
|
||||
direction = "EGRESS"
|
||||
action = "deny"
|
||||
priority = 200
|
||||
ranges = ["192.168.0.0/24"]
|
||||
ports = {
|
||||
tcp = ["443"]
|
||||
}
|
||||
target_service_accounts = null
|
||||
target_resources = null
|
||||
logging = false
|
||||
}
|
||||
}
|
||||
policy2 = {
|
||||
allow-ingress = {
|
||||
description = ""
|
||||
direction = "INGRESS"
|
||||
action = "allow"
|
||||
priority = 100
|
||||
ranges = ["10.0.0.0/8"]
|
||||
ports = {
|
||||
tcp = ["22"]
|
||||
}
|
||||
target_service_accounts = null
|
||||
target_resources = null
|
||||
logging = false
|
||||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
def test_custom(plan_runner):
|
||||
'Test custom firewall policies.'
|
||||
_, resources = plan_runner(FIXTURES_DIR, firewall_policies=_POLICIES)
|
||||
assert len(resources) == 5
|
||||
policies = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy']
|
||||
rules = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy_rule']
|
||||
assert set(r['index'] for r in policies) == set([
|
||||
'policy1', 'policy2'
|
||||
])
|
||||
assert set(r['index'] for r in rules) == set([
|
||||
'policy1-deny-egress', 'policy2-allow-ingress', 'policy1-allow-ingress'
|
||||
])
|
||||
|
||||
|
||||
def test_factory(plan_runner):
|
||||
'Test firewall policy factory.'
|
||||
_, resources = plan_runner(FIXTURES_DIR, firewall_policy_factory=_FACTORY)
|
||||
assert len(resources) == 3
|
||||
policies = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy']
|
||||
rules = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy_rule']
|
||||
assert set(r['index'] for r in policies) == set([
|
||||
'factory-1'
|
||||
])
|
||||
assert set(r['index'] for r in rules) == set([
|
||||
'factory-1-allow-admins', 'factory-1-allow-ssh-from-iap'
|
||||
])
|
||||
|
||||
|
||||
def test_factory_name(plan_runner):
|
||||
'Test firewall policy factory default name.'
|
||||
factory = _FACTORY.replace('"factory-1"', 'null')
|
||||
_, resources = plan_runner(FIXTURES_DIR, firewall_policy_factory=factory)
|
||||
assert len(resources) == 3
|
||||
policies = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy']
|
||||
assert set(r['index'] for r in policies) == set([
|
||||
'factory'
|
||||
])
|
||||
|
||||
|
||||
def test_combined(plan_runner):
|
||||
'Test combined rules.'
|
||||
_, resources = plan_runner(FIXTURES_DIR, firewall_policies=_POLICIES,
|
||||
firewall_policy_factory=_FACTORY)
|
||||
assert len(resources) == 8
|
||||
policies = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy']
|
||||
rules = [r for r in resources
|
||||
if r['type'] == 'google_compute_organization_security_policy_rule']
|
||||
assert set(r['index'] for r in policies) == set([
|
||||
'factory-1', 'policy1', 'policy2'
|
||||
])
|
||||
assert set(r['index'] for r in rules) == set([
|
||||
'factory-1-allow-admins', 'factory-1-allow-ssh-from-iap',
|
||||
'policy1-deny-egress', 'policy2-allow-ingress', 'policy1-allow-ingress'
|
||||
])
|
||||
@@ -22,148 +22,154 @@ FIXTURES_DIR = os.path.join(os.path.dirname(__file__), "fixture")
|
||||
|
||||
|
||||
def test_sinks(plan_runner):
|
||||
"Test folder-level sinks."
|
||||
logging_sinks = """ {
|
||||
"Test folder-level sinks."
|
||||
logging_sinks = """ {
|
||||
warning = {
|
||||
type = "gcs"
|
||||
destination = "mybucket"
|
||||
filter = "severity=WARNING"
|
||||
iam = true
|
||||
include_children = true
|
||||
exclusions = {}
|
||||
type = "storage"
|
||||
destination = "mybucket"
|
||||
filter = "severity=WARNING"
|
||||
iam = true
|
||||
include_children = true
|
||||
bq_partitioned_table = null
|
||||
exclusions = {}
|
||||
}
|
||||
info = {
|
||||
type = "bigquery"
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
filter = "severity=INFO"
|
||||
iam = true
|
||||
include_children = true
|
||||
exclusions = {}
|
||||
type = "bigquery"
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
filter = "severity=INFO"
|
||||
iam = true
|
||||
include_children = true
|
||||
bq_partitioned_table = false
|
||||
exclusions = {}
|
||||
}
|
||||
notice = {
|
||||
type = "pubsub"
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
filter = "severity=NOTICE"
|
||||
iam = true
|
||||
include_children = false
|
||||
exclusions = {}
|
||||
type = "pubsub"
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
filter = "severity=NOTICE"
|
||||
iam = true
|
||||
include_children = false
|
||||
bq_partitioned_table = null
|
||||
exclusions = {}
|
||||
}
|
||||
debug = {
|
||||
type = "logging"
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
filter = "severity=DEBUG"
|
||||
iam = true
|
||||
include_children = false
|
||||
exclusions = {
|
||||
type = "logging"
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
filter = "severity=DEBUG"
|
||||
iam = true
|
||||
include_children = false
|
||||
bq_partitioned_table = null
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
no-container = "logName:container"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
_, resources = plan_runner(FIXTURES_DIR, logging_sinks=logging_sinks)
|
||||
assert len(resources) == 8
|
||||
_, resources = plan_runner(FIXTURES_DIR, logging_sinks=logging_sinks)
|
||||
assert len(resources) == 8
|
||||
|
||||
resource_types = Counter([r["type"] for r in resources])
|
||||
assert resource_types == {
|
||||
"google_logging_organization_sink": 4,
|
||||
"google_bigquery_dataset_iam_member": 1,
|
||||
"google_project_iam_member": 1,
|
||||
"google_pubsub_topic_iam_member": 1,
|
||||
"google_storage_bucket_iam_member": 1,
|
||||
}
|
||||
resource_types = Counter([r["type"] for r in resources])
|
||||
assert resource_types == {
|
||||
"google_logging_organization_sink": 4,
|
||||
"google_bigquery_dataset_iam_member": 1,
|
||||
"google_project_iam_member": 1,
|
||||
"google_pubsub_topic_iam_member": 1,
|
||||
"google_storage_bucket_iam_member": 1,
|
||||
}
|
||||
|
||||
sinks = [r for r in resources if r["type"] == "google_logging_organization_sink"]
|
||||
assert sorted([r["index"] for r in sinks]) == [
|
||||
"debug",
|
||||
"info",
|
||||
"notice",
|
||||
"warning",
|
||||
]
|
||||
values = [
|
||||
(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["include_children"],
|
||||
)
|
||||
for r in sinks
|
||||
]
|
||||
assert sorted(values) == [
|
||||
(
|
||||
"debug",
|
||||
"severity=DEBUG",
|
||||
"logging.googleapis.com/projects/myproject/locations/global/buckets/mybucket",
|
||||
False,
|
||||
),
|
||||
(
|
||||
"info",
|
||||
"severity=INFO",
|
||||
"bigquery.googleapis.com/projects/myproject/datasets/mydataset",
|
||||
True,
|
||||
),
|
||||
(
|
||||
"notice",
|
||||
"severity=NOTICE",
|
||||
"pubsub.googleapis.com/projects/myproject/topics/mytopic",
|
||||
False,
|
||||
),
|
||||
("warning", "severity=WARNING", "storage.googleapis.com/mybucket", True),
|
||||
]
|
||||
sinks = [r for r in resources if r["type"]
|
||||
== "google_logging_organization_sink"]
|
||||
assert sorted([r["index"] for r in sinks]) == [
|
||||
"debug",
|
||||
"info",
|
||||
"notice",
|
||||
"warning",
|
||||
]
|
||||
values = [
|
||||
(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["include_children"],
|
||||
)
|
||||
for r in sinks
|
||||
]
|
||||
assert sorted(values) == [
|
||||
(
|
||||
"debug",
|
||||
"severity=DEBUG",
|
||||
"logging.googleapis.com/projects/myproject/locations/global/buckets/mybucket",
|
||||
False,
|
||||
),
|
||||
(
|
||||
"info",
|
||||
"severity=INFO",
|
||||
"bigquery.googleapis.com/projects/myproject/datasets/mydataset",
|
||||
True,
|
||||
),
|
||||
(
|
||||
"notice",
|
||||
"severity=NOTICE",
|
||||
"pubsub.googleapis.com/projects/myproject/topics/mytopic",
|
||||
False,
|
||||
),
|
||||
("warning", "severity=WARNING", "storage.googleapis.com/mybucket", True),
|
||||
]
|
||||
|
||||
bindings = [r for r in resources if "member" in r["type"]]
|
||||
values = [(r["index"], r["type"], r["values"]["role"]) for r in bindings]
|
||||
assert sorted(values) == [
|
||||
("debug", "google_project_iam_member", "roles/logging.bucketWriter"),
|
||||
("info", "google_bigquery_dataset_iam_member", "roles/bigquery.dataEditor"),
|
||||
("notice", "google_pubsub_topic_iam_member", "roles/pubsub.publisher"),
|
||||
("warning", "google_storage_bucket_iam_member", "roles/storage.objectCreator"),
|
||||
]
|
||||
bindings = [r for r in resources if "member" in r["type"]]
|
||||
values = [(r["index"], r["type"], r["values"]["role"]) for r in bindings]
|
||||
assert sorted(values) == [
|
||||
("debug", "google_project_iam_member", "roles/logging.bucketWriter"),
|
||||
("info", "google_bigquery_dataset_iam_member", "roles/bigquery.dataEditor"),
|
||||
("notice", "google_pubsub_topic_iam_member", "roles/pubsub.publisher"),
|
||||
("warning", "google_storage_bucket_iam_member", "roles/storage.objectCreator"),
|
||||
]
|
||||
|
||||
exclusions = [(r["index"], r["values"]["exclusions"]) for r in sinks]
|
||||
assert sorted(exclusions) == [
|
||||
(
|
||||
"debug",
|
||||
[
|
||||
{
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:compute",
|
||||
"name": "no-compute",
|
||||
},
|
||||
{
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:container",
|
||||
"name": "no-container",
|
||||
},
|
||||
],
|
||||
),
|
||||
("info", []),
|
||||
("notice", []),
|
||||
("warning", []),
|
||||
]
|
||||
exclusions = [(r["index"], r["values"]["exclusions"]) for r in sinks]
|
||||
assert sorted(exclusions) == [
|
||||
(
|
||||
"debug",
|
||||
[
|
||||
{
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:compute",
|
||||
"name": "no-compute",
|
||||
},
|
||||
{
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:container",
|
||||
"name": "no-container",
|
||||
},
|
||||
],
|
||||
),
|
||||
("info", []),
|
||||
("notice", []),
|
||||
("warning", []),
|
||||
]
|
||||
|
||||
|
||||
def test_exclusions(plan_runner):
|
||||
"Test folder-level logging exclusions."
|
||||
logging_exclusions = (
|
||||
"{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}"
|
||||
)
|
||||
_, resources = plan_runner(FIXTURES_DIR, logging_exclusions=logging_exclusions)
|
||||
assert len(resources) == 2
|
||||
exclusions = [
|
||||
r for r in resources if r["type"] == "google_logging_organization_exclusion"
|
||||
]
|
||||
assert sorted([r["index"] for r in exclusions]) == [
|
||||
"exclusion1",
|
||||
"exclusion2",
|
||||
]
|
||||
values = [(r["index"], r["values"]["filter"]) for r in exclusions]
|
||||
assert sorted(values) == [
|
||||
("exclusion1", "resource.type=gce_instance"),
|
||||
("exclusion2", "severity=NOTICE"),
|
||||
]
|
||||
"Test folder-level logging exclusions."
|
||||
logging_exclusions = (
|
||||
"{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}"
|
||||
)
|
||||
_, resources = plan_runner(
|
||||
FIXTURES_DIR, logging_exclusions=logging_exclusions)
|
||||
assert len(resources) == 2
|
||||
exclusions = [
|
||||
r for r in resources if r["type"] == "google_logging_organization_exclusion"
|
||||
]
|
||||
assert sorted([r["index"] for r in exclusions]) == [
|
||||
"exclusion1",
|
||||
"exclusion2",
|
||||
]
|
||||
values = [(r["index"], r["values"]["filter"]) for r in exclusions]
|
||||
assert sorted(values) == [
|
||||
("exclusion1", "resource.type=gce_instance"),
|
||||
("exclusion2", "severity=NOTICE"),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user