Skip to content

Commit

Permalink
Add network tags support to the organization module (#979)
Browse files Browse the repository at this point in the history
  • Loading branch information
LucaPrete committed Nov 18, 2022
1 parent dea1a77 commit 4124ef4
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 91 deletions.
63 changes: 47 additions & 16 deletions modules/organization/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ module "org" {
"roles/resourcemanager.tagAdmin" = ["group:admins@example.com"]
}
values = {
dev = null
dev = {}
prod = {
description = "Environment: production."
iam = {
Expand All @@ -393,6 +393,34 @@ module "org" {
# tftest modules=1 resources=7
```

You can also define network tags, through a dedicated variable *network_tags*:

```hcl
module "org" {
source = "./fabric/modules/organization"
organization_id = var.organization_id
network_tags = {
net-environment = {
description = "This is a network tag."
network = "my_project/my_vpc"
iam = {
"roles/resourcemanager.tagAdmin" = ["group:admins@example.com"]
}
values = {
dev = null
prod = {
description = "Environment: production."
iam = {
"roles/resourcemanager.tagUser" = ["user:user1@example.com"]
}
}
}
}
}
}
# tftest modules=1 resources=5
```

<!-- TFDOC OPTS files:1 -->
<!-- BEGIN TFDOC -->

Expand All @@ -415,7 +443,7 @@ module "org" {

| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [organization_id](variables.tf#L225) | Organization id in organizations/nnnnnn format. | <code>string</code> || |
| [organization_id](variables.tf#L246) | Organization id in organizations/nnnnnn format. | <code>string</code> || |
| [contacts](variables.tf#L17) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [custom_roles](variables.tf#L24) | Map of role name => list of permissions to create in this project. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [firewall_policies](variables.tf#L31) | Hierarchical firewall policy rules created in the organization. | <code title="map&#40;map&#40;object&#40;&#123;&#10; action &#61; string&#10; description &#61; string&#10; direction &#61; string&#10; logging &#61; bool&#10; ports &#61; map&#40;list&#40;string&#41;&#41;&#10; priority &#61; number&#10; ranges &#61; list&#40;string&#41;&#10; target_resources &#61; list&#40;string&#41;&#10; target_service_accounts &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;&#41;">map&#40;map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
Expand All @@ -430,24 +458,27 @@ module "org" {
| [iam_bindings_authoritative](variables.tf#L116) | IAM authoritative bindings, in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared. Bindings should also be authoritative when using authoritative audit config. Use with caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> |
| [logging_exclusions](variables.tf#L122) | Logging exclusions for this organization in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L129) | Logging sinks to create for the organization. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies](variables.tf#L159) | Organization policies applied to this organization keyed by policy name. | <code title="map&#40;object&#40;&#123;&#10; inherit_from_parent &#61; optional&#40;bool&#41; &#35; for list policies only.&#10; reset &#61; optional&#40;bool&#41;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool, true&#41; &#35; for boolean policies only.&#10; rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool, true&#41; &#35; for boolean policies only.&#10; condition &#61; object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; expression &#61; optional&#40;string&#41;&#10; location &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10; &#125;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies_data_path](variables.tf#L199) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
| [org_policy_custom_constraints](variables.tf#L205) | Organization policiy custom constraints keyed by constraint name. | <code title="map&#40;object&#40;&#123;&#10; display_name &#61; optional&#40;string&#41;&#10; description &#61; optional&#40;string&#41;&#10; action_type &#61; string&#10; condition &#61; string&#10; method_types &#61; list&#40;string&#41;&#10; resource_types &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policy_custom_constraints_data_path](variables.tf#L219) | Path containing org policy custom constraints in YAML format. | <code>string</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L235) | Tag bindings for this organization, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L241) | Tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map&#40;object&#40;&#123;&#10; description &#61; string&#10; iam &#61; map&#40;list&#40;string&#41;&#41;&#10; values &#61; map&#40;object&#40;&#123;&#10; description &#61; string&#10; iam &#61; map&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>null</code> |
| [network_tags](variables.tf#L159) | Network tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; network &#61; string &#35; project_id&#47;vpc_name&#10; values &#61; optional&#40;map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies](variables.tf#L180) | Organization policies applied to this organization keyed by policy name. | <code title="map&#40;object&#40;&#123;&#10; inherit_from_parent &#61; optional&#40;bool&#41; &#35; for list policies only.&#10; reset &#61; optional&#40;bool&#41;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool, true&#41; &#35; for boolean policies only.&#10; rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool, true&#41; &#35; for boolean policies only.&#10; condition &#61; object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; expression &#61; optional&#40;string&#41;&#10; location &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10; &#125;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies_data_path](variables.tf#L220) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
| [org_policy_custom_constraints](variables.tf#L226) | Organization policiy custom constraints keyed by constraint name. | <code title="map&#40;object&#40;&#123;&#10; display_name &#61; optional&#40;string&#41;&#10; description &#61; optional&#40;string&#41;&#10; action_type &#61; string&#10; condition &#61; string&#10; method_types &#61; list&#40;string&#41;&#10; resource_types &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policy_custom_constraints_data_path](variables.tf#L240) | Path containing org policy custom constraints in YAML format. | <code>string</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L275) | Tag bindings for this organization, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L255) | Tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; values &#61; optional&#40;map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |

## Outputs

| name | description | sensitive |
|---|---|:---:|
| [custom_role_id](outputs.tf#L18) | Map of custom role IDs created in the organization. | |
| [custom_roles](outputs.tf#L31) | Map of custom roles resources created in the organization. | |
| [firewall_policies](outputs.tf#L36) | Map of firewall policy resources created in the organization. | |
| [firewall_policy_id](outputs.tf#L41) | Map of firewall policy ids created in the organization. | |
| [organization_id](outputs.tf#L46) | Organization id dependent on module resources. | |
| [sink_writer_identities](outputs.tf#L63) | Writer identities created for each sink. | |
| [tag_keys](outputs.tf#L71) | Tag key resources. | |
| [tag_values](outputs.tf#L78) | Tag value resources. | |
| [custom_role_id](outputs.tf#L17) | Map of custom role IDs created in the organization. | |
| [custom_roles](outputs.tf#L30) | Map of custom roles resources created in the organization. | |
| [firewall_policies](outputs.tf#L35) | Map of firewall policy resources created in the organization. | |
| [firewall_policy_id](outputs.tf#L40) | Map of firewall policy ids created in the organization. | |
| [network_tag_keys](outputs.tf#L45) | Tag key resources. | |
| [network_tag_values](outputs.tf#L52) | Tag value resources. | |
| [organization_id](outputs.tf#L60) | Organization id dependent on module resources. | |
| [sink_writer_identities](outputs.tf#L77) | Writer identities created for each sink. | |
| [tag_keys](outputs.tf#L85) | Tag key resources. | |
| [tag_values](outputs.tf#L92) | Tag value resources. | |

<!-- END TFDOC -->
21 changes: 18 additions & 3 deletions modules/organization/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* limitations under the License.
*/


output "custom_role_id" {
description = "Map of custom role IDs created in the organization."
value = {
Expand Down Expand Up @@ -43,6 +42,21 @@ output "firewall_policy_id" {
value = { for k, v in google_compute_firewall_policy.policy : k => v.id }
}

output "network_tag_keys" {
description = "Tag key resources."
value = {
for k, v in google_tags_tag_key.default : k => v if v.purpose != null
}
}

output "network_tag_values" {
description = "Tag value resources."
value = {
for k, v in google_tags_tag_value.default
: k => v if google_tags_tag_key.default[split("/", k)[0]].purpose != null
}
}

output "organization_id" {
description = "Organization id dependent on module resources."
value = var.organization_id
Expand Down Expand Up @@ -71,13 +85,14 @@ output "sink_writer_identities" {
output "tag_keys" {
description = "Tag key resources."
value = {
for k, v in google_tags_tag_key.default : k => v
for k, v in google_tags_tag_key.default : k => v if v.purpose == null
}
}

output "tag_values" {
description = "Tag value resources."
value = {
for k, v in google_tags_tag_value.default : k => v
for k, v in google_tags_tag_value.default
: k => v if google_tags_tag_key.default[split("/", k)[0]].purpose == null
}
}
31 changes: 14 additions & 17 deletions modules/organization/tags.tf
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ locals {
tag_values_iam = {
for t in local._tag_values_iam : "${t.key}:${t.role}" => t
}
tags = {
for k, v in coalesce(var.tags, {}) :
k => v == null ? { description = null, iam = {}, values = null } : v
}
tags = merge(var.tags, var.network_tags)
tags_iam = {
for t in local._tags_iam : "${t.tag}:${t.role}" => t
}
Expand All @@ -67,13 +64,16 @@ locals {
# keys
resource "google_tags_tag_key" "default" {
for_each = local.tags
parent = var.organization_id
short_name = each.key
description = coalesce(
each.value.description,
"Managed by the Terraform organization module."
for_each = local.tags
parent = var.organization_id
purpose = (
lookup(each.value, "network", null) == null ? null : "GCE_FIREWALL"
)
purpose_data = (
lookup(each.value, "network", null) == null ? null : { network = each.value.network }
)
short_name = each.key
description = each.value.description
depends_on = [
google_organization_iam_binding.authoritative,
google_organization_iam_member.additive,
Expand All @@ -93,13 +93,10 @@ resource "google_tags_tag_key_iam_binding" "default" {
# values
resource "google_tags_tag_value" "default" {
for_each = local.tag_values
parent = google_tags_tag_key.default[each.value.tag].id
short_name = each.value.name
description = coalesce(
each.value.description,
"Managed by the Terraform organization module."
)
for_each = local.tag_values
parent = google_tags_tag_key.default[each.value.tag].id
short_name = each.value.name
description = each.value.description
}
resource "google_tags_tag_value_iam_binding" "default" {
Expand Down
53 changes: 40 additions & 13 deletions modules/organization/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,27 @@ variable "logging_sinks" {
}
}

variable "network_tags" {
description = "Network tags by key name. The `iam` attribute behaves like the similarly named one at module level."
type = map(object({
description = optional(string, "Managed by the Terraform organization module.")
iam = optional(map(list(string)), {})
network = string # project_id/vpc_name
values = optional(map(object({
description = optional(string, "Managed by the Terraform organization module.")
iam = optional(map(list(string)), {})
})), {})
}))
nullable = false
default = {}
validation {
condition = alltrue([
for k, v in var.network_tags : v != null
])
error_message = "Use an empty map instead of null as value."
}
}

variable "org_policies" {
description = "Organization policies applied to this organization keyed by policy name."
type = map(object({
Expand Down Expand Up @@ -231,22 +252,28 @@ variable "organization_id" {
}
}

variable "tags" {
description = "Tags by key name. The `iam` attribute behaves like the similarly named one at module level."
type = map(object({
description = optional(string, "Managed by the Terraform organization module.")
iam = optional(map(list(string)), {})
values = optional(map(object({
description = optional(string, "Managed by the Terraform organization module.")
iam = optional(map(list(string)), {})
})), {})
}))
nullable = false
default = {}
validation {
condition = alltrue([
for k, v in var.tags : v != null
])
error_message = "Use an empty map instead of null as value."
}
}

variable "tag_bindings" {
description = "Tag bindings for this organization, in key => tag value id format."
type = map(string)
default = null
}

variable "tags" {
description = "Tags by key name. The `iam` attribute behaves like the similarly named one at module level."
type = map(object({
description = string
iam = map(list(string))
values = map(object({
description = string
iam = map(list(string))
}))
}))
default = null
}
1 change: 1 addition & 0 deletions tests/modules/organization/fixture/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module "test" {
iam_audit_config = var.iam_audit_config
logging_sinks = var.logging_sinks
logging_exclusions = var.logging_exclusions
network_tags = var.network_tags
org_policies = var.org_policies
org_policies_data_path = var.org_policies_data_path
org_policy_custom_constraints = var.org_policy_custom_constraints
Expand Down
5 changes: 5 additions & 0 deletions tests/modules/organization/fixture/test.network_tags.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
network_tags = {
net_environment = {
network = "foobar"
}
}
38 changes: 38 additions & 0 deletions tests/modules/organization/fixture/test.resource_tags.tfvars
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
tags = {
foo = {}
bar = {
description = null
iam = null
values = null
}
foobar = {
description = "Foobar tag."
iam = {
"roles/resourcemanager.tagAdmin" = [
"user:user1@example.com", "user:user2@example.com"
]
}
values = {
one = null
two = {
description = "Foobar 2."
iam = {
"roles/resourcemanager.tagViewer" = [
"user:user3@example.com"
]
}
}
three = {
description = "Foobar 3."
iam = {
"roles/resourcemanager.tagViewer" = [
"user:user3@example.com"
]
"roles/resourcemanager.tagAdmin" = [
"user:user4@example.com"
]
}
}
}
}
}
5 changes: 5 additions & 0 deletions tests/modules/organization/fixture/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ variable "logging_exclusions" {
default = {}
}

variable "network_tags" {
type = any
default = null
}

variable "org_policies" {
type = any
default = {}
Expand Down

0 comments on commit 4124ef4

Please sign in to comment.