add support for service account IAM variables to pf (#2130)
This commit is contained in:
committed by
GitHub
parent
81cf47c785
commit
39139e2fa1
@@ -43,18 +43,21 @@ Some examples on where to use each of the three sets are [provided below](#examp
|
||||
|
||||
Service accounts can be managed as part of each project's YAML configuration. This allows creation of default service accounts used for GCE instances, in firewall rules, or for application-level credentials without resorting to a separate Terraform configuration.
|
||||
|
||||
Each service account is represented by one key and a set of optional key/value pairs in the `service_accounts` top-level YAML map, like in this example:
|
||||
Each service account is represented by one key and a set of optional key/value pairs in the `service_accounts` top-level YAML map, which expose most of the variables available in the `iam-service-account` module:
|
||||
|
||||
```yaml
|
||||
service_accounts:
|
||||
be-0: {}
|
||||
fe-1:
|
||||
display_name: GCE frontend service account.
|
||||
iam_self_roles:
|
||||
- roles/storage.objectViewer
|
||||
iam_project_roles:
|
||||
- roles/storage.objectViewer
|
||||
my-host-project:
|
||||
- roles/compute.networkUser
|
||||
```
|
||||
|
||||
Both the `display_name` and `iam_project_roles` attributes are optional.
|
||||
Both the `display_name` and `iam_self_roles` attributes are optional.
|
||||
|
||||
### Billing budgets
|
||||
|
||||
@@ -122,7 +125,7 @@ module "project-factory" {
|
||||
projects_data_path = "data/projects"
|
||||
}
|
||||
}
|
||||
# tftest modules=8 resources=35 files=prj-app-1,prj-app-2,prj-app-3,budget-test-100 inventory=example.yaml
|
||||
# tftest modules=8 resources=37 files=prj-app-1,prj-app-2,prj-app-3,budget-test-100
|
||||
```
|
||||
|
||||
```yaml
|
||||
@@ -140,11 +143,17 @@ services:
|
||||
- storage.googleapis.com
|
||||
service_accounts:
|
||||
app-1-be:
|
||||
iam_project_roles:
|
||||
iam_self_roles:
|
||||
- roles/logging.logWriter
|
||||
- roles/monitoring.metricWriter
|
||||
iam_project_roles:
|
||||
my-host-project:
|
||||
- roles/compute.networkUser
|
||||
app-1-fe:
|
||||
display_name: "Test app 1 frontend."
|
||||
iam_project_roles:
|
||||
my-host-project:
|
||||
- roles/compute.networkUser
|
||||
billing_budgets:
|
||||
- test-100
|
||||
# tftest-file id=prj-app-1 path=data/projects/prj-app-1.yaml
|
||||
@@ -223,9 +232,9 @@ update_rules:
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [factories_config](variables.tf#L91) | Path to folder with YAML resource description data files. | <code title="object({ projects_data_path = string budgets = optional(object({ billing_account = string budgets_data_path = string notification_channels = optional(map(any), {}) })) })">object({…})</code> | ✓ | |
|
||||
| [data_defaults](variables.tf#L17) | Optional default values used when corresponding project data from files are missing. | <code title="object({ billing_account = optional(string) contacts = optional(map(list(string)), {}) labels = optional(map(string), {}) metric_scopes = optional(list(string), []) parent = optional(string) prefix = optional(string) service_encryption_key_ids = optional(map(list(string)), {}) service_perimeter_bridges = optional(list(string), []) service_perimeter_standard = optional(string) services = optional(list(string), []) shared_vpc_service_config = optional(object({ host_project = string network_users = optional(list(string), []) service_identity_iam = optional(map(list(string)), {}) service_identity_subnet_iam = optional(map(list(string)), {}) service_iam_grants = optional(list(string), []) network_subnet_users = optional(map(list(string)), {}) }), { host_project = null }) tag_bindings = optional(map(string), {}) service_accounts = optional(map(object({ display_name = optional(string, "Terraform-managed.") iam_project_roles = optional(list(string)) })), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [data_merges](variables.tf#L49) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | <code title="object({ contacts = optional(map(list(string)), {}) labels = optional(map(string), {}) metric_scopes = optional(list(string), []) service_encryption_key_ids = optional(map(list(string)), {}) service_perimeter_bridges = optional(list(string), []) services = optional(list(string), []) tag_bindings = optional(map(string), {}) service_accounts = optional(map(object({ display_name = optional(string, "Terraform-managed.") iam_project_roles = optional(list(string)) })), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [data_overrides](variables.tf#L69) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | <code title="object({ billing_account = optional(string) contacts = optional(map(list(string))) parent = optional(string) prefix = optional(string) service_encryption_key_ids = optional(map(list(string))) service_perimeter_bridges = optional(list(string)) service_perimeter_standard = optional(string) tag_bindings = optional(map(string)) services = optional(list(string)) service_accounts = optional(map(object({ display_name = optional(string, "Terraform-managed.") iam_project_roles = optional(list(string)) }))) })">object({…})</code> | | <code>{}</code> |
|
||||
| [data_defaults](variables.tf#L17) | Optional default values used when corresponding project data from files are missing. | <code title="object({ billing_account = optional(string) contacts = optional(map(list(string)), {}) labels = optional(map(string), {}) metric_scopes = optional(list(string), []) parent = optional(string) prefix = optional(string) service_encryption_key_ids = optional(map(list(string)), {}) service_perimeter_bridges = optional(list(string), []) service_perimeter_standard = optional(string) services = optional(list(string), []) shared_vpc_service_config = optional(object({ host_project = string network_users = optional(list(string), []) service_identity_iam = optional(map(list(string)), {}) service_identity_subnet_iam = optional(map(list(string)), {}) service_iam_grants = optional(list(string), []) network_subnet_users = optional(map(list(string)), {}) }), { host_project = null }) tag_bindings = optional(map(string), {}) service_accounts = optional(map(object({ display_name = optional(string, "Terraform-managed.") iam_self_roles = optional(list(string)) })), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [data_merges](variables.tf#L49) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | <code title="object({ contacts = optional(map(list(string)), {}) labels = optional(map(string), {}) metric_scopes = optional(list(string), []) service_encryption_key_ids = optional(map(list(string)), {}) service_perimeter_bridges = optional(list(string), []) services = optional(list(string), []) tag_bindings = optional(map(string), {}) service_accounts = optional(map(object({ display_name = optional(string, "Terraform-managed.") iam_self_roles = optional(list(string)) })), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [data_overrides](variables.tf#L69) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | <code title="object({ billing_account = optional(string) contacts = optional(map(list(string))) parent = optional(string) prefix = optional(string) service_encryption_key_ids = optional(map(list(string))) service_perimeter_bridges = optional(list(string)) service_perimeter_standard = optional(string) tag_bindings = optional(map(string)) services = optional(list(string)) service_accounts = optional(map(object({ display_name = optional(string, "Terraform-managed.") iam_self_roles = optional(list(string)) }))) })">object({…})</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
||||
@@ -103,20 +103,31 @@ locals {
|
||||
var.data_defaults.tag_bindings
|
||||
)
|
||||
# non-project resources
|
||||
service_accounts = coalesce(
|
||||
var.data_overrides.service_accounts,
|
||||
try(v.service_accounts, null),
|
||||
var.data_defaults.service_accounts
|
||||
)
|
||||
service_accounts = try(v.service_accounts, {})
|
||||
})
|
||||
}
|
||||
service_accounts = flatten([
|
||||
for k, v in local.projects : [
|
||||
for name, opts in v.service_accounts : {
|
||||
project = k
|
||||
name = name
|
||||
display_name = try(opts.display_name, "Terraform-managed.")
|
||||
iam_project_roles = try(opts.iam_project_roles, null)
|
||||
project = k
|
||||
name = name
|
||||
display_name = coalesce(
|
||||
try(var.data_overrides.service_accounts.display_name, null),
|
||||
try(opts.display_name, null),
|
||||
try(var.data_defaults.service_accounts.display_name, null),
|
||||
"Terraform-managed."
|
||||
)
|
||||
iam_billing_roles = try(opts.iam_billing_roles, {})
|
||||
iam_organization_roles = try(opts.iam_organization_roles, {})
|
||||
iam_sa_roles = try(opts.iam_sa_roles, {})
|
||||
iam_project_roles = try(opts.iam_project_roles, {})
|
||||
iam_self_roles = distinct(concat(
|
||||
try(var.data_overrides.service_accounts.iam_self_roles, []),
|
||||
try(opts.iam_self_roles, []),
|
||||
try(var.data_defaults.service_accounts.iam_self_roles, []),
|
||||
))
|
||||
iam_storage_roles = try(opts.iam_storage_roles, {})
|
||||
opts = opts
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
@@ -67,14 +67,17 @@ module "projects" {
|
||||
module "service-accounts" {
|
||||
source = "../iam-service-account"
|
||||
for_each = {
|
||||
for k in local.service_accounts : "${k.project}-${k.name}" => k
|
||||
for k in local.service_accounts : "${k.project}/${k.name}" => k
|
||||
}
|
||||
project_id = module.projects[each.value.project].project_id
|
||||
name = each.value.name
|
||||
display_name = each.value.display_name
|
||||
iam_project_roles = each.value.iam_project_roles == null ? {} : {
|
||||
(module.projects[each.value.project].project_id) = each.value.iam_project_roles
|
||||
}
|
||||
iam_project_roles = merge(
|
||||
each.value.iam_project_roles,
|
||||
each.value.iam_self_roles == null ? {} : {
|
||||
(module.projects[each.value.project].project_id) = each.value.iam_self_roles
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
module "billing-account" {
|
||||
|
||||
@@ -21,7 +21,6 @@ output "projects" {
|
||||
|
||||
output "service_accounts" {
|
||||
description = "Service account emails."
|
||||
# TODO: group by project
|
||||
value = {
|
||||
for k, v in module.service-accounts : k => v.email
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ variable "data_defaults" {
|
||||
tag_bindings = optional(map(string), {})
|
||||
# non-project resources
|
||||
service_accounts = optional(map(object({
|
||||
display_name = optional(string, "Terraform-managed.")
|
||||
iam_project_roles = optional(list(string))
|
||||
display_name = optional(string, "Terraform-managed.")
|
||||
iam_self_roles = optional(list(string))
|
||||
})), {})
|
||||
})
|
||||
nullable = false
|
||||
@@ -58,8 +58,8 @@ variable "data_merges" {
|
||||
tag_bindings = optional(map(string), {})
|
||||
# non-project resources
|
||||
service_accounts = optional(map(object({
|
||||
display_name = optional(string, "Terraform-managed.")
|
||||
iam_project_roles = optional(list(string))
|
||||
display_name = optional(string, "Terraform-managed.")
|
||||
iam_self_roles = optional(list(string))
|
||||
})), {})
|
||||
})
|
||||
nullable = false
|
||||
@@ -80,8 +80,8 @@ variable "data_overrides" {
|
||||
services = optional(list(string))
|
||||
# non-project resources
|
||||
service_accounts = optional(map(object({
|
||||
display_name = optional(string, "Terraform-managed.")
|
||||
iam_project_roles = optional(list(string))
|
||||
display_name = optional(string, "Terraform-managed.")
|
||||
iam_self_roles = optional(list(string))
|
||||
})))
|
||||
})
|
||||
nullable = false
|
||||
|
||||
Reference in New Issue
Block a user