diff --git a/modules/iam-service-account/README.md b/modules/iam-service-account/README.md
index eb5ab95b..68850685 100644
--- a/modules/iam-service-account/README.md
+++ b/modules/iam-service-account/README.md
@@ -43,21 +43,22 @@ module "myproject-default-service-accounts" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L84) | Name of the service account to create. | string
| ✓ | |
-| [project_id](variables.tf#L95) | Project id where service account will be created. | string
| ✓ | |
+| [name](variables.tf#L91) | Name of the service account to create. | string
| ✓ | |
+| [project_id](variables.tf#L102) | Project id where service account will be created. | string
| ✓ | |
| [description](variables.tf#L17) | Optional description. | string
| | null
|
| [display_name](variables.tf#L23) | Display name of the service account to create. | string
| | "Terraform-managed."
|
| [generate_key](variables.tf#L29) | Generate a key for service account. | bool
| | false
|
| [iam](variables.tf#L35) | IAM bindings on the service account in {ROLE => [MEMBERS]} format. | map(list(string))
| | {}
|
-| [iam_billing_roles](variables.tf#L42) | Billing account roles granted to this service account, by billing account id. Non-authoritative. | map(list(string))
| | {}
|
-| [iam_folder_roles](variables.tf#L49) | Folder roles granted to this service account, by folder id. Non-authoritative. | map(list(string))
| | {}
|
-| [iam_organization_roles](variables.tf#L56) | Organization roles granted to this service account, by organization id. Non-authoritative. | map(list(string))
| | {}
|
-| [iam_project_roles](variables.tf#L63) | Project roles granted to this service account, by project id. | map(list(string))
| | {}
|
-| [iam_sa_roles](variables.tf#L70) | Service account roles granted to this service account, by service account name. | map(list(string))
| | {}
|
-| [iam_storage_roles](variables.tf#L77) | Storage roles granted to this service account, by bucket name. | map(list(string))
| | {}
|
-| [prefix](variables.tf#L89) | Prefix applied to service account names. | string
| | null
|
-| [public_keys_directory](variables.tf#L100) | Path to public keys data files to upload to the service account (should have `.pem` extension). | string
| | ""
|
-| [service_account_create](variables.tf#L106) | Create service account. When set to false, uses a data source to reference an existing service account. | bool
| | true
|
+| [iam_additive](variables.tf#L42) | IAM additive bindings on the service account in {ROLE => [MEMBERS]} format. | map(list(string))
| | {}
|
+| [iam_billing_roles](variables.tf#L49) | Billing account roles granted to this service account, by billing account id. Non-authoritative. | map(list(string))
| | {}
|
+| [iam_folder_roles](variables.tf#L56) | Folder roles granted to this service account, by folder id. Non-authoritative. | map(list(string))
| | {}
|
+| [iam_organization_roles](variables.tf#L63) | Organization roles granted to this service account, by organization id. Non-authoritative. | map(list(string))
| | {}
|
+| [iam_project_roles](variables.tf#L70) | Project roles granted to this service account, by project id. | map(list(string))
| | {}
|
+| [iam_sa_roles](variables.tf#L77) | Service account roles granted to this service account, by service account name. | map(list(string))
| | {}
|
+| [iam_storage_roles](variables.tf#L84) | Storage roles granted to this service account, by bucket name. | map(list(string))
| | {}
|
+| [prefix](variables.tf#L96) | Prefix applied to service account names. | string
| | null
|
+| [public_keys_directory](variables.tf#L107) | Path to public keys data files to upload to the service account (should have `.pem` extension). | string
| | ""
|
+| [service_account_create](variables.tf#L113) | Create service account. When set to false, uses a data source to reference an existing service account. | bool
| | true
|
## Outputs
@@ -66,9 +67,9 @@ module "myproject-default-service-accounts" {
| [email](outputs.tf#L17) | Service account email. | |
| [iam_email](outputs.tf#L25) | IAM-format service account email. | |
| [id](outputs.tf#L33) | Service account id. | |
-| [key](outputs.tf#L41) | Service account key. | ✓ |
-| [name](outputs.tf#L47) | Service account name. | |
-| [service_account](outputs.tf#L52) | Service account resource. | |
-| [service_account_credentials](outputs.tf#L57) | Service account json credential templates for uploaded public keys data. | |
+| [key](outputs.tf#L42) | Service account key. | ✓ |
+| [name](outputs.tf#L48) | Service account name. | |
+| [service_account](outputs.tf#L57) | Service account resource. | |
+| [service_account_credentials](outputs.tf#L62) | Service account json credential templates for uploaded public keys data. | |
diff --git a/modules/iam-service-account/iam.tf b/modules/iam-service-account/iam.tf
index 1aa260a7..02c879d9 100644
--- a/modules/iam-service-account/iam.tf
+++ b/modules/iam-service-account/iam.tf
@@ -17,6 +17,15 @@
# tfdoc:file:description IAM bindings.
locals {
+ _iam_additive_pairs = flatten([
+ for role, members in var.iam_additive : [
+ for member in members : { role = role, member = member }
+ ]
+ ])
+ iam_additive = {
+ for pair in local._iam_additive_pairs :
+ "${pair.role}-${pair.member}" => pair
+ }
iam_billing_pairs = flatten([
for entity, roles in var.iam_billing_roles : [
for role in roles : [
@@ -61,6 +70,13 @@ locals {
])
}
+resource "google_service_account_iam_member" "roles" {
+ for_each = local.iam_additive
+ service_account_id = local.service_account.name
+ role = each.value.role
+ member = each.value.member
+}
+
resource "google_service_account_iam_binding" "roles" {
for_each = var.iam
service_account_id = local.service_account.name
diff --git a/modules/iam-service-account/main.tf b/modules/iam-service-account/main.tf
index 37f8205b..d9f3b9c4 100644
--- a/modules/iam-service-account/main.tf
+++ b/modules/iam-service-account/main.tf
@@ -21,7 +21,7 @@ locals {
? google_service_account_key.key["1"]
: map("", null)
, {})
- prefix = var.prefix != null ? "${var.prefix}-" : ""
+ prefix = var.prefix == null || var.prefix == "" ? "" : "${var.prefix}-"
resource_email_static = "${local.prefix}${var.name}@${var.project_id}.iam.gserviceaccount.com"
resource_iam_email = (
local.service_account != null
@@ -29,6 +29,7 @@ locals {
: local.resource_iam_email_static
)
resource_iam_email_static = "serviceAccount:${local.resource_email_static}"
+ service_account_id_static = "projects/${var.project_id}/serviceAccounts/${local.resource_email_static}"
service_account = (
var.service_account_create
? try(google_service_account.service_account.0, null)
diff --git a/modules/iam-service-account/outputs.tf b/modules/iam-service-account/outputs.tf
index 42196534..e6c28dfd 100644
--- a/modules/iam-service-account/outputs.tf
+++ b/modules/iam-service-account/outputs.tf
@@ -32,9 +32,10 @@ output "iam_email" {
output "id" {
description = "Service account id."
- value = local.service_account.id
+ value = local.service_account_id_static
depends_on = [
- local.service_account
+ data.google_service_account.service_account,
+ google_service_account.service_account
]
}
@@ -46,7 +47,11 @@ output "key" {
output "name" {
description = "Service account name."
- value = local.service_account.name
+ value = local.service_account_id_static
+ depends_on = [
+ data.google_service_account.service_account,
+ google_service_account.service_account
+ ]
}
output "service_account" {
diff --git a/modules/iam-service-account/variables.tf b/modules/iam-service-account/variables.tf
index ee156134..363814e1 100644
--- a/modules/iam-service-account/variables.tf
+++ b/modules/iam-service-account/variables.tf
@@ -39,6 +39,13 @@ variable "iam" {
nullable = false
}
+variable "iam_additive" {
+ description = "IAM additive bindings on the service account in {ROLE => [MEMBERS]} format."
+ type = map(list(string))
+ default = {}
+ nullable = false
+}
+
variable "iam_billing_roles" {
description = "Billing account roles granted to this service account, by billing account id. Non-authoritative."
type = map(list(string))