Merge pull request #153 from terraform-google-modules/terraform-0.13

Add support for Terraform 0.13 features
This commit is contained in:
Julio Castillo 2020-11-06 11:57:19 +01:00 committed by GitHub
commit 94e0268e3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
176 changed files with 1953 additions and 1691 deletions

View File

@ -40,6 +40,8 @@ steps:
entrypoint: pytest
args:
- -vv
- tests/cloud_operations
- tests/data_solutions
- tests/foundations
- tests/networking
env:

View File

@ -33,7 +33,7 @@ The current list of modules supports most of the core foundational and networkin
Currently available modules:
- **foundational** - [folders](./modules/folders), [log sinks](./modules/logging-sinks), [organization](./modules/organization), [project](./modules/project), [service accounts](./modules/iam-service-accounts)
- **foundational** - [folder](./modules/folder), [log sinks](./modules/logging-sinks), [organization](./modules/organization), [project](./modules/project), [service accounts](./modules/iam-service-account)
- **networking** - [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN static](./modules/net-vpn-static), [VPN dynamic](./modules/net-vpn-dynamic), [VPN HA](./modules/net-vpn-ha), [NAT](./modules/net-cloudnat), [address reservation](./modules/net-address), [DNS](./modules/dns), [L4 ILB](./modules/net-ilb), [Service Directory](./modules/service-directory), [Cloud Endpoints](./modules/cloudenpoints)
- **compute** - [VM/VM group](./modules/compute-vm), [MIG](./modules/compute-mig), [GKE cluster](./modules/gke-cluster), [GKE nodepool](./modules/gke-nodepool), [COS container](./modules/cos-container) (coredns, mysql, onprem, squid)
- **data** - [GCS](./modules/gcs), [BigQuery dataset](./modules/bigquery-dataset), [Pub/Sub](./modules/pubsub), [Datafusion](./modules/datafusion), [Bigtable instance](./modules/bigtable-instance)

View File

