Update service account module to Terraform 0.13

This commit is contained in:
Julio Castillo 2020-10-20 22:36:03 +02:00
parent 1e5085a8b2
commit 13ed799a8b
8 changed files with 240 additions and 290 deletions

View File

@ -0,0 +1,54 @@
# 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-accounts"
project_id = "myproject"
name = "vm-default"
generate_key = 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 |
|---|---|:---: |:---:|:---:|
| 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_billing_roles* | Project roles granted to the service account, by billing account id. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(string))</code> | | <code title="">{}</code> |
| *iam_folder_roles* | Project roles granted to the service account, by folder id. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(string))</code> | | <code title="">{}</code> |
| *iam_members* | Map of members which are granted authoritative roles on the service account, keyed by role. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(string))</code> | | <code title="">{}</code> |
| *iam_organization_roles* | Project roles granted to the service account, by organization id. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(string))</code> | | <code title="">{}</code> |
| *iam_project_roles* | Project roles granted to the service account, by project id. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(string))</code> | | <code title="">{}</code> |
| *iam_roles* | Authoritative roles granted on the service account. | <code title="set&#40;string&#41;">set(string)</code> | | <code title="">[]</code> |
| *iam_storage_roles* | Storage roles granted to the service account, by bucket name. | <code title="map&#40;set&#40;string&#41;&#41;">map(set(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,125 @@
/**
* 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_roles
#for_each = toset(keys(var.iam_members))
service_account_id = google_service_account.service_account.name
role = each.key
members = lookup(var.iam_members, each.key, [])
}
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,63 @@
* 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."
type = map(list(string))
description = "Map of members which are granted authoritative roles on the service account, keyed by role."
type = map(set(string))
default = {}
}
variable "iam_roles" {
description = "List of authoritative roles granted on the service accounts."
type = list(string)
description = "Authoritative roles granted on the service account."
type = set(string)
default = []
}
variable "iam_billing_roles" {
description = "Project roles granted to all service accounts, by billing account id."
type = map(list(string))
description = "Project roles granted to the service account, by billing account id."
type = map(set(string))
default = {}
}
variable "iam_folder_roles" {
description = "Project roles granted to all service accounts, by folder id."
type = map(list(string))
description = "Project roles granted to the service account, by folder id."
type = map(set(string))
default = {}
}
variable "iam_organization_roles" {
description = "Project roles granted to all service accounts, by organization id."
type = map(list(string))
description = "Project roles granted to the service account, by organization id."
type = map(set(string))
default = {}
}
variable "iam_project_roles" {
description = "Project roles granted to all service accounts, by project id."
type = map(list(string))
description = "Project roles granted to the service account, by project id."
type = map(set(string))
default = {}
}
variable "iam_storage_roles" {
description = "Storage roles granted to all service accounts, by bucket name."
type = map(list(string))
description = "Storage roles granted to the service account, by bucket name."
type = map(set(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
}