Skip to content

Commit

Permalink
Add IAM variables template to ADR
Browse files Browse the repository at this point in the history
  • Loading branch information
juliocc committed Sep 17, 2023
1 parent 0c578c0 commit 7e7981a
Showing 1 changed file with 212 additions and 2 deletions.
214 changes: 212 additions & 2 deletions modules/__docs/20230816-iam-refactor.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ The new variable will closely follow the type of the authoritative `iam_bindings
variable "iam_bindings_additive" {
description = "Additive IAM bindings with support for conditions, in {KEY => { role = ROLE, members = [], condition = {}}} format."
type = map(object({
member = string
role = string
member = string
role = string
condition = optional(object({
expression = string
title = string
Expand Down Expand Up @@ -132,3 +132,213 @@ This brings several advantages over the previous handling of IAM:
### Blueprints

A few data blueprints that leverage `iam_additive` have been refactored to use the new variable. This is most notable in data blueprints, where extra files have been added to the more complex examples like data foundations, to abstract IAM bindings in a way similar to what is described above for FAST.

## Implementation

The following sections provide a template for IAM-related variables and resources to ensure a consistent implementation of IAM across the repository. Use these code snippets to add IAM support to your module.

### Top-level module IAM

Use this template if your module manages a single instance of a given resource (e.g. a KMS keyring).

```terraform
# variables.tf
variable "iam" {
description = "IAM bindings in {ROLE => [MEMBERS]} format. Mutually exclusive with the access_* variables used for basic roles."
type = map(list(string))
default = {}
nullable = false
}
variable "iam_bindings" {
description = "Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary."
type = map(object({
members = list(string)
role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
}))
default = {}
nullable = false
}
variable "iam_bindings_additive" {
description = "Keyring individual additive IAM bindings. Keys are arbitrary."
type = map(object({
member = string
role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
}))
default = {}
nullable = false
}
```

```terraform
# iam.tf
resource "google_RESOURCE_TYPE_iam_binding" "authoritative" {
for_each = var.iam
role = each.key
members = each.value
// add extra attributes (e.g. resource id)
}
resource "google_RESOURCE_TYPE_iam_binding" "bindings" {
for_each = var.iam_bindings
role = each.value.role
members = each.value.members
// add extra attributes (e.g. resource id)
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
}
resource "google_RESOURCE_TYPE_iam_member" "bindings" {
for_each = var.iam_bindings_additive
role = each.value.role
member = each.value.member
// add extra attributes (e.g. resource id)
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
}
```

### Sub-resources IAM

Use this template if your module manages multiple instances of a resource (e.g. keys in KMS keyring).

```terraform
# variables.tf
variable "sub_resources" {
type = map(object({
# sub-resource configuration here
iam = optional(map(list(string)), {})
iam_bindings = optional(map(object({
members = list(string)
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})), {})
iam_bindings_additive = optional(map(object({
member = string
role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})), {})
}))
default = {}
nullable = false
}
```

```terraform
# iam.tf
locals {
SUB_RESOURCE_iam = flatten([
for k, v in var.SUB_RESOURCEs : [
for role, members in v.iam : {
key = k
role = role
members = members
}
]
])
SUB_RESOURCE_iam_bindings = merge([
for k, v in var.SUB_RESOURCEs : {
for binding_key, data in v.iam_bindings :
binding_key => {
SUB_RESOURCE = k
role = data.role
members = data.members
condition = data.condition
}
}
]...)
SUB_RESOURCE_iam_bindings_additive = merge([
for k, v in var.subresources : {
for binding_key, data in v.iam_bindings_additive :
binding_key => {
SUB_RESOURCE = k
role = data.role
member = data.member
condition = data.condition
}
}
]...)
}
```

```terraform
# iam.tf
resource "google_SUB_RESOURCE_iam_binding" "authoritative" {
for_each = {
for binding in local.SUB_RESOURCE_iam :
"${binding.key}.${binding.role}" => binding
}
role = each.value.role
members = each.value.members
// add extra attributes (e.g. sub resource id)
}
resource "google_SUB_RESOURCE_iam_binding" "bindings" {
for_each = local.SUB_RESOURCE_iam_bindings
role = each.value.role
members = each.value.members
// add extra attributes (e.g. sub resource id)
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
}
resource "google_SUB_RESOURCE_iam_member" "members" {
for_each = local.SUB_RESOURCE_iam_bindings_additive
role = each.value.role
member = each.value.member
// add extra attributes (e.g. sub resource id)
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
}
```

0 comments on commit 7e7981a

Please sign in to comment.