Add support for group-based IAM to resource management modules (#229)

* group_iam support for organization

* group_iam support for folder

* fix typo in variable description

* add group_iam to project module

* update project module README
This commit is contained in:
Ludovico Magnocavallo
2021-04-11 14:48:16 +02:00
committed by GitHub
parent 7154e2cee6
commit f8413cc98e
12 changed files with 206 additions and 96 deletions

View File

@@ -1,6 +1,6 @@
# Google Cloud Folder Module
This module allows the creation and management of folders together with their individual IAM bindings and organization policies.
This module allows the creation and management of folders, including support for IAM bindings, organization policies, and hierarchical firewall rules.
## Examples
@@ -11,11 +11,14 @@ module "folder" {
source = "./modules/folder"
parent = "organizations/1234567890"
name = "Folder name"
group_iam = {
"cloud-owners@example.org" = ["roles/owner", "roles/projectCreator"]
}
iam = {
"roles/owner" = ["group:users@example.com"]
"roles/owner" = ["user:one@example.com"]
}
}
# tftest:modules=1:resources=2
# tftest:modules=1:resources=3
```
### Organization policies
@@ -158,7 +161,6 @@ module "folder2" {
# tftest:modules=2:resources=6
```
<!-- BEGIN TFDOC -->
## Variables
@@ -168,7 +170,8 @@ module "folder2" {
| *firewall_policies* | Hierarchical firewall policies to *create* in this folder. | <code title="map&#40;map&#40;object&#40;&#123;&#10;description &#61; string&#10;direction &#61; string&#10;action &#61; string&#10;priority &#61; number&#10;ranges &#61; list&#40;string&#41;&#10;ports &#61; map&#40;list&#40;string&#41;&#41;&#10;target_service_accounts &#61; list&#40;string&#41;&#10;target_resources &#61; list&#40;string&#41;&#10;logging &#61; bool&#10;&#125;&#41;&#41;&#41;">map(map(object({...})))</code> | | <code title="">{}</code> |
| *firewall_policy_attachments* | List of hierarchical firewall policy IDs to *attach* to this folder. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *folder_create* | Create folder. When set to false, uses id to reference an existing folder. | <code title="">bool</code> | | <code title="">true</code> |
| *iam* | IAM bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(string))</code> | | <code title="">{}</code> |
| *group_iam* | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam* | IAM bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *id* | Folder ID in case you use folder_create=false | <code title="">string</code> | | <code title="">null</code> |
| *logging_exclusions* | Logging exclusions for this folder in the form {NAME -> FILTER}. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *logging_sinks* | Logging sinks to create for this folder. | <code title="map&#40;object&#40;&#123;&#10;destination &#61; string&#10;type &#61; string&#10;filter &#61; string&#10;iam &#61; bool&#10;include_children &#61; bool&#10;exclusions &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |

View File

@@ -21,6 +21,19 @@ locals {
merge(rule, { policy = policy, name = rule_name })
]
])
group_iam_roles = distinct(flatten(values(var.group_iam)))
group_iam = {
for r in local.group_iam_roles : r => [
for k, v in var.group_iam : "group:${k}" if try(index(v, r), null) != null
]
}
iam = {
for role in distinct(concat(keys(var.iam), keys(local.group_iam))) :
role => concat(
try(var.iam[role], []),
try(local.group_iam[role], [])
)
}
rules_map = {
for rule in local.extended_rules :
"${rule.policy}-${rule.name}" => rule
@@ -59,7 +72,7 @@ resource "google_folder" "folder" {
}
resource "google_folder_iam_binding" "authoritative" {
for_each = var.iam
for_each = local.iam
folder = local.folder.name
role = each.key
members = each.value

View File

@@ -14,9 +14,75 @@
* limitations under the License.
*/
variable "contacts" {
description = "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"
type = map(list(string))
default = {}
}
variable "firewall_policies" {
description = "Hierarchical firewall policies to *create* in this folder."
type = map(map(object({
description = string
direction = string
action = string
priority = number
ranges = list(string)
ports = map(list(string))
target_service_accounts = list(string)
target_resources = list(string)
logging = bool
})))
default = {}
}
variable "firewall_policy_attachments" {
description = "List of hierarchical firewall policy IDs to *attach* to this folder."
type = map(string)
default = {}
}
variable "folder_create" {
description = "Create folder. When set to false, uses id to reference an existing folder."
type = bool
default = true
}
variable "group_iam" {
description = "Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable."
type = map(list(string))
default = {}
}
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format."
type = map(set(string))
type = map(list(string))
default = {}
}
variable "id" {
description = "Folder ID in case you use folder_create=false"
type = string
default = null
}
variable "logging_sinks" {
description = "Logging sinks to create for this folder."
type = map(object({
destination = string
type = string
filter = string
iam = bool
include_children = bool
# TODO exclusions also support description and disabled
exclusions = map(string)
}))
default = {}
}
variable "logging_exclusions" {
description = "Logging exclusions for this folder in the form {NAME -> FILTER}."
type = map(string)
default = {}
}
@@ -52,63 +118,3 @@ variable "policy_list" {
}))
default = {}
}
variable "firewall_policies" {
description = "Hierarchical firewall policies to *create* in this folder."
type = map(map(object({
description = string
direction = string
action = string
priority = number
ranges = list(string)
ports = map(list(string))
target_service_accounts = list(string)
target_resources = list(string)
logging = bool
})))
default = {}
}
variable "firewall_policy_attachments" {
description = "List of hierarchical firewall policy IDs to *attach* to this folder."
type = map(string)
default = {}
}
variable "logging_sinks" {
description = "Logging sinks to create for this folder."
type = map(object({
destination = string
type = string
filter = string
iam = bool
include_children = bool
# TODO exclusions also support description and disabled
exclusions = map(string)
}))
default = {}
}
variable "logging_exclusions" {
description = "Logging exclusions for this folder in the form {NAME -> FILTER}."
type = map(string)
default = {}
}
variable "folder_create" {
description = "Create folder. When set to false, uses id to reference an existing folder."
type = bool
default = true
}
variable "id" {
description = "Folder ID in case you use folder_create=false"
type = string
default = null
}
variable "contacts" {
description = "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"
type = map(list(string))
default = {}
}