Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorder org policy rules #1079

Merged
merged 4 commits into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 103 additions & 69 deletions modules/folder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

This module allows the creation and management of folders, including support for IAM bindings, organization policies, and hierarchical firewall rules.

## Examples

### IAM bindings
## Basic example with IAM bindings

```hcl
module "folder" {
Expand All @@ -14,17 +12,26 @@ module "folder" {
group_iam = {
"[email protected]" = [
"roles/owner",
"roles/resourcemanager.folderAdmin",
"roles/resourcemanager.projectCreator"
]
}
iam = {
"roles/owner" = ["user:[email protected]"]
"roles/owner" = ["user:[email protected]"]
}
iam_additive = {
"roles/compute.admin" = ["user:[email protected]", "user:[email protected]"]
"roles/compute.viewer" = ["user:[email protected]"]
}
iam_additive_members = {
"user:[email protected]" = ["roles/storage.admin"]
"user:[email protected]" = ["roles/storage.objectViewer"]
}
}
# tftest modules=1 resources=3
# tftest modules=1 resources=9 inventory=iam.yaml
```

### Organization policies
## Organization policies

To manage organization policies, the `orgpolicy.googleapis.com` service should be enabled in the quota project.

Expand Down Expand Up @@ -72,70 +79,14 @@ module "folder" {
}
}
}
# tftest modules=1 resources=8
# tftest modules=1 resources=8 inventory=org-policies.yaml
```

### Organization policy factory

See the [organization policy factory in the project module](../project#organization-policy-factory).

### Firewall policy factory

In the same way as for the [organization](../organization) module, the in-built factory allows you to define a single policy, using one file for rules, and an optional file for CIDR range substitution variables. Remember that non-absolute paths are relative to the root module (the folder where you run `terraform`).

```hcl
module "folder" {
source = "./fabric/modules/folder"
parent = "organizations/1234567890"
name = "Folder name"
firewall_policy_factory = {
cidr_file = "configs/firewall-policies/cidrs.yaml"
policy_name = null
rules_file = "configs/firewall-policies/rules.yaml"
}
firewall_policy_association = {
factory-policy = module.folder.firewall_policy_id["factory"]
}
}
# tftest modules=1 resources=5 files=cidrs,rules
```

```yaml
# tftest-file id=cidrs path=configs/firewall-policies/cidrs.yaml
rfc1918:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
```

```yaml
# tftest-file id=rules path=configs/firewall-policies/rules.yaml
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
```

### Logging Sinks
## Logging Sinks

```hcl
module "gcs" {
Expand Down Expand Up @@ -164,7 +115,6 @@ module "bucket" {
id = "bucket"
}


module "folder-sink" {
source = "./fabric/modules/folder"
parent = "folders/657104291943"
Expand Down Expand Up @@ -198,10 +148,19 @@ module "folder-sink" {
no-gce-instances = "resource.type=gce_instance"
}
}
# tftest modules=5 resources=14
# tftest modules=5 resources=14 inventory=logging.yaml
```

### Hierarchical firewall policies
## Hierarchical firewall policies

Hierarchical firewall policies can be managed in two ways:

- via the `firewall_policies` variable, to directly define policies and rules in Terraform
- via the `firewall_policy_factory` variable, to leverage external YaML files via a simple "factory" embedded in the module ([see here](../../blueprints/factories) for more context on factories)

Once you have policies (either created via the module or externally), you can associate them using the `firewall_policy_association` variable.

### Directly defined firewall policies

```hcl
module "folder1" {
Expand All @@ -211,6 +170,17 @@ module "folder1" {

firewall_policies = {
iap-policy = {
allow-admins = {
description = "Access from the admin subnet to all subnets"
direction = "INGRESS"
action = "allow"
priority = 1000
ranges = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
ports = { all = [] }
target_service_accounts = null
target_resources = null
logging = false
}
allow-iap-ssh = {
description = "Always allow ssh from IAP"
direction = "INGRESS"
Expand All @@ -237,7 +207,71 @@ module "folder2" {
iap-policy = module.folder1.firewall_policy_id["iap-policy"]
}
}
# tftest modules=2 resources=6
# tftest modules=2 resources=7 inventory=hfw.yaml
```
### Firewall policy factory

The in-built factory allows you to define a single policy, using one file for rules, and an optional file for CIDR range substitution variables. Remember that non-absolute paths are relative to the root module (the folder where you run `terraform`).

```hcl
module "folder1" {
source = "./fabric/modules/folder"
parent = var.organization_id
name = "policy-container"
firewall_policy_factory = {
cidr_file = "configs/firewall-policies/cidrs.yaml"
policy_name = "iap-policy"
rules_file = "configs/firewall-policies/rules.yaml"
}
firewall_policy_association = {
iap-policy = "iap-policy"
}
}

module "folder2" {
source = "./fabric/modules/folder"
parent = var.organization_id
name = "hf2"
firewall_policy_association = {
iap-policy = module.folder1.firewall_policy_id["iap-policy"]
}
}
# tftest modules=2 resources=7 files=cidrs,rules inventory=hfw.yaml
```

```yaml
# tftest-file id=cidrs path=configs/firewall-policies/cidrs.yaml
rfc1918:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
```

```yaml
# tftest-file id=rules path=configs/firewall-policies/rules.yaml
allow-admins:
description: Access from the admin subnet to all subnets
direction: INGRESS
action: allow
priority: 1000
ranges:
- $rfc1918
ports:
all: []
target_resources: null
logging: false

allow-iap-ssh:
description: "Always allow ssh from IAP"
direction: INGRESS
action: allow
priority: 100
ranges:
- 35.235.240.0/20
ports:
tcp: ["22"]
target_resources: null
logging: false
```

## Tags
Expand Down Expand Up @@ -269,7 +303,7 @@ module "folder" {
foo = "tagValues/12345678"
}
}
# tftest modules=2 resources=6
# tftest modules=2 resources=6 inventory=tags.yaml
```

<!-- TFDOC OPTS files:1 -->
Expand Down
34 changes: 17 additions & 17 deletions modules/folder/organization-policies.tf
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,6 @@ resource "google_org_policy_policy" "default" {
inherit_from_parent = each.value.inherit_from_parent
reset = each.value.reset

rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}

dynamic "rules" {
for_each = each.value.rules
iterator = rule
Expand All @@ -138,5 +121,22 @@ resource "google_org_policy_policy" "default" {
}
}
}

rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}
}
}
34 changes: 17 additions & 17 deletions modules/organization/organization-policies.tf
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,6 @@ resource "google_org_policy_policy" "default" {
inherit_from_parent = each.value.inherit_from_parent
reset = each.value.reset

rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}

dynamic "rules" {
for_each = each.value.rules
iterator = rule
Expand All @@ -138,6 +121,23 @@ resource "google_org_policy_policy" "default" {
}
}
}

rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}
}

depends_on = [
Expand Down
34 changes: 17 additions & 17 deletions modules/project/organization-policies.tf
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,6 @@ resource "google_org_policy_policy" "default" {
inherit_from_parent = each.value.inherit_from_parent
reset = each.value.reset

rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}

dynamic "rules" {
for_each = each.value.rules
iterator = rule
Expand All @@ -138,5 +121,22 @@ resource "google_org_policy_policy" "default" {
}
}
}

rules {
allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null
deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null
enforce = (
each.value.is_boolean_policy && each.value.enforce != null
? upper(tostring(each.value.enforce))
: null
)
dynamic "values" {
for_each = each.value.has_values ? [1] : []
content {
allowed_values = try(each.value.allow.values, null)
denied_values = try(each.value.deny.values, null)
}
}
}
}
}
5 changes: 5 additions & 0 deletions tests/examples/test_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ def test_example(plan_validator, tmp_path, example):
summary = plan_validator(module_path=tmp_path, inventory_paths=inventory,
tf_var_files=[])

import yaml
print(yaml.dump({"values": summary.values}))
print(yaml.dump({"counts": summary.counts}))
print(yaml.dump({"outputs": summary.outputs}))

counts = summary.counts
num_modules, num_resources = counts['modules'], counts['resources']
assert expected_modules == num_modules, 'wrong number of modules'
Expand Down
Loading