Organization module (#57)

* modules/org: first shot

* modules/org: README

* update changelog
This commit is contained in:
Ludovico Magnocavallo
2020-04-07 18:47:07 +02:00
committed by GitHub
parent 2106c18dc5
commit 74e0035f4a
10 changed files with 492 additions and 1 deletions

View File

@@ -0,0 +1,53 @@
# Organization Module
This module allows managing several organization properties:
- IAM bindings, both authoritative and additive
- custom IAM roles
- audit logging configuration for services
- organization policies
## Example
```hcl
module "org" {
source = "./modules/organization"
org_id = 1234567890
iam_roles = ["roles/projectCreator"]
iam_members = { "roles/projectCreator" = ["group:cloud-admins@example.org"] }
policy_boolean = {
"constraints/compute.disableGuestAttributesAccess" = true
"constraints/compute.skipDefaultNetworkCreation" = true
}
policy_list = {
"constraints/compute.trustedImageProjects" = {
inherit_from_parent = null
suggested_value = null
status = true
values = ["projects/my-project"]
}
}
}
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| org_id | Organization id in nnnnnn format. | <code title="">number</code> | ✓ | |
| *custom_roles* | Map of role name => list of permissions to create in this project. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_additive_members* | Map of member lists used to set non authoritative bindings, keyed by role. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_additive_roles* | List of roles used to set non authoritative bindings. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *iam_audit_config* | Service audit logging configuration. Service as key, map of log permission (eg DATA_READ) and excluded members as value for each service. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *iam_members* | Map of member lists used to set authoritative bindings, keyed by role. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | List of roles used to set authoritative bindings. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *policy_boolean* | Map of boolean org policies and enforcement value, set value to null for policy restore. | <code title="map&#40;bool&#41;">map(bool)</code> | | <code title="">{}</code> |
| *policy_list* | Map of list org policies, status is true for allow, false for deny, null for restore. Values can only be used for allow or deny. | <code title="map&#40;object&#40;&#123;&#10;inherit_from_parent &#61; bool&#10;suggested_value &#61; string&#10;status &#61; bool&#10;values &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| org_id | Organization id dependent on module resources. | |
<!-- END TFDOC -->

View File

@@ -0,0 +1,138 @@
/**
* Copyright 2020 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.
*/
locals {
iam_additive_pairs = flatten([
for role in var.iam_additive_roles : [
for member in lookup(var.iam_additive_members, role, []) :
{ role = role, member = member }
]
])
iam_additive = {
for pair in local.iam_additive_pairs :
"${pair.role}-${pair.member}" => pair
}
}
resource "google_organization_iam_custom_role" "roles" {
for_each = var.custom_roles
org_id = var.org_id
role_id = each.key
title = "Custom role ${each.key}"
description = "Terraform-managed"
permissions = each.value
}
resource "google_organization_iam_binding" "authoritative" {
for_each = toset(var.iam_roles)
org_id = var.org_id
role = each.value
members = lookup(var.iam_members, each.value, [])
}
resource "google_organization_iam_member" "additive" {
for_each = length(var.iam_additive_roles) > 0 ? local.iam_additive : {}
org_id = var.org_id
role = each.value.role
member = each.value.member
}
resource "google_organization_iam_audit_config" "config" {
for_each = var.iam_audit_config
org_id = var.org_id
service = each.key
dynamic audit_log_config {
for_each = each.value
iterator = config
content {
log_type = config.key
exempted_members = config.value
}
}
}
resource "google_organization_policy" "boolean" {
for_each = var.policy_boolean
org_id = var.org_id
constraint = each.key
dynamic boolean_policy {
for_each = each.value == null ? [] : [each.value]
iterator = policy
content {
enforced = policy.value
}
}
dynamic restore_policy {
for_each = each.value == null ? [""] : []
content {
default = true
}
}
}
resource "google_organization_policy" "list" {
for_each = var.policy_list
org_id = var.org_id
constraint = each.key
dynamic list_policy {
for_each = each.value.status == null ? [] : [each.value]
iterator = policy
content {
inherit_from_parent = policy.value.inherit_from_parent
suggested_value = policy.value.suggested_value
dynamic allow {
for_each = policy.value.status ? [""] : []
content {
values = (
try(length(policy.value.values) > 0, false)
? policy.value.values
: null
)
all = (
try(length(policy.value.values) > 0, false)
? null
: true
)
}
}
dynamic deny {
for_each = policy.value.status ? [] : [""]
content {
values = (
try(length(policy.value.values) > 0, false)
? policy.value.values
: null
)
all = (
try(length(policy.value.values) > 0, false)
? null
: true
)
}
}
}
}
dynamic restore_policy {
for_each = each.value.status == null ? [true] : []
content {
default = true
}
}
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright 2020 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.
*/
output "org_id" {
description = "Organization id dependent on module resources."
value = var.org_id
depends_on = [
google_organization_iam_audit_config,
google_organization_iam_binding.authoritative,
google_organization_iam_custom_role.roles,
google_organization_iam_member.additive,
google_organization_policy.boolean,
google_organization_policy.list
]
}

View File

@@ -0,0 +1,78 @@
/**
* Copyright 2020 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 "custom_roles" {
description = "Map of role name => list of permissions to create in this project."
type = map(list(string))
default = {}
}
variable "iam_members" {
description = "Map of member lists used to set authoritative bindings, keyed by role."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "List of roles used to set authoritative bindings."
type = list(string)
default = []
}
variable "iam_additive_members" {
description = "Map of member lists used to set non authoritative bindings, keyed by role."
type = map(list(string))
default = {}
}
variable "iam_additive_roles" {
description = "List of roles used to set non authoritative bindings."
type = list(string)
default = []
}
variable "iam_audit_config" {
description = "Service audit logging configuration. Service as key, map of log permission (eg DATA_READ) and excluded members as value for each service."
type = map(map(list(string)))
default = {}
# default = {
# allServices = {
# DATA_READ = ["user:me@example.org"]
# }
# }
}
variable "org_id" {
description = "Organization id in nnnnnn format."
type = number
}
variable "policy_boolean" {
description = "Map of boolean org policies and enforcement value, set value to null for policy restore."
type = map(bool)
default = {}
}
variable "policy_list" {
description = "Map of list org policies, status is true for allow, false for deny, null for restore. Values can only be used for allow or deny."
type = map(object({
inherit_from_parent = bool
suggested_value = string
status = bool
values = list(string)
}))
default = {}
}

View File

@@ -0,0 +1,19 @@
/**
* Copyright 2019 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.
*/
terraform {
required_version = ">= 0.12.6"
}