@ -41,8 +41,7 @@ module "project" {
"compute.zoneOperations.list"
]
}
iam_roles = [local.role_id]
iam_members = {
iam = {
(local.role_id) = [module.service-account.iam_email]
}
}
@ -64,10 +63,7 @@ module "pubsub" {
project_id = module.project.project_id
name = var.name
subscriptions = { "${var.name}-default" = null }
iam_roles = [
"roles/pubsub.publisher"
]
iam_members = {
iam = {
"roles/pubsub.publisher" = [
"serviceAccount:${module.project.service_accounts.robots.cloudasset}"
]
@ -75,9 +71,9 @@ module "pubsub" {
}
module "service-account" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = module.project.project_id
names = ["${var.name}-cf"]
name = "${var.name}-cf"
# iam_project_roles = { (module.project.project_id) = [local.role_id] }
}

View File

@ -77,26 +77,22 @@ module "service-directory" {
project_id = module.project.project_id
location = var.region
name = var.name
iam_members = {
iam = {
"roles/servicedirectory.editor" = [
module.vm-ns-editor.service_account_iam_email
]
}
iam_roles = ["roles/servicedirectory.editor"]
services = {
app1 = { endpoints = ["vm1", "vm2"], metadata = null }
app2 = { endpoints = ["vm1", "vm2"], metadata = null }
}
service_iam_members = {
service_iam = {
app1 = {
"roles/servicedirectory.editor" = [
module.vm-svc-editor.service_account_iam_email
]
}
}
service_iam_roles = {
app1 = ["roles/servicedirectory.editor"]
}
endpoint_config = {
"app1/vm1" = { address = "127.0.0.2", port = 80, metadata = {} }
"app1/vm2" = { address = "127.0.0.3", port = 80, metadata = {} }

View File

@ -34,10 +34,7 @@ module "project" {
disable_on_destroy = false,
disable_dependent_services = false
}
iam_roles = [
"roles/monitoring.metricWriter",
]
iam_members = {
iam = {
"roles/monitoring.metricWriter" = [module.cf.service_account_iam_email]
}
}

View File

@ -1,4 +1,4 @@
# Copyright 2019 Google LLC
# 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.

View File

@ -17,6 +17,7 @@
###############################################################################
# Projects #
###############################################################################
module "project" {
source = "../../modules/project"
name = var.project_id
@ -35,9 +36,9 @@ module "project" {
}
module "service-account" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = module.project.project_id
names = ["${var.name}-cf"]
name = "${var.name}-cf"
iam_project_roles = {
(var.project_id) = ["roles/cloudasset.viewer"]
}
@ -46,6 +47,7 @@ module "service-account" {
###############################################################################
# Pub/Sub #
###############################################################################
module "pubsub" {
source = "../../modules/pubsub"
project_id = module.project.project_id
@ -60,6 +62,7 @@ module "pubsub" {
###############################################################################
# Cloud Function #
###############################################################################
module "cf" {
source = "../../modules/cloud-function"
project_id = module.project.project_id
@ -88,6 +91,7 @@ resource "random_pet" "random" {
###############################################################################
# Cloud Scheduler #
###############################################################################
resource "google_app_engine_application" "app" {
project = module.project.project_id
location_id = var.location
@ -116,6 +120,7 @@ resource "google_cloud_scheduler_job" "job" {
###############################################################################
# Bigquery #
###############################################################################
module "bq" {
source = "../../modules/bigquery-dataset"
project_id = module.project.project_id

View File

@ -1,17 +0,0 @@
# 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
#
# https://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"
}

View File

@ -79,10 +79,7 @@ module "kms" {
location = var.location
}
keys = { key-gce = null, key-gcs = null }
key_iam_roles = {
key-gce = ["roles/cloudkms.cryptoKeyEncrypterDecrypter"]
}
key_iam_members = {
key_iam = {
key-gce = {
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
"serviceAccount:${module.project-service.service_accounts.robots.compute}",
@ -145,11 +142,9 @@ module "kms_vm_example" {
###############################################################################
module "kms-gcs" {
source = "../../modules/gcs"
project_id = module.project-service.project_id
prefix = "my-bucket-001"
names = ["kms-gcs"]
encryption_keys = {
kms-gcs = module.kms.keys.key-gce.self_link,
}
source = "../../modules/gcs"
project_id = module.project-service.project_id
prefix = "my-bucket-001"
name = "kms-gcs"
encryption_key = module.kms.keys.key-gcs.self_link
}

View File

@ -13,19 +13,13 @@
# limitations under the License.
output "bucket" {
description = "GCS Bucket Cloud KMS crypto keys."
value = {
for bucket in module.kms-gcs.buckets :
bucket.name => bucket.url
}
description = "GCS Bucket URL."
value = module.kms-gcs.url
}
output "bucket_keys" {
description = "GCS Bucket Cloud KMS crypto keys."
value = {
for bucket in module.kms-gcs.buckets :
bucket.name => bucket.encryption
}
value = module.kms-gcs.bucket.encryption
}
output "projects" {

View File

@ -57,9 +57,9 @@ module "project-kms" {
###############################################################################
module "service-account-bq" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = module.project-service.project_id
names = ["bq-test"]
name = "bq-test"
iam_project_roles = {
(var.project_service_name) = [
"roles/logging.logWriter",
@ -70,9 +70,9 @@ module "service-account-bq" {
}
module "service-account-gce" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = module.project-service.project_id
names = ["gce-test"]
name = "gce-test"
iam_project_roles = {
(var.project_service_name) = [
"roles/logging.logWriter",
@ -86,9 +86,9 @@ module "service-account-gce" {
}
module "service-account-df" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = module.project-service.project_id
names = ["df-test"]
name = "df-test"
iam_project_roles = {
(var.project_service_name) = [
"roles/dataflow.worker",
@ -120,12 +120,7 @@ module "kms" {
location = var.location
}
keys = { key-gce = null, key-gcs = null, key-bq = null }
key_iam_roles = {
key-gce = ["roles/cloudkms.cryptoKeyEncrypterDecrypter"]
key-gcs = ["roles/cloudkms.cryptoKeyEncrypterDecrypter"]
key-bq = ["roles/cloudkms.cryptoKeyEncrypterDecrypter"]
}
key_iam_members = {
key_iam = {
key-gce = {
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
"serviceAccount:${module.project-service.service_accounts.robots.compute}",
@ -155,10 +150,7 @@ module "kms-regional" {
location = var.region
}
keys = { key-df = null }
key_iam_roles = {
key-df = ["roles/cloudkms.cryptoKeyEncrypterDecrypter"]
}
key_iam_members = {
key_iam = {
key-df = {
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
"serviceAccount:${module.project-service.service_accounts.robots.dataflow}",
@ -254,38 +246,33 @@ module "vm_example" {
###############################################################################
module "kms-gcs" {
source = "../../modules/gcs"
project_id = module.project-service.project_id
prefix = module.project-service.project_id
names = ["data", "df-tmplocation"]
iam_roles = {
data = ["roles/storage.admin", "roles/storage.objectViewer"],
df-tmplocation = ["roles/storage.admin"]
}
iam_members = {
source = "../../modules/gcs"
for_each = {
data = {
"roles/storage.admin" = [
"serviceAccount:${module.service-account-gce.email}",
],
"roles/storage.viewer" = [
"serviceAccount:${module.service-account-df.email}",
],
},
members = {
"roles/storage.admin" = [
"serviceAccount:${module.service-account-gce.email}",
],
"roles/storage.objectViewer" = [
"serviceAccount:${module.service-account-df.email}",
]
}
}
df-tmplocation = {
"roles/storage.admin" = [
"serviceAccount:${module.service-account-gce.email}",
"serviceAccount:${module.service-account-df.email}",
]
members = {
"roles/storage.admin" = [
"serviceAccount:${module.service-account-gce.email}",
"serviceAccount:${module.service-account-df.email}",
]
}
}
}
encryption_keys = {
data = module.kms.keys.key-gcs.self_link,
df-tmplocation = module.kms.keys.key-gcs.self_link,
}
force_destroy = {
data = true,
df-tmplocation = true,
}
project_id = module.project-service.project_id
prefix = module.project-service.project_id
name = each.key
iam = each.value.members
encryption_key = module.kms.keys.key-gcs.self_link
force_destroy = true
}
###############################################################################
@ -297,10 +284,11 @@ module "bigquery-dataset" {
project_id = module.project-service.project_id
id = "bq_dataset"
access_roles = {
reader-group = { role = "READER", type = "domain" }
reader-group = { role = "READER", type = "service_account" }
owner = { role = "OWNER", type = "user_by_email" }
}
access_identities = {
reader-group = module.service-account-bq.email
owner = module.service-account-bq.email
}
encryption_key = module.kms.keys.key-bq.self_link

View File

@ -14,13 +14,13 @@
output "bq_tables" {
description = "Bigquery Tables."
value = module.bigquery-dataset.table_ids
value = module.bigquery-dataset.table_ids
}
output "buckets" {
description = "GCS Bucket Cloud KMS crypto keys."
value = {
for bucket in module.kms-gcs.buckets :
for name, bucket in module.kms-gcs :
bucket.name => bucket.url
}
}

View File

@ -21,9 +21,9 @@
# Shared folder
module "shared-folder" {
source = "../../modules/folders"
source = "../../modules/folder"
parent = var.root_node
names = ["shared"]
name = "shared"
}
# Terraform project
@ -34,7 +34,7 @@ module "tf-project" {
parent = module.shared-folder.id
prefix = var.prefix
billing_account = var.billing_account_id
iam_additive_bindings = {
iam_additive = {
for name in var.iam_terraform_owners : (name) => ["roles/owner"]
}
services = var.project_services
@ -45,7 +45,7 @@ module "tf-project" {
module "tf-gcs-bootstrap" {
source = "../../modules/gcs"
project_id = module.tf-project.project_id
names = ["tf-bootstrap"]
name = "tf-bootstrap"
prefix = "${var.prefix}-tf"
location = var.gcs_defaults.location
}
@ -96,14 +96,10 @@ module "audit-project" {
parent = var.root_node
prefix = var.prefix
billing_account = var.billing_account_id
iam_members = {
iam = {
"roles/bigquery.dataEditor" = [module.audit-log-sinks.writer_identities[0]]
"roles/viewer" = var.iam_audit_viewers
}
iam_roles = [
"roles/bigquery.dataEditor",
"roles/viewer"
]
services = concat(var.project_services, [
"bigquery.googleapis.com",
])
@ -147,7 +143,7 @@ module "shared-project" {
parent = module.shared-folder.id
prefix = var.prefix
billing_account = var.billing_account_id
iam_additive_bindings = {
iam_additive = {
for name in var.iam_shared_owners : (name) => ["roles/owner"]
}
services = var.project_services

View File

@ -33,7 +33,7 @@ If no shared services are needed, the shared service project module can of cours
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| billing_account_id | Billing account id used as to create projects. | <code title="">string</code> | ✓ | |
| environments | Environment short names. | <code title="list&#40;string&#41;">list(string)</code> | ✓ | |
| environments | Environment short names. | <code title="set&#40;string&#41;">set(string)</code> | ✓ | |
| organization_id | Organization id in organizations/nnnnnnnn format. | <code title="">string</code> | ✓ | |
| prefix | Prefix used for resources that need unique names. | <code title="">string</code> | ✓ | |
| root_node | Root node for the new hierarchy, either 'organizations/org_id' or 'folders/folder_id'. | <code title="">string</code> | ✓ | |

View File

@ -24,7 +24,7 @@ module "tf-project" {
parent = var.root_node
prefix = var.prefix
billing_account = var.billing_account_id
iam_additive_bindings = {
iam_additive = {
for name in var.iam_terraform_owners : (name) => ["roles/owner"]
}
services = var.project_services
@ -33,9 +33,10 @@ module "tf-project" {
# per-environment service accounts
module "tf-service-accounts" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
for_each = var.environments
project_id = module.tf-project.project_id
names = var.environments
name = each.value
prefix = var.prefix
iam_billing_roles = {
(var.billing_account_id) = (
@ -49,7 +50,7 @@ module "tf-service-accounts" {
var.iam_xpn_config.grant ? local.sa_xpn_org_roles : []
)
}
generate_keys = var.service_account_keys
generate_key = var.service_account_keys
}
# bootstrap Terraform state GCS bucket
@ -57,7 +58,7 @@ module "tf-service-accounts" {
module "tf-gcs-bootstrap" {
source = "../../modules/gcs"
project_id = module.tf-project.project_id
names = ["tf-bootstrap"]
name = "tf-bootstrap"
prefix = "${var.prefix}-tf"
location = var.gcs_location
}
@ -66,17 +67,13 @@ module "tf-gcs-bootstrap" {
module "tf-gcs-environments" {
source = "../../modules/gcs"
for_each = var.environments
project_id = module.tf-project.project_id
names = var.environments
name = each.value
prefix = "${var.prefix}-tf"
location = var.gcs_location
iam_roles = {
for name in var.environments : (name) => ["roles/storage.objectAdmin"]
}
iam_members = {
for name in var.environments : (name) => {
"roles/storage.objectAdmin" = [module.tf-service-accounts.iam_emails[name]]
}
iam = {
"roles/storage.objectAdmin" = [module.tf-service-accounts[each.value].iam_email]
}
}
@ -85,17 +82,13 @@ module "tf-gcs-environments" {
###############################################################################
module "environment-folders" {
source = "../../modules/folders"
parent = var.root_node
names = var.environments
iam_roles = {
for name in var.environments : (name) => local.folder_roles
}
iam_members = {
for name in var.environments : (name) => {
for role in local.folder_roles :
(role) => [module.tf-service-accounts.iam_emails[name]]
}
source = "../../modules/folder"
for_each = var.environments
parent = var.root_node
name = each.value
iam = {
for role in local.folder_roles :
(role) => [module.tf-service-accounts[each.value].iam_email]
}
}
@ -111,14 +104,10 @@ module "audit-project" {
parent = var.root_node
prefix = var.prefix
billing_account = var.billing_account_id
iam_members = {
iam = {
"roles/bigquery.dataEditor" = [module.audit-log-sinks.writer_identities[0]]
"roles/viewer" = var.iam_audit_viewers
}
iam_roles = [
"roles/bigquery.dataEditor",
"roles/viewer"
]
services = concat(var.project_services, [
"bigquery.googleapis.com",
])
@ -163,7 +152,7 @@ module "sharedsvc-project" {
parent = var.root_node
prefix = var.prefix
billing_account = var.billing_account_id
iam_additive_bindings = {
iam_additive = {
for name in var.iam_shared_owners : (name) => ["roles/owner"]
}
services = var.project_services

View File

@ -24,23 +24,23 @@ output "bootstrap_tf_gcs_bucket" {
output "environment_folders" {
description = "Top-level environment folders."
value = module.environment-folders.ids
value = { for folder in module.environment-folders : folder.name => folder.id }
}
output "environment_tf_gcs_buckets" {
description = "GCS buckets used for each environment Terraform state."
value = module.tf-gcs-environments.names
value = { for env, bucket in module.tf-gcs-environments : env => bucket.name }
}
output "environment_service_account_keys" {
description = "Service account keys used to run each environment Terraform modules."
sensitive = true
value = module.tf-service-accounts.keys
value = { for env, sa in module.tf-service-accounts : env => sa.key }
}
output "environment_service_accounts" {
description = "Service accounts used to run each environment Terraform modules."
value = module.tf-service-accounts.emails
value = { for env, sa in module.tf-service-accounts : env => sa.email }
}
output "audit_logs_bq_dataset" {

View File

@ -29,7 +29,7 @@ variable "billing_account_id" {
variable "environments" {
description = "Environment short names."
type = list(string)
type = set(string)
}
variable "gcs_location" {

View File

@ -10,11 +10,11 @@ Specific modules also offer support for non-authoritative bindings (e.g. `google
## Foundational modules
- [folders](./folders)
- [folder](./folder)
- [log sinks](./logging-sinks)
- [organization](./organization)
- [project](./project)
- [service accounts](./iam-service-accounts)
- [service account](./iam-service-account)
## Networking modules

View File

@ -13,8 +13,7 @@ module "docker_artifact_registry" {
location = "europe-west1"
format = "DOCKER"
id = "myregistry"
iam_roles = ["roles/artifactregistry.admin"]
iam_members = {
iam = {
"roles/artifactregistry.admin" = ["group:cicd@example.com"]
}
}
@ -29,8 +28,7 @@ module "docker_artifact_registry" {
| project_id | Registry project id. | <code title="">string</code> | ✓ | |
| *description* | An optional description for the repository | <code title="">string</code> | | <code title="">Terraform-managed registry</code> |
| *format* | Repository format. One of DOCKER or UNSPECIFIED | <code title="">string</code> | | <code title="">DOCKER</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> |
| *iam* | IAM bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *labels* | Labels to be attached to the registry. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *location* | Registry location. Use `gcloud beta artifacts locations list' to get valid values | <code title="">string</code> | | <code title=""></code> |

View File

@ -26,10 +26,10 @@ resource "google_artifact_registry_repository" "registry" {
resource "google_artifact_registry_repository_iam_binding" "bindings" {
provider = google-beta
for_each = toset(var.iam_roles)
for_each = var.iam
project = var.project_id
location = google_artifact_registry_repository.registry.location
repository = google_artifact_registry_repository.registry.name
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
}

View File

@ -14,18 +14,12 @@
* limitations under the License.
*/
variable "iam_members" {
description = "Map of member lists used to set authoritative bindings, keyed by role."
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "List of roles used to set authoritative bindings."
type = list(string)
default = []
}
variable "location" {
description = "Registry location. Use `gcloud beta artifacts locations list' to get valid values"
type = string

View File

@ -13,23 +13,21 @@ This module allows managing a single BigTable instance, including access configu
```hcl
module "big-table-instance" {
module "bigtable-instance" {
source = "./modules/bigtable-instance"
project_id = "my-project"
name = "instance"
cluster_id = "instance"
instance_type = "PRODUCTION"
zone = "europe-west1-b"
tables = {
test1 = { table_options = null },
test2 = { table_options = {
test1 = null,
test2 = {
split_keys = ["a", "b", "c"]
column_family = null
}
}
}
iam_roles = ["viewer"]
iam_members = {
viewer = ["user:viewer@testdomain.com"]
iam = {
"roles/bigtable.user" = ["user:viewer@testdomain.com"]
}
}
```
@ -45,13 +43,12 @@ module "big-table-instance" {
| *cluster_id* | The ID of the Cloud Bigtable cluster. | <code title="">string</code> | | <code title="">europe-west1</code> |
| *deletion_protection* | Whether or not to allow Terraform to destroy the instance. Unless this field is set to false in Terraform state, a terraform destroy or terraform apply that would delete the instance will fail. | <code title=""></code> | | <code title="">true</code> |
| *display_name* | The human-readable display name of the Bigtable instance. | <code title=""></code> | | <code title="">null</code> |
| *iam_members* | Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the instance are preserved. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *instance_type* | None | <code title="">string</code> | | <code title="">DEVELOPMENT</code> |
| *iam* | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *instance_type* | (deprecated) The instance type to create. One of 'DEVELOPMENT' or 'PRODUCTION'. | <code title="">string</code> | | <code title="">null</code> |
| *num_nodes* | The number of nodes in your Cloud Bigtable cluster. | <code title="">number</code> | | <code title="">1</code> |
| *storage_type* | The storage type to use. | <code title="">string</code> | | <code title="">SSD</code> |
| *table_options_defaults* | Default option of tables created in the BigTable instance. | <code title="object&#40;&#123;&#10;split_keys &#61; list&#40;string&#41;&#10;column_family &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;split_keys &#61; &#91;&#93;&#10;column_family &#61; null&#10;&#125;">...</code> |
| *tables* | Tables to be created in the BigTable instance. | <code title="map&#40;object&#40;&#123;&#10;table_options &#61; object&#40;&#123;&#10;split_keys &#61; list&#40;string&#41;&#10;column_family &#61; string&#10;&#125;&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *tables* | Tables to be created in the BigTable instance, options can be null. | <code title="map&#40;object&#40;&#123;&#10;split_keys &#61; list&#40;string&#41;&#10;column_family &#61; string&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
## Outputs

View File

@ -16,11 +16,7 @@
locals {
tables = {
for k, v in var.tables : k => v.table_options != null ? v.table_options : var.table_options_defaults
}
iam_roles_bindings = {
for k in var.iam_roles : k => lookup(var.iam_members, k, [])
for k, v in var.tables : k => v != null ? v : var.table_options_defaults
}
}
@ -39,11 +35,10 @@ resource "google_bigtable_instance" "default" {
}
resource "google_bigtable_instance_iam_binding" "default" {
for_each = local.iam_roles_bindings
for_each = var.iam
project = var.project_id
instance = google_bigtable_instance.default.name
role = "roles/bigtable.${each.key}"
role = each.key
members = each.value
}

View File

@ -18,8 +18,8 @@ output "id" {
description = "An identifier for the resource with format projects/{{project}}/instances/{{name}}."
value = google_bigtable_instance.default.id
depends_on = [
google_bigtable_instance_iam_binding,
google_bigtable_table
google_bigtable_instance_iam_binding.default,
google_bigtable_table.default
]
}
@ -27,8 +27,8 @@ output "instance" {
description = "BigTable intance."
value = google_bigtable_instance.default
depends_on = [
google_bigtable_instance_iam_binding,
google_bigtable_table
google_bigtable_instance_iam_binding.default,
google_bigtable_table.default
]
}

View File

@ -14,18 +14,6 @@
* limitations under the License.
*/
variable "iam_roles" {
description = "Authoritative for a given role. Updates the IAM policy to grant a role to a list of members."
type = list(string)
default = []
}
variable "iam_members" {
description = "Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the instance are preserved."
type = map(list(string))
default = {}
}
variable "cluster_id" {
description = "The ID of the Cloud Bigtable cluster."
type = string
@ -42,10 +30,16 @@ variable "display_name" {
default = null
}
variable "iam" {
description = "IAM bindings for topic in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "instance_type" {
description = "The instance type to create. One of \"DEVELOPMENT\" or \"PRODUCTION\". Defaults to \"DEVELOPMENT\""
description = "(deprecated) The instance type to create. One of 'DEVELOPMENT' or 'PRODUCTION'."
type = string
default = "DEVELOPMENT"
default = null
}
variable "name" {
@ -71,12 +65,10 @@ variable "storage_type" {
}
variable "tables" {
description = "Tables to be created in the BigTable instance."
description = "Tables to be created in the BigTable instance, options can be null."
type = map(object({
table_options = object({
split_keys = list(string)
column_family = string
})
split_keys = list(string)
column_family = string
}))
default = {}
}

View File

@ -63,8 +63,7 @@ module "cf-http" {
source_dir = "my-cf-source-folder"
output_path = "bundle.zip"
}
iam_roles = ["roles/cloudfunctions.invoker"]
iam_members = {
iam = {
"roles/cloudfunctions.invoker" = ["allUsers"]
}
}
@ -137,8 +136,7 @@ module "cf-http" {
| *bucket_config* | Enable and configure auto-created bucket. Set fields to null to use defaults. | <code title="object&#40;&#123;&#10;location &#61; string&#10;lifecycle_delete_age &#61; number&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *environment_variables* | Cloud function environment variables. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *function_config* | Cloud function configuration. | <code title="object&#40;&#123;&#10;entry_point &#61; string&#10;ingress_settings &#61; string&#10;instances &#61; number&#10;memory &#61; number&#10;runtime &#61; string&#10;timeout &#61; number&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;entry_point &#61; &#34;main&#34;&#10;ingress_settings &#61; null&#10;instances &#61; 1&#10;memory &#61; 256&#10;runtime &#61; &#34;python37&#34;&#10;timeout &#61; 180&#10;&#125;">...</code> |
| *iam_members* | Map of member lists used to set authoritative bindings, keyed by role. Ignored for template use. | <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. Ignored for template use. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *iam* | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *ingress_settings* | Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL and ALLOW_INTERNAL_ONLY. | <code title="">string</code> | | <code title="">null</code> |
| *labels* | Resource labels | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *prefix* | Optional prefix used for resource names. | <code title="">string</code> | | <code title="">null</code> |

View File

@ -95,12 +95,12 @@ resource "google_cloudfunctions_function" "function" {
}
resource "google_cloudfunctions_function_iam_binding" "default" {
for_each = toset(var.iam_roles)
for_each = var.iam
project = var.project_id
region = var.region
cloud_function = google_cloudfunctions_function.function.name
role = each.value
members = try(var.iam_members[each.value], {})
role = each.key
members = each.value
}
resource "google_storage_bucket" "bucket" {

View File

@ -42,18 +42,6 @@ variable "environment_variables" {
default = {}
}
variable "iam_members" {
description = "Map of member lists used to set authoritative bindings, keyed by role. Ignored for template use."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "List of roles used to set authoritative bindings. Ignored for template use."
type = list(string)
default = []
}
variable "function_config" {
description = "Cloud function configuration."
type = object({
@ -74,6 +62,12 @@ variable "function_config" {
}
}
variable "iam" {
description = "IAM bindings for topic in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "ingress_settings" {
description = "Control traffic that reaches the cloud function. Allowed values are ALLOW_ALL and ALLOW_INTERNAL_ONLY."
type = string

View File

@ -184,8 +184,7 @@ module "instance-group" {
| *encryption* | Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk. | <code title="object&#40;&#123;&#10;encrypt_boot &#61; bool&#10;disk_encryption_key_raw &#61; string&#10;kms_key_self_link &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *group* | Define this variable to create an instance group for instances. Disabled for template use. | <code title="object&#40;&#123;&#10;named_ports &#61; map&#40;number&#41;&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *hostname* | Instance FQDN name. | <code title="">string</code> | | <code title="">null</code> |
| *iam_members* | Map of member lists used to set authoritative bindings, keyed by role. Ignored for template use. | <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. Ignored for template use. | <code title="list&#40;string&#41;">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> |
| *instance_count* | Number of instances to create (only for non-template usage). | <code title="">number</code> | | <code title="">1</code> |
| *instance_type* | Instance type. | <code title="">string</code> | | <code title="">f1-micro</code> |
| *labels* | Instance labels. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |

View File

@ -25,9 +25,9 @@ locals {
for pair in setproduct(keys(local.names), keys(local.attached_disks)) :
"${pair[0]}-${pair[1]}" => { disk_name = pair[1], name = pair[0] }
}
iam_roles = var.use_instance_template ? {} : {
for pair in setproduct(var.iam_roles, keys(local.names)) :
"${pair.0}/${pair.1}" => { role = pair.0, name = pair.1 }
iam_members = var.use_instance_template ? {} : {
for pair in setproduct(keys(var.iam), keys(local.names)) :
"${pair.0}/${pair.1}" => { role = pair.0, name = pair.1, members = var.iam[pair.0] }
}
names = (
var.use_instance_template ? { (var.name) = 0 } : {
@ -196,12 +196,12 @@ resource "google_compute_instance" "default" {
}
resource "google_compute_instance_iam_binding" "default" {
for_each = local.iam_roles
for_each = local.iam_members
project = var.project_id
zone = local.zones[each.value.name]
instance_name = each.value.name
role = each.value.role
members = lookup(var.iam_members, each.value.role, [])
members = each.value.members
depends_on = [google_compute_instance.default]
}

View File

@ -90,18 +90,12 @@ variable "hostname" {
default = null
}
variable "iam_members" {
description = "Map of member lists used to set authoritative bindings, keyed by role. Ignored for template use."
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "List of roles used to set authoritative bindings. Ignored for template use."
type = list(string)
default = []
}
variable "instance_count" {
description = "Number of instances to create (only for non-template usage)."
type = number

View File

@ -9,8 +9,7 @@ module "container_registry" {
source = "../../modules/container-registry"
project_id = "myproject"
location = "EU"
iam_roles = ["roles/storage.admin"]
iam_members = {
iam = {
"roles/storage.admin" = ["group:cicd@example.com"]
}
}
@ -22,8 +21,7 @@ module "container_registry" {
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| project_id | Registry project id. | <code title="">string</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="">null</code> |
| *iam_roles* | List of roles used to set authoritative bindings. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">null</code> |
| *iam* | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *location* | Registry location. Can be US, EU, ASIA or empty | <code title="">string</code> | | <code title=""></code> |
## Outputs

View File

@ -20,8 +20,8 @@ resource "google_container_registry" "registry" {
}
resource "google_storage_bucket_iam_binding" "bindings" {
for_each = toset(var.iam_roles)
for_each = var.iam
bucket = google_container_registry.registry.id
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
}

View File

@ -14,16 +14,10 @@
* limitations under the License.
*/
variable "iam_members" {
description = "Map of member lists used to set authoritative bindings, keyed by role."
variable "iam" {
description = "IAM bindings for topic in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = null
}
variable "iam_roles" {
description = "List of roles used to set authoritative bindings."
type = list(string)
default = null
default = {}
}
variable "location" {

View File

@ -37,7 +37,7 @@ module "private-dns" {
| *peer_network* | Peering network self link, only valid for 'peering' zone types. | <code title="">string</code> | | <code title="">null</code> |
| *recordsets* | List of DNS record objects to manage. | <code title="list&#40;object&#40;&#123;&#10;name &#61; string&#10;type &#61; string&#10;ttl &#61; number&#10;records &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">list(object({...}))</code> | | <code title="">[]</code> |
| *service_directory_namespace* | Service directory namespace id (URL), only valid for 'service-directory' zone types. | <code title="">string</code> | | <code title="">null</code> |
| *type* | Type of zone to create, valid values are 'public', 'private', 'forwarding', 'peering', 'service-directory'. | <code title="">string</code> | | <code title="">private</code> |
| *type* | Type of zone to create, valid values are 'public', 'private', 'forwarding', 'peering', 'service-directory'. | <code title="">string</code> | | <code title="private&#10;validation &#123;&#10;condition &#61; contains&#40;&#91;&#34;public&#34;, &#34;private&#34;, &#34;forwarding&#34;, &#34;peering&#34;, &#34;service-directory&#34;&#93;, var.type&#41;&#10;error_message &#61; &#34;Zone must be one of &#39;public&#39;, &#39;private&#39;, &#39;forwarding&#39;, &#39;peering&#39;, &#39;service-directory&#39;.&#34;&#10;&#125;">...</code> |
| *zone_create* | Create zone. When set to false, uses a data source to reference existing zone. | <code title="">bool</code> | | <code title="">true</code> |
## Outputs

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -22,10 +22,10 @@ locals {
zone = (
var.zone_create
? try(
google_dns_managed_zone.non-public.0, try(
google_dns_managed_zone.public.0, null
)
google_dns_managed_zone.non-public.0, try(
google_dns_managed_zone.public.0, null
)
)
: try(data.google_dns_managed_zone.public.0, null)
)
dns_keys = try(
@ -34,12 +34,12 @@ locals {
}
resource "google_dns_managed_zone" "non-public" {
count = (var.zone_create && var.type != "public" ) ? 1 : 0
count = (var.zone_create && var.type != "public") ? 1 : 0
provider = google-beta
project = var.project_id
name = var.name
dns_name = var.domain
description = "Terraform-managed zone."
description = var.description
visibility = "private"
dynamic forwarding_config {
@ -94,12 +94,12 @@ resource "google_dns_managed_zone" "non-public" {
}
data "google_dns_managed_zone" "public" {
count = var.zone_create ? 0 : 1
name = var.name
count = var.zone_create ? 0 : 1
name = var.name
}
resource "google_dns_managed_zone" "public" {
count = (var.zone_create && var.type == "public" ) ? 1 : 0
count = (var.zone_create && var.type == "public") ? 1 : 0
project = var.project_id
name = var.name
dns_name = var.domain
@ -132,7 +132,7 @@ resource "google_dns_managed_zone" "public" {
}
data "google_dns_keys" "dns_keys" {
count = var.zone_create && ( var.dnssec_config == {} || var.type != "public" ) ? 0 : 1
count = var.zone_create && (var.dnssec_config == {} || var.type != "public") ? 0 : 1
managed_zone = local.zone.id
}

View File

@ -97,6 +97,10 @@ variable "type" {
description = "Type of zone to create, valid values are 'public', 'private', 'forwarding', 'peering', 'service-directory'."
type = string
default = "private"
validation {
condition = contains(["public", "private", "forwarding", "peering", "service-directory"], var.type)
error_message = "Zone must be one of 'public', 'private', 'forwarding', 'peering', 'service-directory'."
}
}
variable "zone_create" {
@ -106,3 +110,4 @@ variable "zone_create" {
}

View File

@ -15,7 +15,7 @@
*/
terraform {
required_version = ">= 0.12.20"
required_version = ">= 0.13.0"
required_providers {
google = "~> 3.10"
google-beta = "~> 3.20"

View File

@ -1,6 +1,6 @@
# Google Cloud Endpoints
This module allows simple management of ['Google Cloud Endpoints'](https://cloud.google.com/endpoints/) services. It supports creating ['OpenAPI'](https://cloud.google.com/endpoints/docs/openapi) or ['gRPC'](https://cloud.google.com/endpoints/docs/grpc/about-grpc) endpoints.
This module allows simple management of ['Google Cloud Endpoints'](https://cloud.google.com/endpoints/) services. It supports creating ['OpenAPI'](https://cloud.google.com/endpoints/docs/openapi) or ['gRPC'](https://cloud.google.com/endpoints/docs/grpc/about-grpc) endpoints.
## Examples
@ -12,26 +12,23 @@ module "endpoint" {
project_id = "my-project"
service_name = "YOUR-API.endpoints.YOUR-PROJECT-ID.cloud.goog"
openapi_config = { "yaml_path" = "openapi.yaml" }
grpc_config = null
iam_roles = ["servicemanagement.serviceController"]
iam_members = {
"servicemanagement.serviceController" = ["serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com"]
iam = {
"servicemanagement.serviceController" = ["serviceAccount:123456890-compute@developer.gserviceaccount.com"]
}
}
```
[Here](https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/endpoints/getting-started/openapi.yaml) you can find an example of an openapi.yaml file. Once created the endpoint, remember to activate the service at project level.
[Here](https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/endpoints/getting-started/openapi.yaml) you can find an example of an openapi.yaml file. Once created the endpoint, remember to activate the service at project level.
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| grpc_config | The configuration for a gRPC enpoint. Either this or openapi_config must be specified. | <code title="object&#40;&#123;&#10;yaml_path &#61; string&#10;protoc_output_path &#61; string&#10;&#125;&#41;">object({...})</code> | ✓ | |
| openapi_config | The configuration for an OpenAPI endopoint. Either this or grpc_config must be specified. | <code title="object&#40;&#123;&#10;yaml_path &#61; string&#10;&#125;&#41;">object({...})</code> | ✓ | |
| service_name | The name of the service. Usually of the form '$apiname.endpoints.$projectid.cloud.goog'. | <code title="">string</code> | ✓ | |
| *iam_members* | Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the instance are preserved. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *grpc_config* | The configuration for a gRPC enpoint. Either this or openapi_config must be specified. | <code title="object&#40;&#123;&#10;yaml_path &#61; string&#10;protoc_output_path &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *iam* | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *project_id* | The project ID that the service belongs to. | <code title="">string</code> | | <code title="">null</code> |
## Outputs

View File

@ -14,12 +14,6 @@
* limitations under the License.
*/
locals {
iam_roles_bindings = {
for k in var.iam_roles : k => lookup(var.iam_members, k, [])
}
}
resource "google_endpoints_service" "default" {
project = var.project_id
service_name = var.service_name
@ -29,8 +23,8 @@ resource "google_endpoints_service" "default" {
}
resource "google_endpoints_service_iam_binding" "default" {
for_each = local.iam_roles_bindings
for_each = var.iam
service_name = google_endpoints_service.default.service_name
role = "roles/${each.key}"
role = each.key
members = each.value
}

View File

@ -16,27 +16,22 @@
variable "grpc_config" {
description = "The configuration for a gRPC enpoint. Either this or openapi_config must be specified."
type = object({
type = object({
yaml_path = string
protoc_output_path = string
})
default = null
}
variable "iam_roles" {
description = "Authoritative for a given role. Updates the IAM policy to grant a role to a list of members."
type = list(string)
default = []
}
variable "iam_members" {
description = "Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the instance are preserved."
variable "iam" {
description = "IAM bindings for topic in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "openapi_config" {
description = "The configuration for an OpenAPI endopoint. Either this or grpc_config must be specified."
type = object({
type = object({
yaml_path = string
})
}

View File

@ -1,6 +1,6 @@
# Google Cloud Folder Module
This module allow creation and management of sets of folders sharing a common parent, and their individual IAM bindings. It also allows setting a common set of organization policies on all folders.
This module allows the creation and management of folders together with their individual IAM bindings and organization policies.
## Examples
@ -8,16 +8,11 @@ This module allow creation and management of sets of folders sharing a common pa
```hcl
module "folder" {
source = "./modules/folders"
source = "./modules/folder"
parent = "organizations/1234567890"
names = ["Folder one", "Folder two"]
iam_members = {
"Folder one" = {
"roles/owner" = ["group:users@example.com"]
}
}
iam_roles = {
"Folder one" = ["roles/owner"]
name = "Folder name"
iam = {
"roles/owner" = ["group:users@example.com"]
}
}
```
@ -26,9 +21,9 @@ module "folder" {
```hcl
module "folder" {
source = "./modules/folders"
source = "./modules/folder"
parent = "organizations/1234567890"
names = ["Folder one", "Folder two"]
name = "Folder name"
policy_boolean = {
"constraints/compute.disableGuestAttributesAccess" = true
"constraints/compute.skipDefaultNetworkCreation" = true
@ -49,10 +44,9 @@ module "folder" {
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| parent | Parent in folders/folder_id or organizations/org_id format. | <code title="">string</code> | ✓ | |
| *iam_members* | List of IAM members keyed by folder name and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">null</code> |
| *iam_roles* | List of IAM roles keyed by folder name. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">null</code> |
| *names* | Folder names. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| name | Folder name. | <code title="">string</code> | ✓ | |
| parent | Parent in folders/folder_id or organizations/org_id format. | <code title="string&#10;validation &#123;&#10;condition &#61; can&#40;regex&#40;&#34;&#40;organizations&#124;folders&#41;&#47;&#91;0-9&#93;&#43;&#34;, var.parent&#41;&#41;&#10;error_message &#61; &#34;Parent must be of the form folders&#47;folder_id or organizations&#47;organization_id.&#34;&#10;&#125;">string</code> | ✓ | |
| *iam* | IAM bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(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> |
@ -60,12 +54,7 @@ module "folder" {
| name | description | sensitive |
|---|---|:---:|
| folder | Folder resource (for single use). | |
| folders | Folder resources. | |
| id | Folder id (for single use). | |
| ids | Folder ids. | |
| ids_list | List of folder ids. | |
| name | Folder name (for single use). | |
| names | Folder names. | |
| names_list | List of folder names. | |
| folder | Folder resource. | |
| id | Folder id. | |
| name | Folder name. | |
<!-- END TFDOC -->

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -14,63 +14,26 @@
* limitations under the License.
*/
locals {
folders = (
local.has_folders
? [for name in var.names : google_folder.folders[name]]
: []
)
# needed when destroying
has_folders = length(google_folder.folders) > 0
iam_pairs = var.iam_roles == null ? [] : flatten([
for name, roles in var.iam_roles :
[for role in roles : { name = name, role = role }]
])
iam_keypairs = {
for pair in local.iam_pairs :
"${pair.name}-${pair.role}" => pair
}
iam_members = var.iam_members == null ? {} : var.iam_members
policy_boolean_pairs = {
for pair in setproduct(var.names, keys(var.policy_boolean)) :
"${pair.0}-${pair.1}" => {
folder = pair.0,
policy = pair.1,
policy_data = var.policy_boolean[pair.1]
}
}
policy_list_pairs = {
for pair in setproduct(var.names, keys(var.policy_list)) :
"${pair.0}-${pair.1}" => {
folder = pair.0,
policy = pair.1,
policy_data = var.policy_list[pair.1]
}
}
}
resource "google_folder" "folders" {
for_each = toset(var.names)
display_name = each.value
resource "google_folder" "folder" {
display_name = var.name
parent = var.parent
}
resource "google_folder_iam_binding" "authoritative" {
for_each = local.iam_keypairs
folder = google_folder.folders[each.value.name].name
role = each.value.role
members = lookup(
lookup(local.iam_members, each.value.name, {}), each.value.role, []
)
for_each = var.iam
folder = google_folder.folder.name
role = each.key
members = each.value
}
resource "google_folder_organization_policy" "boolean" {
for_each = local.policy_boolean_pairs
folder = google_folder.folders[each.value.folder].id
constraint = each.value.policy
for_each = var.policy_boolean
folder = google_folder.folder.name
constraint = each.key
dynamic boolean_policy {
for_each = each.value.policy_data == null ? [] : [each.value.policy_data]
for_each = each.value == null ? [] : [each.value]
iterator = policy
content {
enforced = policy.value
@ -78,7 +41,7 @@ resource "google_folder_organization_policy" "boolean" {
}
dynamic restore_policy {
for_each = each.value.policy_data == null ? [""] : []
for_each = each.value == null ? [""] : []
content {
default = true
}
@ -86,12 +49,12 @@ resource "google_folder_organization_policy" "boolean" {
}
resource "google_folder_organization_policy" "list" {
for_each = local.policy_list_pairs
folder = google_folder.folders[each.value.folder].id
constraint = each.value.policy
for_each = var.policy_list
folder = google_folder.folder.name
constraint = each.key
dynamic list_policy {
for_each = each.value.policy_data.status == null ? [] : [each.value.policy_data]
for_each = each.value.status == null ? [] : [each.value]
iterator = policy
content {
inherit_from_parent = policy.value.inherit_from_parent
@ -130,7 +93,7 @@ resource "google_folder_organization_policy" "list" {
}
dynamic restore_policy {
for_each = each.value.policy_data.status == null ? [true] : []
for_each = each.value.status == null ? [true] : []
content {
default = true
}

35
modules/folder/outputs.tf Normal file
View File

@ -0,0 +1,35 @@
/**
* 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 "folder" {
description = "Folder resource."
value = google_folder.folder
}
output "id" {
description = "Folder id."
value = google_folder.folder.name
depends_on = [
google_folder_iam_binding.authoritative,
google_folder_organization_policy.boolean,
google_folder_organization_policy.list
]
}
output "name" {
description = "Folder name."
value = google_folder.folder.display_name
}

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -14,27 +14,24 @@
* limitations under the License.
*/
variable "iam_members" {
description = "List of IAM members keyed by folder name and role."
type = map(map(list(string)))
default = null
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format."
type = map(set(string))
default = {}
}
variable "iam_roles" {
description = "List of IAM roles keyed by folder name."
type = map(list(string))
default = null
}
variable "names" {
description = "Folder names."
type = list(string)
default = []
variable "name" {
description = "Folder name."
type = string
}
variable "parent" {
description = "Parent in folders/folder_id or organizations/org_id format."
type = string
validation {
condition = can(regex("(organizations|folders)/[0-9]+", var.parent))
error_message = "Parent must be of the form folders/folder_id or organizations/organization_id."
}
}
variable "policy_boolean" {

View File

@ -15,5 +15,5 @@
*/
terraform {
required_version = ">= 0.12.6"
required_version = ">= 0.13.0"
}

View File

@ -36,10 +36,9 @@ module "folders-unit" {
| short_name | Short name used as GCS bucket and service account prefixes, do not use capital letters or spaces. | <code title="">string</code> | ✓ | |
| *environments* | Unit environments short names. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="&#123;&#10;non-prod &#61; &#34;Non production&#34;&#10;prod &#61; &#34;Production&#34;&#10;&#125;">...</code> |
| *gcs_defaults* | Defaults use for the state GCS buckets. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="&#123;&#10;location &#61; &#34;EU&#34;&#10;storage_class &#61; &#34;MULTI_REGIONAL&#34;&#10;&#125;">...</code> |
| *iam* | IAM bindings for the top-level folder in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_billing_config* | Grant billing user role to service accounts, defaults to granting on the billing account. | <code title="object&#40;&#123;&#10;grant &#61; bool&#10;target_org &#61; bool&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;grant &#61; true&#10;target_org &#61; false&#10;&#125;">...</code> |
| *iam_enviroment_roles* | IAM roles granted to the environment service account on the environment sub-folder. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="&#91;&#10;&#34;roles&#47;compute.networkAdmin&#34;,&#10;&#34;roles&#47;owner&#34;,&#10;&#34;roles&#47;resourcemanager.folderAdmin&#34;,&#10;&#34;roles&#47;resourcemanager.projectCreator&#34;,&#10;&#93;">...</code> |
| *iam_members* | IAM members for roles applied on the unit folder. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">null</code> |
| *iam_roles* | IAM roles applied on the unit folder. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">null</code> |
| *iam_xpn_config* | Grant Shared VPC creation roles to service accounts, defaults to granting at folder level. | <code title="object&#40;&#123;&#10;grant &#61; bool&#10;target_org &#61; bool&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;grant &#61; true&#10;target_org &#61; false&#10;&#125;">...</code> |
| *prefix* | Optional prefix used for GCS bucket names to ensure uniqueness. | <code title="">string</code> | | <code title="">null</code> |
| *service_account_keys* | Generate and store service account keys in the state file. | <code title="">bool</code> | | <code title="">false</code> |

View File

@ -16,12 +16,7 @@
locals {
folder_roles = concat(var.iam_enviroment_roles, local.sa_xpn_folder_roles)
iam_members = var.iam_members == null ? {} : var.iam_members
iam_roles = var.iam_roles == null ? [] : var.iam_roles
unit_iam_bindings = {
for role in local.iam_roles :
role => lookup(local.iam_members, role, [])
}
iam = var.iam == null ? {} : var.iam
folder_iam_service_account_bindings = {
for pair in setproduct(keys(var.environments), local.folder_roles) :
"${pair.0}-${pair.1}" => { environment = pair.0, role = pair.1 }

View File

@ -34,7 +34,7 @@ resource "google_folder" "environment" {
}
resource "google_folder_iam_binding" "unit" {
for_each = local.unit_iam_bindings
for_each = var.iam
folder = google_folder.unit.name
role = each.key
members = each.value
@ -92,9 +92,9 @@ resource "google_storage_bucket" "tfstate" {
var.prefix == null ? "" : "${var.prefix}-",
"${var.short_name}-${each.key}-tf"
])
location = var.gcs_defaults.location
storage_class = var.gcs_defaults.storage_class
force_destroy = false
location = var.gcs_defaults.location
storage_class = var.gcs_defaults.storage_class
force_destroy = false
uniform_bucket_level_access = true
versioning {
enabled = true

View File

@ -42,6 +42,12 @@ variable "gcs_defaults" {
}
}
variable "iam" {
description = "IAM bindings for the top-level folder in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_billing_config" {
description = "Grant billing user role to service accounts, defaults to granting on the billing account."
type = object({
@ -65,18 +71,6 @@ variable "iam_enviroment_roles" {
]
}
variable "iam_members" {
description = "IAM members for roles applied on the unit folder."
type = map(list(string))
default = null
}
variable "iam_roles" {
description = "IAM roles applied on the unit folder."
type = list(string)
default = null
}
variable "iam_xpn_config" {
description = "Grant Shared VPC creation roles to service accounts, defaults to granting at folder level."
type = object({

View File

@ -1,78 +0,0 @@
/**
* Copyright 2018 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 "folder" {
description = "Folder resource (for single use)."
value = local.has_folders ? local.folders[0] : null
}
output "id" {
description = "Folder id (for single use)."
value = local.has_folders ? local.folders[0].name : null
depends_on = [
google_folder_iam_binding.authoritative,
google_folder_organization_policy.boolean,
google_folder_organization_policy.list
]
}
output "name" {
description = "Folder name (for single use)."
value = local.has_folders ? local.folders[0].display_name : null
}
output "folders" {
description = "Folder resources."
value = local.folders
}
output "ids" {
description = "Folder ids."
value = (
local.has_folders
? zipmap(var.names, [for f in local.folders : f.name])
: {}
)
depends_on = [
google_folder_iam_binding.authoritative,
google_folder_organization_policy.boolean,
google_folder_organization_policy.list
]
}
output "names" {
description = "Folder names."
value = (
local.has_folders
? zipmap(var.names, [for f in local.folders : f.display_name])
: {}
)
}
output "ids_list" {
description = "List of folder ids."
value = [for f in local.folders : f.name]
depends_on = [
google_folder_iam_binding.authoritative,
google_folder_organization_policy.boolean,
google_folder_organization_policy.list
]
}
output "names_list" {
description = "List of folder names."
value = [for f in local.folders : f.display_name]
}

View File

@ -7,21 +7,13 @@
## Example
```hcl
module "buckets" {
module "bucket" {
source = "./modules/gcs"
project_id = "myproject"
prefix = "test"
names = ["bucket-one", "bucket-two"]
bucket_policy_only = {
bucket-one = false
}
iam_members = {
bucket-two = {
"roles/storage.admin" = ["group:storage@example.com"]
}
}
iam_roles = {
bucket-two = ["roles/storage.admin"]
name = "my-bucket"
iam = {
"roles/storage.admin" = ["group:storage@example.com"]
}
}
```
@ -29,56 +21,38 @@ module "buckets" {
### Example with Cloud KMS
```hcl
module "buckets" {
module "bucket" {
source = "./modules/gcs"
project_id = "myproject"
prefix = "test"
names = ["bucket-one", "bucket-two"]
bucket_policy_only = {
bucket-one = false
}
iam_members = {
bucket-two = {
"roles/storage.admin" = ["group:storage@example.com"]
}
}
iam_roles = {
bucket-two = ["roles/storage.admin"]
}
encryption_keys = {
bucket-two = local.kms_key.self_link,
name = "my-bucket"
iam = {
"roles/storage.admin" = ["group:storage@example.com"]
}
encryption_keys = local.kms_key.self_link
}
```
### Example with retention policy
```hcl
module "buckets" {
module "bucket" {
source = "./modules/gcs"
project_id = "myproject"
prefix = "test"
names = ["bucket-one", "bucket-two"]
bucket_policy_only = {
bucket-one = false
}
iam_members = {
bucket-two = {
"roles/storage.admin" = ["group:storage@example.com"]
}
}
iam_roles = {
bucket-two = ["roles/storage.admin"]
name = "my-bucket"
iam = {
"roles/storage.admin" = ["group:storage@example.com"]
}
retention_policies = {
bucket-one = { retention_period = 100 , is_locked = true}
bucket-two = { retention_period = 900 , is_locked = false}
retention_period = 100
is_locked = true
}
logging_config = {
bucket-one = { log_bucket = bucket_name_for_logging , log_object_prefix = null}
bucket-two = { log_bucket = bucket_name_for_logging , log_object_prefix = "logs_for_bucket_two"}
log_bucket = bucket_name_for_logging
log_object_prefix = null
}
}
```
@ -88,31 +62,25 @@ module "buckets" {
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| names | Bucket name suffixes. | <code title="list&#40;string&#41;">list(string)</code> | ✓ | |
| name | Bucket name suffix. | <code title="">string</code> | ✓ | |
| project_id | Bucket project id. | <code title="">string</code> | ✓ | |
| *uniform_bucket_level_access* | Optional map to enable object ACLs keyed by name, defaults to true. | <code title="map&#40;bool&#41;">map(bool)</code> | | <code title="">{}</code> |
| *encryption_keys* | Per-bucket KMS keys that will be used for encryption. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *force_destroy* | Optional map to set force destroy keyed by name, defaults to false. | <code title="map&#40;bool&#41;">map(bool)</code> | | <code title="">{}</code> |
| *iam_members* | IAM members keyed by bucket name and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *iam_roles* | IAM roles keyed by bucket name. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *encryption_key* | KMS key that will be used for encryption. | <code title="">string</code> | | <code title="">null</code> |
| *force_destroy* | Optional map to set force destroy keyed by name, defaults to false. | <code title="">bool</code> | | <code title="">false</code> |
| *iam* | IAM bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *labels* | Labels to be attached to all buckets. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *location* | Bucket location. | <code title="">string</code> | | <code title="">EU</code> |
| *logging_config* | Per-bucket logging. | <code title="map&#40;object&#40;&#123;&#10;log_bucket &#61; string&#10;log_object_prefix &#61; string&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *logging_config* | Bucket logging configuration. | <code title="object&#40;&#123;&#10;log_bucket &#61; string&#10;log_object_prefix &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *prefix* | Prefix used to generate the bucket name. | <code title="">string</code> | | <code title="">null</code> |
| *retention_policies* | Per-bucket retention policy. | <code title="map&#40;object&#40;&#123;&#10;retention_period &#61; number&#10;is_locked &#61; bool&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *storage_class* | Bucket storage class. | <code title="">string</code> | | <code title="">MULTI_REGIONAL</code> |
| *versioning* | Optional map to set versioning keyed by name, defaults to false. | <code title="map&#40;bool&#41;">map(bool)</code> | | <code title="">{}</code> |
| *retention_policy* | Bucket retention policy. | <code title="object&#40;&#123;&#10;retention_period &#61; number&#10;is_locked &#61; bool&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *storage_class* | Bucket storage class. | <code title="">string</code> | | <code title="MULTI_REGIONAL&#10;validation &#123;&#10;condition &#61; contains&#40;&#91;&#34;STANDARD&#34;, &#34;MULTI_REGIONAL&#34;, &#34;REGIONAL&#34;, &#34;NEARLINE&#34;, &#34;COLDLINE&#34;, &#34;ARCHIVE&#34;&#93;, var.storage_class&#41;&#10;error_message &#61; &#34;Storage class must be one of STANDARD, MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, ARCHIVE.&#34;&#10;&#125;">...</code> |
| *uniform_bucket_level_access* | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | <code title="">bool</code> | | <code title="">true</code> |
| *versioning* | Enable versioning, defaults to false. | <code title="">bool</code> | | <code title="">false</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| bucket | Bucket resource (for single use). | |
| buckets | Bucket resources. | |
| name | Bucket name (for single use). | |
| names | Bucket names. | |
| names_list | List of bucket names. | |
| url | Bucket URL (for single use). | |
| urls | Bucket URLs. | |
| urls_list | List of bucket URLs. | |
| bucket | Bucket resource. | |
| name | Bucket name. | |
| url | Bucket URL. | |
<!-- END TFDOC -->

View File

@ -15,85 +15,57 @@
*/
locals {
buckets = (
local.has_buckets
? [for name in var.names : google_storage_bucket.buckets[name]]
: []
)
# needed when destroying
has_buckets = length(google_storage_bucket.buckets) > 0
iam_pairs = var.iam_roles == null ? [] : flatten([
for name, roles in var.iam_roles :
[for role in roles : { name = name, role = role }]
])
iam_keypairs = {
for pair in local.iam_pairs :
"${pair.name}-${pair.role}" => pair
}
iam_members = var.iam_members == null ? {} : var.iam_members
prefix = (
var.prefix == null || var.prefix == "" # keep "" for backward compatibility
? ""
: join("-", [var.prefix, lower(var.location), ""])
)
kms_keys = {
for name in var.names : name => lookup(var.encryption_keys, name, null)
}
retention_policy = {
for name in var.names : name => lookup(var.retention_policies, name, null)
}
logging_config = {
for name in var.names : name => lookup(var.logging_config, name, null)
}
}
resource "google_storage_bucket" "buckets" {
for_each = toset(var.names)
name = "${local.prefix}${lower(each.key)}"
project = var.project_id
location = var.location
storage_class = var.storage_class
force_destroy = lookup(var.force_destroy, each.key, false)
uniform_bucket_level_access = lookup(var.uniform_bucket_level_access, each.key, true)
resource "google_storage_bucket" "bucket" {
name = "${local.prefix}${lower(var.name)}"
project = var.project_id
location = var.location
storage_class = var.storage_class
force_destroy = var.force_destroy
uniform_bucket_level_access = var.uniform_bucket_level_access
versioning {
enabled = lookup(var.versioning, each.key, false)
enabled = var.versioning
}
labels = merge(var.labels, {
location = lower(var.location)
name = lower(each.key)
name = lower(var.name)
storage_class = lower(var.storage_class)
})
dynamic encryption {
for_each = local.kms_keys[each.key] == null ? [] : [""]
for_each = var.encryption_key == null ? [] : [""]
content {
default_kms_key_name = local.kms_keys[each.key]
default_kms_key_name = var.encryption_key
}
}
dynamic retention_policy {
for_each = local.retention_policy[each.key] == null ? [] : [""]
for_each = var.retention_policy == null ? [] : [""]
content {
retention_period = local.retention_policy[each.key]["retention_period"]
is_locked = local.retention_policy[each.key]["is_locked"]
retention_period = var.retention_policy.retention_period
is_locked = var.retention_policy.is_locked
}
}
dynamic logging {
for_each = local.logging_config[each.key] == null ? [] : [""]
for_each = var.logging_config == null ? [] : [""]
content {
log_bucket = local.logging_config[each.key]["log_bucket"]
log_object_prefix = local.logging_config[each.key]["log_object_prefix"]
log_bucket = var.logging_config.log_bucket
log_object_prefix = var.logging_config.log_object_prefix
}
}
}
resource "google_storage_bucket_iam_binding" "bindings" {
for_each = local.iam_keypairs
bucket = google_storage_bucket.buckets[each.value.name].name
role = each.value.role
members = lookup(
lookup(local.iam_members, each.value.name, {}), each.value.role, []
)
for_each = var.iam
bucket = google_storage_bucket.bucket.name
role = each.key
members = each.value
}

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -15,49 +15,16 @@
*/
output "bucket" {
description = "Bucket resource (for single use)."
value = local.has_buckets ? local.buckets[0] : null
description = "Bucket resource."
value = google_storage_bucket.bucket
}
output "name" {
description = "Bucket name (for single use)."
value = local.has_buckets ? local.buckets[0].name : null
description = "Bucket name."
value = google_storage_bucket.bucket.name
}
output "url" {
description = "Bucket URL (for single use)."
value = local.has_buckets ? local.buckets[0].url : null
}
output "buckets" {
description = "Bucket resources."
value = local.buckets
}
output "names" {
description = "Bucket names."
value = (
local.has_buckets
? zipmap(var.names, [for b in local.buckets : lookup(b, "name", null)])
: {}
)
}
output "urls" {
description = "Bucket URLs."
value = (
local.has_buckets
? zipmap(var.names, [for b in local.buckets : b.url])
: {}
)
}
output "names_list" {
description = "List of bucket names."
value = [for b in local.buckets : b.name]
}
output "urls_list" {
description = "List of bucket URLs."
value = [for b in local.buckets : b.name]
description = "Bucket URL."
value = google_storage_bucket.bucket.url
}

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -15,33 +15,27 @@
*/
variable "uniform_bucket_level_access" {
description = "Optional map to allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API)."
type = map(bool)
default = {}
description = "Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API)."
type = bool
default = true
}
variable "force_destroy" {
description = "Optional map to set force destroy keyed by name, defaults to false."
type = map(bool)
default = {}
type = bool
default = false
}
variable "iam_members" {
description = "IAM members keyed by bucket name and role."
type = map(map(list(string)))
default = {}
}
variable "iam_roles" {
description = "IAM roles keyed by bucket name."
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "encryption_keys" {
description = "Per-bucket KMS keys that will be used for encryption."
type = map(string)
default = {}
variable "encryption_key" {
description = "KMS key that will be used for encryption."
type = string
default = null
}
variable "labels" {
@ -57,17 +51,17 @@ variable "location" {
}
variable "logging_config" {
description = "Per-bucket logging."
type = map(object({
description = "Bucket logging configuration."
type = object({
log_bucket = string
log_object_prefix = string
}))
default = {}
})
default = null
}
variable "names" {
description = "Bucket name suffixes."
type = list(string)
variable "name" {
description = "Bucket name suffix."
type = string
}
variable "prefix" {
@ -81,23 +75,27 @@ variable "project_id" {
type = string
}
variable "retention_policies" {
description = "Per-bucket retention policy."
type = map(object({
variable "retention_policy" {
description = "Bucket retention policy."
type = object({
retention_period = number
is_locked = bool
}))
default = {}
})
default = null
}
variable "storage_class" {
description = "Bucket storage class."
type = string
default = "MULTI_REGIONAL"
validation {
condition = contains(["STANDARD", "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", "ARCHIVE"], var.storage_class)
error_message = "Storage class must be one of STANDARD, MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, ARCHIVE."
}
}
variable "versioning" {
description = "Optional map to set versioning keyed by name, defaults to false."
type = map(bool)
default = {}
description = "Enable versioning, defaults to false."
type = bool
default = false
}

View File

@ -15,5 +15,5 @@
*/
terraform {
required_version = ">= 0.12.6"
required_version = ">= 0.13.0"
}

View File

@ -0,0 +1,52 @@
# Google Service Account Module
This module allows simplified creation and management of one a service account and its IAM bindings. A key can optionally be generated and will be stored in Terraform state. To use it create a sensitive output in your root modules referencing the `key` output, then extract the private key from the JSON formatted outputs.
## Example
```hcl
module "myproject-default-service-accounts" {
source = "./modules/iam-service-account"
project_id = "myproject"
name = "vm-default"
generate_key = true
# authoritative roles granted *on* the service accounts to other identities
iam = {
"roles/iam.serviceAccountUser" = ["user:foo@example.com"]
}
# non-authoritative roles granted *to* the service accounts on other resources
iam_project_roles = {
"myproject" = [
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
]
}
}
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| name | Name of the service account to create. | <code title="">string</code> | ✓ | |
| project_id | Project id where service account will be created. | <code title="">string</code> | ✓ | |
| *display_name* | Display name of the service account to create. | <code title="">string</code> | | <code title="">Terraform-managed.</code> |
| *generate_key* | Generate a key for service account. | <code title="">bool</code> | | <code title="">false</code> |
| *iam* | IAM bindings on the service account in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_billing_roles* | Project roles granted to the service account, by billing account id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_folder_roles* | Project roles granted to the service account, by folder id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_organization_roles* | Project roles granted to the service account, by organization id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_project_roles* | Project roles granted to the service account, by project id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_storage_roles* | Storage roles granted to the service account, by bucket name. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *prefix* | Prefix applied to service account names. | <code title="">string</code> | | <code title="">null</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| email | Service account email. | |
| iam_email | IAM-format service account email. | |
| key | Service account key. | ✓ |
| service_account | Service account resource. | |
<!-- END TFDOC -->

View File

@ -0,0 +1,124 @@
/**
* 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_billing_pairs = flatten([
for entity, roles in var.iam_billing_roles : [
for role in roles : [
{ entity = entity, role = role }
]
]
])
iam_folder_pairs = flatten([
for entity, roles in var.iam_folder_roles : [
for role in roles : [
{ entity = entity, role = role }
]
]
])
iam_organization_pairs = flatten([
for entity, roles in var.iam_organization_roles : [
for role in roles : [
{ entity = entity, role = role }
]
]
])
iam_project_pairs = flatten([
for entity, roles in var.iam_project_roles : [
for role in roles : [
{ entity = entity, role = role }
]
]
])
iam_storage_pairs = flatten([
for entity, roles in var.iam_storage_roles : [
for role in roles : [
{ entity = entity, role = role }
]
]
])
key = var.generate_key ? google_service_account_key.key["1"] : {}
prefix = var.prefix != null ? "${var.prefix}-" : ""
resource_iam_email = "serviceAccount:${google_service_account.service_account.email}"
}
resource "google_service_account" "service_account" {
project = var.project_id
account_id = "${local.prefix}${var.name}"
display_name = var.display_name
}
resource "google_service_account_key" "key" {
for_each = var.generate_key ? { 1 = 1 } : {}
service_account_id = google_service_account.service_account.email
}
resource "google_service_account_iam_binding" "roles" {
for_each = var.iam
service_account_id = google_service_account.service_account.name
role = each.key
members = each.value
}
resource "google_billing_account_iam_member" "billing-roles" {
for_each = {
for pair in local.iam_billing_pairs :
"${pair.entity}-${pair.role}" => pair
}
billing_account_id = each.value.entity
role = each.value.role
member = local.resource_iam_email
}
resource "google_folder_iam_member" "folder-roles" {
for_each = {
for pair in local.iam_folder_pairs :
"${pair.entity}-${pair.role}" => pair
}
folder = each.value.entity
role = each.value.role
member = local.resource_iam_email
}
resource "google_organization_iam_member" "organization-roles" {
for_each = {
for pair in local.iam_organization_pairs :
"${pair.entity}-${pair.role}" => pair
}
org_id = each.value.entity
role = each.value.role
member = local.resource_iam_email
}
resource "google_project_iam_member" "project-roles" {
for_each = {
for pair in local.iam_project_pairs :
"${pair.entity}-${pair.role}" => pair
}
project = each.value.entity
role = each.value.role
member = local.resource_iam_email
}
resource "google_storage_bucket_iam_member" "bucket-roles" {
for_each = {
for pair in local.iam_storage_pairs :
"${pair.entity}-${pair.role}" => pair
}
bucket = each.value.entity
role = each.value.role
member = local.resource_iam_email
}

View File

@ -0,0 +1,36 @@
/**
* 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 "service_account" {
description = "Service account resource."
value = google_service_account.service_account
}
output "email" {
description = "Service account email."
value = google_service_account.service_account.email
}
output "iam_email" {
description = "IAM-format service account email."
value = local.resource_iam_email
}
output "key" {
description = "Service account key."
sensitive = true
value = local.key
}

View File

@ -14,58 +14,57 @@
* limitations under the License.
*/
variable "generate_keys" {
description = "Generate keys for service accounts."
variable "generate_key" {
description = "Generate a key for service account."
type = bool
default = false
}
variable "iam_members" {
description = "Map of member lists which are granted authoritative roles on the service accounts, keyed by role."
variable "iam" {
description = "IAM bindings on the service account in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "List of authoritative roles granted on the service accounts."
type = list(string)
default = []
}
variable "iam_billing_roles" {
description = "Project roles granted to all service accounts, by billing account id."
description = "Project roles granted to the service account, by billing account id."
type = map(list(string))
default = {}
}
variable "iam_folder_roles" {
description = "Project roles granted to all service accounts, by folder id."
description = "Project roles granted to the service account, by folder id."
type = map(list(string))
default = {}
}
variable "iam_organization_roles" {
description = "Project roles granted to all service accounts, by organization id."
description = "Project roles granted to the service account, by organization id."
type = map(list(string))
default = {}
}
variable "iam_project_roles" {
description = "Project roles granted to all service accounts, by project id."
description = "Project roles granted to the service account, by project id."
type = map(list(string))
default = {}
}
variable "iam_storage_roles" {
description = "Storage roles granted to all service accounts, by bucket name."
description = "Storage roles granted to the service account, by bucket name."
type = map(list(string))
default = {}
}
variable "names" {
description = "Names of the service accounts to create."
type = list(string)
default = []
variable "name" {
description = "Name of the service account to create."
type = string
}
variable "display_name" {
description = "Display name of the service account to create."
type = string
default = "Terraform-managed."
}
variable "prefix" {

View File

@ -1,59 +0,0 @@
# Google Service Accounts Module
This module allows simplified creation and management of one or more service accounts and their IAM bindings. Keys can optionally be generated and will be stored in Terraform state. To use them create a sensitive output in your root modules referencing the `keys` or `key` outputs, then extract the private key from the JSON formatted outputs.
## Example
```hcl
module "myproject-default-service-accounts" {
source = "./modules/iam-service-accounts"
project_id = "myproject"
names = ["vm-default", "gke-node-default"]
generate_keys = true
# authoritative roles granted *on* the service accounts to other identities
iam_roles = ["roles/iam.serviceAccountUser"]
iam_members = {
"roles/iam.serviceAccountUser" = ["user:foo@example.com"]
}
# non-authoritative roles granted *to* the service accounts on other resources
iam_project_roles = {
"myproject" = [
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
]
}
}
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| project_id | Project id where service account will be created. | <code title="">string</code> | ✓ | |
| *generate_keys* | Generate keys for service accounts. | <code title="">bool</code> | | <code title="">false</code> |
| *iam_billing_roles* | Project roles granted to all service accounts, by billing account id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_folder_roles* | Project roles granted to all service accounts, by folder id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_members* | Map of member lists which are granted authoritative roles on the service accounts, keyed by role. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_organization_roles* | Project roles granted to all service accounts, by organization id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_project_roles* | Project roles granted to all service accounts, by project id. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | List of authoritative roles granted on the service accounts. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *iam_storage_roles* | Storage roles granted to all service accounts, by bucket name. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *names* | Names of the service accounts to create. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *prefix* | Prefix applied to service account names. | <code title="">string</code> | | <code title="">null</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| email | Service account email (for single use). | |
| emails | Service account emails. | |
| emails_list | Service account emails. | |
| iam_email | IAM-format service account email (for single use). | |
| iam_emails | IAM-format service account emails. | |
| iam_emails_list | IAM-format service account emails. | |
| key | Service account key (for single use). | |
| keys | Map of service account keys. | ✓ |
| service_account | Service account resource (for single use). | |
| service_accounts | Service account resources. | |
<!-- END TFDOC -->

View File

@ -1,136 +0,0 @@
/**
* 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_pairs = {
for pair in setproduct(var.names, var.iam_roles) :
"${pair.0}-${pair.1}" => { name = pair.0, role = pair.1 }
}
iam_billing_pairs = flatten([
for entity, roles in var.iam_billing_roles : [
for role in roles : [
for name in var.names : { entity = entity, role = role, name = name }
]
]
])
iam_folder_pairs = flatten([
for entity, roles in var.iam_folder_roles : [
for role in roles : [
for name in var.names : { entity = entity, role = role, name = name }
]
]
])
iam_organization_pairs = flatten([
for entity, roles in var.iam_organization_roles : [
for role in roles : [
for name in var.names : { entity = entity, role = role, name = name }
]
]
])
iam_project_pairs = flatten([
for entity, roles in var.iam_project_roles : [
for role in roles : [
for name in var.names : { entity = entity, role = role, name = name }
]
]
])
iam_storage_pairs = flatten([
for entity, roles in var.iam_storage_roles : [
for role in roles : [
for name in var.names : { entity = entity, role = role, name = name }
]
]
])
keys = var.generate_keys ? google_service_account_key.keys : {}
prefix = var.prefix != null ? "${var.prefix}-" : ""
resource = try(google_service_account.service_accounts[var.names[0]], null)
resource_iam_emails = {
for name, resource in google_service_account.service_accounts :
name => "serviceAccount:${resource.email}"
}
}
resource "google_service_account" "service_accounts" {
for_each = toset(var.names)
project = var.project_id
account_id = "${local.prefix}${lower(each.value)}"
display_name = "Terraform-managed."
}
resource "google_service_account_key" "keys" {
for_each = var.generate_keys ? toset(var.names) : toset([])
service_account_id = google_service_account.service_accounts[each.value].email
}
resource "google_service_account_iam_binding" "sa-roles" {
for_each = local.iam_pairs
service_account_id = google_service_account.service_accounts[each.value.name].name
role = each.value.role
members = lookup(var.iam_members, each.value.role, [])
}
resource "google_billing_account_iam_member" "roles" {
for_each = {
for pair in local.iam_billing_pairs :
"${pair.name}-${pair.entity}-${pair.role}" => pair
}
billing_account_id = each.value.entity
role = each.value.role
member = local.resource_iam_emails[each.value.name]
}
resource "google_folder_iam_member" "roles" {
for_each = {
for pair in local.iam_folder_pairs :
"${pair.name}-${pair.entity}-${pair.role}" => pair
}
folder = each.value.entity
role = each.value.role
member = local.resource_iam_emails[each.value.name]
}
resource "google_organization_iam_member" "roles" {
for_each = {
for pair in local.iam_organization_pairs :
"${pair.name}-${pair.entity}-${pair.role}" => pair
}
org_id = each.value.entity
role = each.value.role
member = local.resource_iam_emails[each.value.name]
}
resource "google_project_iam_member" "project-roles" {
for_each = {
for pair in local.iam_project_pairs :
"${pair.name}-${pair.entity}-${pair.role}" => pair
}
project = each.value.entity
role = each.value.role
member = local.resource_iam_emails[each.value.name]
}
resource "google_storage_bucket_iam_member" "bucket-roles" {
for_each = {
for pair in local.iam_storage_pairs :
"${pair.name}-${pair.entity}-${pair.role}" => pair
}
bucket = each.value.entity
role = each.value.role
member = local.resource_iam_emails[each.value.name]
}
# TODO(ludoo): link from README
# ref: https://cloud.google.com/vpc/docs/shared-vpc

View File

@ -1,75 +0,0 @@
/**
* 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 "service_account" {
description = "Service account resource (for single use)."
value = local.resource
}
output "service_accounts" {
description = "Service account resources."
value = google_service_account.service_accounts
}
output "email" {
description = "Service account email (for single use)."
value = try(local.resource.email, null)
}
output "iam_email" {
description = "IAM-format service account email (for single use)."
value = try("serviceAccount:${local.resource.email}", null)
}
output "key" {
description = "Service account key (for single use)."
value = try(local.keys[var.names[0]], null)
}
output "emails" {
description = "Service account emails."
value = {
for name, resource in google_service_account.service_accounts :
name => resource.email
}
}
output "iam_emails" {
description = "IAM-format service account emails."
value = local.resource_iam_emails
}
output "emails_list" {
description = "Service account emails."
value = [
for name, resource in google_service_account.service_accounts :
resource.email
]
}
output "iam_emails_list" {
description = "IAM-format service account emails."
value = [
for name, resource in google_service_account.service_accounts :
"serviceAccount:${resource.email}"
]
}
output "keys" {
description = "Map of service account keys."
sensitive = true
value = local.keys
}

View File

@ -16,8 +16,7 @@ In this module **no lifecycle blocks are set on resources to prevent destroy**,
module "kms" {
source = "../modules/kms"
project_id = "my-project"
iam_roles = ["roles/owner"]
iam_members = {
iam = {
"roles/owner" = ["user:user1@example.com"]
}
keyring = { location = "europe-west1", name = "test" }
@ -32,10 +31,7 @@ module "kms" {
module "kms" {
source = "../modules/kms"
project_id = "my-project"
key_iam_roles = {
key-a = ["roles/owner"]
}
key_iam_members = {
key_iam = {
key-a = {
"roles/owner" = ["user:user1@example.com"]
}
@ -76,10 +72,8 @@ module "kms" {
|---|---|:---: |:---:|:---:|
| keyring | Keyring attributes. | <code title="object&#40;&#123;&#10;location &#61; string&#10;name &#61; string&#10;&#125;&#41;">object({...})</code> | ✓ | |
| project_id | Project id where the keyring will be created. | <code title="">string</code> | ✓ | |
| *iam_members* | Keyring IAM members. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | Keyring IAM roles. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *key_iam_members* | IAM members keyed by key name and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *key_iam_roles* | IAM roles keyed by key name. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam* | Keyring IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *key_iam* | Key IAM bindings for topic in {KEY => {ROLE => [MEMBERS]}} format. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *key_purpose* | Per-key purpose, if not set defaults will be used. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="map&#40;object&#40;&#123;&#10;purpose &#61; string&#10;version_template &#61; object&#40;&#123;&#10;algorithm &#61; string&#10;protection_level &#61; string&#10;&#125;&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *key_purpose_defaults* | Defaults used for key purpose when not defined at the key level. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="object&#40;&#123;&#10;purpose &#61; string&#10;version_template &#61; object&#40;&#123;&#10;algorithm &#61; string&#10;protection_level &#61; string&#10;&#125;&#41;&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;purpose &#61; null&#10;version_template &#61; null&#10;&#125;">...</code> |
| *keyring_create* | Set to false to manage keys and IAM bindings in an existing keyring. | <code title="">bool</code> | | <code title="">true</code> |

View File

@ -15,14 +15,15 @@
*/
locals {
key_iam_pairs = flatten([
for name, roles in var.key_iam_roles :
[for role in roles : { name = name, role = role }]
key_iam_members = flatten([
for key, roles in var.key_iam : [
for role, members in roles : {
key = key
role = role
members = members
}
]
])
key_iam_keypairs = {
for pair in local.key_iam_pairs :
"${pair.name}-${pair.role}" => pair
}
key_purpose = {
for key, attrs in var.keys : key => try(
var.key_purpose[key], var.key_purpose_defaults
@ -47,16 +48,13 @@ resource "google_kms_key_ring" "default" {
project = var.project_id
name = var.keyring.name
location = var.keyring.location
# lifecycle {
# prevent_destroy = true
# }
}
resource "google_kms_key_ring_iam_binding" "default" {
for_each = toset(var.iam_roles)
for_each = var.iam
key_ring_id = local.keyring.self_link
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
}
resource "google_kms_crypto_key" "default" {
@ -73,16 +71,14 @@ resource "google_kms_crypto_key" "default" {
protection_level = local.key_purpose[each.key].version_template.protection_level
}
}
# lifecycle {
# prevent_destroy = true
# }
}
resource "google_kms_crypto_key_iam_binding" "default" {
for_each = local.key_iam_keypairs
for_each = {
for binding in local.key_iam_members :
"${binding.key}.${binding.role}" => binding
}
role = each.value.role
crypto_key_id = google_kms_crypto_key.default[each.value.name].self_link
members = lookup(
lookup(var.key_iam_members, each.value.name, {}), each.value.role, []
)
crypto_key_id = google_kms_crypto_key.default[each.value.key].self_link
members = each.value.members
}

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -14,30 +14,18 @@
* limitations under the License.
*/
variable "iam_members" {
description = "Keyring IAM members."
variable "iam" {
description = "Keyring IAM bindings for topic in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "Keyring IAM roles."
type = list(string)
default = []
}
variable "key_iam_members" {
description = "IAM members keyed by key name and role."
variable "key_iam" {
description = "Key IAM bindings for topic in {KEY => {ROLE => [MEMBERS]}} format."
type = map(map(list(string)))
default = {}
}
variable "key_iam_roles" {
description = "IAM roles keyed by key name."
type = map(list(string))
default = {}
}
variable "key_purpose" {
description = "Per-key purpose, if not set defaults will be used. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required."
type = map(object({

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.

View File

@ -21,7 +21,7 @@ module "peering" {
}
```
If you need to create more than one peering for the same VPC Network `(A -> B, A -> C)` you have to use output from the first module as a dependency for the second one to keep order of peering creation (It is not currently possible to create more than one peering connection for a VPC Network at the same time).
If you need to create more than one peering for the same VPC Network `(A -> B, A -> C)` you use a `depends_on` for second one to keep order of peering creation (It is not currently possible to create more than one peering connection for a VPC Network at the same time).
```hcl
module "peering-a-b" {
@ -39,7 +39,7 @@ module "peering-a-c" {
local_network = "<A NETWORK SELF LINK>"
peer_network = "<C NETWORK SELF LINK>"
module_depends_on = [module.peering-a-b.complete]
depends_on = [ module.peering-a-b ]
}
```
@ -52,7 +52,6 @@ module "peering-a-c" {
| peer_network | Resource link of the peer network. | <code title="">string</code> | ✓ | |
| *export_local_custom_routes* | Export custom routes to peer network from local network. | <code title="">bool</code> | | <code title="">false</code> |
| *export_peer_custom_routes* | Export custom routes to local network from peer network. | <code title="">bool</code> | | <code title="">false</code> |
| *module_depends_on* | List of modules or resources this module depends on. | <code title="">list</code> | | <code title="">[]</code> |
| *peer_create_peering* | Create the peering on the remote side. If false, only the peering from this network to the remote network is created. | <code title="">bool</code> | | <code title="">true</code> |
| *prefix* | Name prefix for the network peerings. | <code title="">string</code> | | <code title="">network-peering</code> |
@ -60,7 +59,6 @@ module "peering-a-c" {
| name | description | sensitive |
|---|---|:---:|
| complete | Output to be used as a module dependency. | |
| local_network_peering | Network peering resource. | |
| peer_network_peering | Peer network peering resource. | |
<!-- END TFDOC -->
<!-- END TFDOC -->

View File

@ -25,8 +25,6 @@ resource "google_compute_network_peering" "local_network_peering" {
peer_network = var.peer_network
export_custom_routes = var.export_local_custom_routes
import_custom_routes = var.export_peer_custom_routes
depends_on = [null_resource.module_depends_on]
}
resource "google_compute_network_peering" "peer_network_peering" {
@ -37,15 +35,5 @@ resource "google_compute_network_peering" "peer_network_peering" {
export_custom_routes = var.export_peer_custom_routes
import_custom_routes = var.export_local_custom_routes
depends_on = [null_resource.module_depends_on, google_compute_network_peering.local_network_peering]
}
resource "null_resource" "module_depends_on" {
triggers = {
value = length(var.module_depends_on)
}
}
resource "null_resource" "complete" {
depends_on = [google_compute_network_peering.local_network_peering, google_compute_network_peering.peer_network_peering]
depends_on = [google_compute_network_peering.local_network_peering]
}

View File

@ -23,8 +23,3 @@ output "peer_network_peering" {
description = "Peer network peering resource."
value = google_compute_network_peering.peer_network_peering
}
output "complete" {
description = "Output to be used as a module dependency."
value = null_resource.complete.id
}

View File

@ -42,12 +42,6 @@ variable "export_local_custom_routes" {
default = false
}
variable "module_depends_on" {
description = "List of modules or resources this module depends on."
type = list
default = []
}
variable "peer_create_peering" {
description = "Create the peering on the remote side. If false, only the peering from this network to the remote network is created."
type = bool

View File

@ -86,13 +86,7 @@ module "vpc-host" {
local.service_project_1.project_id,
local.service_project_2.project_id
]
iam_roles = {
"europe-west1/subnet-1" = [
"roles/compute.networkUser",
"roles/compute.securityAdmin"
]
}
iam_members = {
iam = {
"europe-west1/subnet-1" = {
"roles/compute.networkUser" = [
local.service_project_1.cloudsvc_sa,
@ -116,14 +110,13 @@ module "vpc-host" {
| *auto_create_subnetworks* | Set to true to create an auto mode subnet, defaults to custom mode. | <code title="">bool</code> | | <code title="">false</code> |
| *delete_default_routes_on_create* | Set to true to delete the default routes at creation time. | <code title="">bool</code> | | <code title="">false</code> |
| *description* | An optional description of this resource (triggers recreation on change). | <code title="">string</code> | | <code title="">Terraform-managed.</code> |
| *iam_members* | List of IAM members keyed by subnet 'region/name' and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *iam_roles* | List of IAM roles keyed by subnet 'region/name'. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam* | Subnet IAM bindings in {REGION/NAME => {ROLE => [MEMBERS]} format. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *log_config_defaults* | Default configuration for flow logs when enabled. | <code title="object&#40;&#123;&#10;aggregation_interval &#61; string&#10;flow_sampling &#61; number&#10;metadata &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;aggregation_interval &#61; &#34;INTERVAL_5_SEC&#34;&#10;flow_sampling &#61; 0.5&#10;metadata &#61; &#34;INCLUDE_ALL_METADATA&#34;&#10;&#125;">...</code> |
| *log_configs* | Map keyed by subnet 'region/name' of optional configurations for flow logs when enabled. | <code title="map&#40;map&#40;string&#41;&#41;">map(map(string))</code> | | <code title="">{}</code> |
| *peering_config* | VPC peering configuration. | <code title="object&#40;&#123;&#10;peer_vpc_self_link &#61; string&#10;export_routes &#61; bool&#10;import_routes &#61; bool&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *peering_create_remote_end* | Skip creation of peering on the remote end when using peering_config | <code title="">bool</code> | | <code title="">true</code> |
| *routes* | Network routes, keyed by name. | <code title="map&#40;object&#40;&#123;&#10;dest_range &#61; string&#10;priority &#61; number&#10;tags &#61; list&#40;string&#41;&#10;next_hop_type &#61; string &#35; gateway, instance, ip, vpn_tunnel, ilb&#10;next_hop &#61; string&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *routing_mode* | The network routing mode (default 'GLOBAL') | <code title="">string</code> | | <code title="">GLOBAL</code> |
| *routing_mode* | The network routing mode (default 'GLOBAL') | <code title="">string</code> | | <code title="GLOBAL&#10;validation &#123;&#10;condition &#61; var.routing_mode &#61;&#61; &#34;GLOBAL&#34; &#124;&#124; var.routing_mode &#61;&#61; &#34;REGIONAL&#34;&#10;error_message &#61; &#34;Routing type must be GLOBAL or REGIONAL.&#34;&#10;&#125;">...</code> |
| *shared_vpc_host* | Enable shared VPC for this project. | <code title="">bool</code> | | <code title="">false</code> |
| *shared_vpc_service_projects* | Shared VPC service projects to register with this host | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *subnet_descriptions* | Optional map of subnet descriptions, keyed by subnet 'region/name'. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |

View File

@ -15,15 +15,17 @@
*/
locals {
iam_members = var.iam_members == null ? {} : var.iam_members
iam_pairs = var.iam_roles == null ? [] : flatten([
for subnet, roles in var.iam_roles :
[for role in roles : { subnet = subnet, role = role }]
iam_members = var.iam == null ? {} : var.iam
subnet_iam_members = flatten([
for subnet, roles in local.iam_members : [
for role, members in roles : {
subnet = subnet
role = role
members = members
}
]
])
iam_keypairs = {
for pair in local.iam_pairs :
"${pair.subnet}-${pair.role}" => pair
}
log_configs = var.log_configs == null ? {} : var.log_configs
peer_network = (
var.peering_config == null
@ -152,14 +154,15 @@ resource "google_compute_subnetwork" "subnetwork" {
}
resource "google_compute_subnetwork_iam_binding" "binding" {
for_each = local.iam_keypairs
for_each = {
for binding in local.subnet_iam_members :
"${binding.subnet}.${binding.role}" => binding
}
project = var.project_id
subnetwork = google_compute_subnetwork.subnetwork[each.value.subnet].name
region = google_compute_subnetwork.subnetwork[each.value.subnet].region
role = each.value.role
members = lookup(
lookup(local.iam_members, each.value.subnet, {}), each.value.role, []
)
members = each.value.members
}
resource "google_compute_route" "gateway" {

View File

@ -32,14 +32,8 @@ variable "description" {
default = "Terraform-managed."
}
variable "iam_roles" {
description = "List of IAM roles keyed by subnet 'region/name'."
type = map(list(string))
default = {}
}
variable "iam_members" {
description = "List of IAM members keyed by subnet 'region/name' and role."
variable "iam" {
description = "Subnet IAM bindings in {REGION/NAME => {ROLE => [MEMBERS]} format."
type = map(map(list(string)))
default = {}
}
@ -106,6 +100,11 @@ variable "routing_mode" {
description = "The network routing mode (default 'GLOBAL')"
type = string
default = "GLOBAL"
validation {
condition = var.routing_mode == "GLOBAL" || var.routing_mode == "REGIONAL"
error_message = "Routing type must be GLOBAL or REGIONAL."
}
}
variable "shared_vpc_host" {

View File

@ -15,5 +15,5 @@
*/
terraform {
required_version = ">= 0.12.6"
required_version = ">= 0.13.0"
}

View File

@ -13,8 +13,7 @@ This module allows managing several organization properties:
module "org" {
source = "./modules/organization"
org_id = 1234567890
iam_roles = ["roles/projectCreator"]
iam_members = { "roles/projectCreator" = ["group:cloud-admins@example.org"] }
iam = { "roles/projectCreator" = ["group:cloud-admins@example.org"] }
policy_boolean = {
"constraints/compute.disableGuestAttributesAccess" = true
"constraints/compute.skipDefaultNetworkCreation" = true
@ -37,10 +36,9 @@ module "org" {
|---|---|:---: |:---:|:---:|
| 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_bindings* | Map of roles lists used to set non authoritative bindings, keyed by members. | <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> |
| *iam_additive* | Non authoritative IAM bindings, in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(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> |

View File

@ -16,7 +16,7 @@
locals {
iam_additive_pairs = flatten([
for member, roles in var.iam_additive_bindings : [
for member, roles in var.iam_additive : [
for role in roles :
{ role = role, member = member }
]
@ -37,14 +37,14 @@ resource "google_organization_iam_custom_role" "roles" {
}
resource "google_organization_iam_binding" "authoritative" {
for_each = toset(var.iam_roles)
for_each = var.iam
org_id = var.org_id
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
}
resource "google_organization_iam_member" "additive" {
for_each = length(var.iam_additive_bindings) > 0 ? local.iam_additive : {}
for_each = length(var.iam_additive) > 0 ? local.iam_additive : {}
org_id = var.org_id
role = each.value.role
member = each.value.member

View File

@ -20,20 +20,14 @@ variable "custom_roles" {
default = {}
}
variable "iam_members" {
description = "Map of member lists used to set authoritative bindings, keyed by role."
variable "iam" {
description = "IAM bindings, in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "List of roles used to set authoritative bindings."
type = list(string)
default = []
}
variable "iam_additive_bindings" {
description = "Map of roles lists used to set non authoritative bindings, keyed by members."
variable "iam_additive" {
description = "Non authoritative IAM bindings, in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}

View File

@ -15,8 +15,7 @@ module "project" {
"container.googleapis.com",
"stackdriver.googleapis.com"
]
iam_roles = ["roles/container.hostServiceAgentUser"]
iam_members = {
iam = {
"roles/container.hostServiceAgentUser" = [
"serviceAccount:${var.gke_service_account}"
]
@ -32,7 +31,7 @@ module "project" {
name = "project-example"
project_create = false
iam_additive_bindings = {
iam_additive = {
"group:usergroup_watermlon_experimentation@lemonadeinc.io" = [
"roles/viewer",
"roles/storage.objectAdmin"
@ -88,15 +87,14 @@ module "project" {
| *auto_create_network* | Whether to create the default network for the project | <code title="">bool</code> | | <code title="">false</code> |
| *billing_account* | Billing account id. | <code title="">string</code> | | <code title="">null</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_bindings* | Map of roles lists used to set non authoritative bindings, keyed by members | <code title="map&#40;list&#40;string&#41;&#41;">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> |
| *iam* | IAM bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(string))</code> | | <code title="">{}</code> |
| *iam_additive* | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *labels* | Resource labels. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *lien_reason* | If non-empty, creates a project lien with this description. | <code title="">string</code> | | <code title=""></code> |
| *oslogin* | Enable OS Login. | <code title="">bool</code> | | <code title="">false</code> |
| *oslogin_admins* | List of IAM-style identities that will be granted roles necessary for OS Login administrators. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *oslogin_users* | List of IAM-style identities that will be granted roles necessary for OS Login users. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *parent* | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code title="">string</code> | | <code title="">null</code> |
| *parent* | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code title="">string</code> | | <code title="null&#10;validation &#123;&#10;condition &#61; var.parent &#61;&#61; null &#124;&#124; can&#40;regex&#40;&#34;&#40;organizations&#124;folders&#41;&#47;&#91;0-9&#93;&#43;&#34;, var.parent&#41;&#41;&#10;error_message &#61; &#34;Parent must be of the form folders&#47;folder_id or organizations&#47;organization_id.&#34;&#10;&#125;">...</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> |
| *prefix* | Prefix used to generate project id and name. | <code title="">string</code> | | <code title="">null</code> |

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -16,7 +16,7 @@
locals {
iam_additive_pairs = flatten([
for member, roles in var.iam_additive_bindings : [
for member, roles in var.iam_additive : [
for role in roles :
{ role = role, member = member }
]
@ -91,10 +91,10 @@ resource "google_project_service" "project_services" {
# - additive (non-authoritative) roles might fail due to dynamic values
resource "google_project_iam_binding" "authoritative" {
for_each = toset(var.iam_roles)
for_each = var.iam
project = local.project.project_id
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
depends_on = [
google_project_service.project_services,
google_project_iam_custom_role.roles
@ -102,7 +102,7 @@ resource "google_project_iam_binding" "authoritative" {
}
resource "google_project_iam_member" "additive" {
for_each = length(var.iam_additive_bindings) > 0 ? local.iam_additive : {}
for_each = length(var.iam_additive) > 0 ? local.iam_additive : {}
project = local.project.project_id
role = each.value.role
member = each.value.member

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.

View File

@ -32,21 +32,14 @@ variable "custom_roles" {
default = {}
}
variable "iam_members" {
description = "Map of member lists used to set authoritative bindings, keyed by role."
type = map(list(string))
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format."
type = map(set(string))
default = {}
}
variable "iam_roles" {
description = "List of roles used to set authoritative bindings."
type = list(string)
default = []
}
variable "iam_additive_bindings" {
description = "Map of roles lists used to set non authoritative bindings, keyed by members"
variable "iam_additive" {
description = "IAM additive bindings in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
@ -90,6 +83,10 @@ variable "parent" {
description = "Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format."
type = string
default = null
validation {
condition = var.parent == null || can(regex("(organizations|folders)/[0-9]+", var.parent))
error_message = "Parent must be of the form folders/folder_id or organizations/organization_id."
}
}
variable "policy_boolean" {

View File

@ -15,5 +15,5 @@
*/
terraform {
required_version = ">= 0.12.6"
required_version = ">= 0.13.0"
}

View File

@ -12,11 +12,7 @@ module "pubsub" {
source = "./modules/pubsub"
project_id = "my-project"
name = "my-topic"
iam_roles = [
"roles/pubsub.viewer",
"roles/pubsub.subscriber"
]
iam_members = {
iam = {
"roles/pubsub.viewer" = ["group:foo@example.com"]
"roles/pubsub.subscriber" = ["user:user1@example.com"]
}
@ -30,7 +26,7 @@ Subscriptions are defined with the `subscriptions` variable, allowing optional c
```hcl
module "pubsub" {
source = "./modules/pubsub"
project_id = "my-project
project_id = "my-project"
name = "my-topic"
subscriptions = {
test-pull = null
@ -54,7 +50,7 @@ Push subscriptions need extra configuration in the `push_configs` variable.
```hcl
module "pubsub" {
source = "./modules/pubsub"
project_id = "my-project
project_id = "my-project"
name = "my-topic"
subscriptions = {
test-push = null
@ -74,16 +70,13 @@ module "pubsub" {
```hcl
module "pubsub" {
source = "./modules/pubsub"
project_id = "my-project
project_id = "my-project"
name = "my-topic"
subscriptions = {
test-1 = null
test-1 = null
}
subscription_iam_roles = {
test-1 = ["roles/pubsub.subscriber"]
}
subscription_iam_members = {
subscription_iam = {
test-1 = {
"roles/pubsub.subscriber" = ["user:user1@ludomagno.net"]
}
@ -100,14 +93,12 @@ module "pubsub" {
| project_id | Project used for resources. | <code title="">string</code> | ✓ | |
| *dead_letter_configs* | Per-subscription dead letter policy configuration. | <code title="map&#40;object&#40;&#123;&#10;topic &#61; string&#10;max_delivery_attemps &#61; number&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *defaults* | Subscription defaults for options. | <code title="object&#40;&#123;&#10;ack_deadline_seconds &#61; number&#10;message_retention_duration &#61; number&#10;retain_acked_messages &#61; bool&#10;expiration_policy_ttl &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;ack_deadline_seconds &#61; null&#10;message_retention_duration &#61; null&#10;retain_acked_messages &#61; null&#10;expiration_policy_ttl &#61; null&#10;&#125;">...</code> |
| *iam_members* | IAM members for each topic role. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | IAM roles for topic. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *iam* | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *kms_key* | KMS customer managed encryption key. | <code title="">string</code> | | <code title="">null</code> |
| *labels* | Labels. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *push_configs* | Push subscription configurations. | <code title="map&#40;object&#40;&#123;&#10;attributes &#61; map&#40;string&#41;&#10;endpoint &#61; string&#10;oidc_token &#61; object&#40;&#123;&#10;audience &#61; string&#10;service_account_email &#61; string&#10;&#125;&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *regions* | List of regions used to set persistence policy. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *subscription_iam_members* | IAM members for each subscription and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *subscription_iam_roles* | IAM roles for each subscription. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *subscription_iam* | IAM bindings for subscriptions in {SUBSCRIPTION => {ROLE => [MEMBERS]}} format. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *subscriptions* | Topic subscriptions. Also define push configs for push subscriptions. If options is set to null subscription defaults will be used. Labels default to topic labels if set to null. | <code title="map&#40;object&#40;&#123;&#10;labels &#61; map&#40;string&#41;&#10;options &#61; object&#40;&#123;&#10;ack_deadline_seconds &#61; number&#10;message_retention_duration &#61; number&#10;retain_acked_messages &#61; bool&#10;expiration_policy_ttl &#61; string&#10;&#125;&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
## Outputs

View File

@ -15,17 +15,15 @@
*/
locals {
iam_pairs = var.subscription_iam_roles == null ? [] : flatten([
for name, roles in var.subscription_iam_roles :
[for role in roles : { name = name, role = role }]
sub_iam_members = flatten([
for sub, roles in var.subscription_iam : [
for role, members in roles : {
sub = sub
role = role
members = members
}
]
])
iam_keypairs = {
for pair in local.iam_pairs :
"${pair.name}-${pair.role}" => pair
}
iam_members = (
var.subscription_iam_members == null ? {} : var.subscription_iam_members
)
oidc_config = {
for k, v in var.push_configs : k => v.oidc_token
}
@ -52,11 +50,11 @@ resource "google_pubsub_topic" "default" {
}
resource "google_pubsub_topic_iam_binding" "default" {
for_each = toset(var.iam_roles)
for_each = var.iam
project = var.project_id
topic = google_pubsub_topic.default.name
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
}
resource "google_pubsub_subscription" "default" {
@ -103,11 +101,12 @@ resource "google_pubsub_subscription" "default" {
}
resource "google_pubsub_subscription_iam_binding" "default" {
for_each = local.iam_keypairs
for_each = {
for binding in local.sub_iam_members :
"${binding.sub}.${binding.role}" => binding
}
project = var.project_id
subscription = google_pubsub_subscription.default[each.value.name].name
subscription = google_pubsub_subscription.default[each.value.sub].name
role = each.value.role
members = lookup(
lookup(local.iam_members, each.value.name, {}), each.value.role, []
)
members = each.value.members
}

View File

@ -39,18 +39,12 @@ variable "defaults" {
}
}
variable "iam_members" {
description = "IAM members for each topic role."
variable "iam" {
description = "IAM bindings for topic in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "IAM roles for topic."
type = list(string)
default = []
}
variable "kms_key" {
description = "KMS customer managed encryption key."
type = string
@ -107,14 +101,8 @@ variable "subscriptions" {
default = {}
}
variable "subscription_iam_members" {
description = "IAM members for each subscription and role."
variable "subscription_iam" {
description = "IAM bindings for subscriptions in {SUBSCRIPTION => {ROLE => [MEMBERS]}} format."
type = map(map(list(string)))
default = {}
}
variable "subscription_iam_roles" {
description = "IAM roles for each subscription."
type = map(list(string))
default = {}
}

View File

@ -25,7 +25,7 @@ module "secret-manager" {
### Secret IAM bindings
IAM bindings can be set per secret in the same way as for most other modules supporting IAM, via `iam_roles` and `iam_members` variables.
IAM bindings can be set per secret in the same way as for most other modules supporting IAM, using the `iam` variable.
```hcl
module "secret-manager" {
@ -35,11 +35,7 @@ module "secret-manager" {
test-auto = null
test-manual = ["europe-west1", "europe-west4"]
}
iam_roles = {
test-auto = ["roles/secretmanager.secretAccessor"]
test-manual = ["roles/secretmanager.secretAccessor"]
}
iam_members = {
iam = {
test-auto = {
"roles/secretmanager.secretAccessor" = ["group:auto-readers@example.com"]
}
@ -80,8 +76,7 @@ module "secret-manager" {
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| project_id | Project id where the keyring will be created. | <code title="">string</code> | ✓ | |
| *iam_members* | IAM members keyed by secret name and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *iam_roles* | IAM roles keyed by secret name. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam* | IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *labels* | Optional labels for each secret. | <code title="map&#40;map&#40;string&#41;&#41;">map(map(string))</code> | | <code title="">{}</code> |
| *secrets* | Map of secrets to manage and their locations. If locations is null, automatic management will be set. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *versions* | Optional versions to manage for each secret. Version names are only used internally to track individual versions. | <code title="map&#40;map&#40;object&#40;&#123;&#10;enabled &#61; bool&#10;data &#61; string&#10;&#125;&#41;&#41;&#41;">map(map(object({...})))</code> | | <code title="">{}</code> |

View File

@ -16,13 +16,15 @@
locals {
# distinct is needed to make the expanding function argument work
iam_pairs = flatten([
for name, roles in var.iam_roles :
[for role in roles : { name = name, role = role }]
iam = flatten([
for secret, roles in var.iam : [
for role, members in roles : {
secret = secret
role = role
members = members
}
]
])
iam_keypairs = {
for pair in local.iam_pairs : "${pair.name}-${pair.role}" => pair
}
version_pairs = flatten([
for secret, versions in var.versions : [
for name, attrs in versions : merge(attrs, { name = name, secret = secret })
@ -73,11 +75,11 @@ resource "google_secret_manager_secret_version" "default" {
}
resource "google_secret_manager_secret_iam_binding" "default" {
provider = google-beta
for_each = local.iam_keypairs
provider = google-beta
for_each = {
for binding in local.iam : "${binding.secret}.${binding.role}" => binding
}
role = each.value.role
secret_id = google_secret_manager_secret.default[each.value.name].id
members = lookup(
lookup(var.iam_members, each.value.name, {}), each.value.role, []
)
secret_id = google_secret_manager_secret.default[each.value.secret].id
members = each.value.members
}

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.

View File

@ -1,5 +1,5 @@
/**
* Copyright 2018 Google LLC
* 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.
@ -14,18 +14,12 @@
* limitations under the License.
*/
variable "iam_members" {
description = "IAM members keyed by secret name and role."
variable "iam" {
description = "IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format."
type = map(map(list(string)))
default = {}
}
variable "iam_roles" {
description = "IAM roles keyed by secret name."
type = map(list(string))
default = {}
}
variable "labels" {
description = "Optional labels for each secret."
type = map(map(string))

View File

@ -15,14 +15,11 @@ module "service-directory" {
project_id = "my-project"
location = "europe-west1"
name = "sd-1"
iam_members = {
iam = {
"roles/servicedirectory.editor" = [
"serviceAccount:namespace-editor@example.com"
]
}
iam_roles = [
"roles/servicedirectory.editor"
]
}
```
@ -40,16 +37,13 @@ module "service-directory" {
metadata = null
}
}
service_iam_members = {
service_iam = {
one = {
"roles/servicedirectory.editor" = [
"serviceAccount:service-editor.example.com"
]
}
}
service_iam_roles = {
one = ["roles/servicedirectory.editor"]
}
endpoint_config = {
"one/first" = { address = "127.0.0.1", port = 80, metadata = {} }
"one/second" = { address = "127.0.0.2", port = 80, metadata = {} }
@ -67,14 +61,11 @@ module "service-directory" {
project_id = "my-project"
location = "europe-west1"
name = "apps"
iam_members = {
iam = {
"roles/servicedirectory.editor" = [
"serviceAccount:namespace-editor@example.com"
]
}
iam_roles = [
"roles/servicedirectory.editor"
]
services = {
app1 = { endpoints = ["one"], metadata = null }
}
@ -104,11 +95,9 @@ module "dns-sd" {
| name | Namespace name. | <code title="">string</code> | ✓ | |
| project_id | Project used for resources. | <code title="">string</code> | ✓ | |
| *endpoint_config* | Map of endpoint attributes, keys are in service/endpoint format. | <code title="map&#40;object&#40;&#123;&#10;address &#61; string&#10;port &#61; number&#10;metadata &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
| *iam_members* | IAM members for each namespace role. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | IAM roles for the namespace. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *iam* | IAM bindings for namespace, in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *labels* | Labels. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *service_iam_members* | IAM members for each service and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *service_iam_roles* | IAM roles for each service. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *service_iam* | IAM bindings for services, in {SERVICE => {ROLE => [MEMBERS]}} format. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *services* | Service configuration, using service names as keys. | <code title="map&#40;object&#40;&#123;&#10;endpoints &#61; list&#40;string&#41;&#10;metadata &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">map(object({...}))</code> | | <code title="">{}</code> |
## Outputs

View File

@ -23,17 +23,14 @@ locals {
endpoints = {
for ep in local.endpoint_list : "${ep.service}/${ep.endpoint}" => ep
}
iam_pairs = var.service_iam_roles == null ? [] : flatten([
for name, roles in var.service_iam_roles :
[for role in roles : { name = name, role = role }]
iam_pairs = var.service_iam == null ? [] : flatten([
for name, bindings in var.service_iam :
[for role in keys(bindings) : { name = name, role = role }]
])
iam_keypairs = {
for pair in local.iam_pairs :
"${pair.name}-${pair.role}" => pair
}
iam_members = (
var.service_iam_members == null ? {} : var.service_iam_members
)
}
resource "google_service_directory_namespace" "default" {
@ -46,10 +43,10 @@ resource "google_service_directory_namespace" "default" {
resource "google_service_directory_namespace_iam_binding" "default" {
provider = google-beta
for_each = toset(var.iam_roles)
for_each = var.iam
name = google_service_directory_namespace.default.name
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
}
resource "google_service_directory_service" "default" {
@ -66,7 +63,7 @@ resource "google_service_directory_service_iam_binding" "default" {
name = google_service_directory_service.default[each.value.name].name
role = each.value.role
members = lookup(
lookup(local.iam_members, each.value.name, {}), each.value.role, []
lookup(var.service_iam, each.value.name, {}), each.value.role, []
)
}

View File

@ -25,18 +25,12 @@ variable "endpoint_config" {
default = {}
}
variable "iam_members" {
description = "IAM members for each namespace role."
variable "iam" {
description = "IAM bindings for namespace, in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "IAM roles for the namespace."
type = list(string)
default = []
}
variable "labels" {
description = "Labels."
type = map(string)
@ -58,18 +52,12 @@ variable "project_id" {
type = string
}
variable "service_iam_members" {
description = "IAM members for each service and role."
variable "service_iam" {
description = "IAM bindings for services, in {SERVICE => {ROLE => [MEMBERS]}} format."
type = map(map(list(string)))
default = {}
}
variable "service_iam_roles" {
description = "IAM roles for each service."
type = map(list(string))
default = {}
}
variable "services" {
description = "Service configuration, using service names as keys."
type = map(object({

View File

@ -12,8 +12,7 @@ module "repo" {
source e = "./modules/source-repository"
project_id = "my-project"
name = "my-repo"
iam_roles = ["roles/source.reader"]
iam_members = {
iam = {
"roles/source.reader" = ["user:foo@example.com"]
}
}
@ -24,10 +23,9 @@ module "repo" {
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| name | Repository topic name. | <code title="">string</code> | ✓ | |
| name | Repository name. | <code title="">string</code> | ✓ | |
| project_id | Project used for resources. | <code title="">string</code> | ✓ | |
| *iam_members* | IAM members for each topic role. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *iam_roles* | IAM roles for topic. | <code title="list&#40;string&#41;">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> |
## Outputs

View File

@ -20,11 +20,11 @@ resource "google_sourcerepo_repository" "default" {
}
resource "google_sourcerepo_repository_iam_binding" "default" {
for_each = toset(var.iam_roles)
for_each = var.iam
project = var.project_id
repository = google_sourcerepo_repository.default.name
role = each.value
members = lookup(var.iam_members, each.value, [])
role = each.key
members = each.value
depends_on = [
google_sourcerepo_repository.default

View File

@ -19,19 +19,13 @@ variable "project_id" {
type = string
}
variable "iam_members" {
description = "IAM members for each topic role."
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
}
variable "iam_roles" {
description = "IAM roles for topic."
type = list(string)
default = []
}
variable "name" {
description = "Repository topic name."
description = "Repository name."
type = string
}

View File

@ -136,7 +136,7 @@ module "hub-to-spoke-2-peering" {
peer_network = module.vpc-spoke-2.self_link
export_local_custom_routes = true
export_peer_custom_routes = false
module_depends_on = [module.hub-to-spoke-1-peering.complete]
depends_on = [module.hub-to-spoke-1-peering]
}
################################################################################
@ -180,9 +180,9 @@ module "vm-spoke-2" {
}
module "service-account-gce" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = var.project_id
names = ["gce-test"]
name = "gce-test"
iam_project_roles = {
(var.project_id) = [
"roles/container.developer",
@ -232,9 +232,9 @@ module "cluster-1-nodepool-1" {
# project level, with no risk of conflicts with pre-existing roles
module "service-account-gke-node" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = var.project_id
names = ["gke-node"]
name = "gke-node"
iam_project_roles = {
(var.project_id) = [
"roles/logging.logWriter", "roles/monitoring.metricWriter",

View File

@ -37,9 +37,9 @@ module "project" {
}
module "service-accounts" {
source = "../../modules/iam-service-accounts"
source = "../../modules/iam-service-account"
project_id = module.project.project_id
names = ["${local.prefix}gce-vm"]
name = "${local.prefix}gce-vm"
iam_project_roles = {
(var.project_id) = [
"roles/logging.logWriter",

Some files were not shown because too many files have changed in this diff Show More