diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 91d90d46..ee0d63a3 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -34,6 +34,8 @@ module "test" { # tftest modules=1 resources=1 inventory=access-policy.yaml ``` +#### Scoped policy + If you need the module to create a scoped policy for you, specify 'scopes' of the policy in the `access_policy_create` variable: ```hcl @@ -49,6 +51,23 @@ module "test" { # tftest modules=1 resources=1 inventory=scoped-access-policy.yaml ``` +#### Access policy IAM + +The usual IAM interface is also implemented here, and can be used with service accounts or user principals: + +```hcl +module "test" { + source = "./fabric/modules/vpc-sc" + access_policy = "12345678" + iam = { + "roles/accesscontextmanager.policyAdmin" = [ + "user:foo@example.org" + ] + } +} +# tftest modules=1 resources=1 +``` + ### Access levels As highlighted above, the `access_levels` type replicates the underlying resource structure. @@ -190,6 +209,7 @@ module "test" { | name | description | resources | |---|---|---| | [access-levels.tf](./access-levels.tf) | Access level resources. | google_access_context_manager_access_level | +| [iam.tf](./iam.tf) | IAM bindings | google_access_context_manager_access_policy_iam_binding ยท google_access_context_manager_access_policy_iam_member | | [main.tf](./main.tf) | Module-level locals and resources. | google_access_context_manager_access_policy | | [outputs.tf](./outputs.tf) | Module outputs. | | | [service-perimeters-bridge.tf](./service-perimeters-bridge.tf) | Bridge service perimeter resources. | google_access_context_manager_service_perimeter | @@ -205,9 +225,12 @@ module "test" { | [access_levels](variables.tf#L17) | Access level definitions. | map(object({…})) | | {} | | [access_policy_create](variables.tf#L61) | Access Policy configuration, fill in to create. Parent is in 'organizations/123456' format, scopes are in 'folders/456789' or 'projects/project_id' format. | object({…}) | | null | | [egress_policies](variables.tf#L71) | Egress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | -| [ingress_policies](variables.tf#L102) | Ingress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | -| [service_perimeters_bridge](variables.tf#L134) | Bridge service perimeters. | map(object({…})) | | {} | -| [service_perimeters_regular](variables.tf#L144) | Regular service perimeters. | map(object({…})) | | {} | +| [iam](variables.tf#L102) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [iam_bindings](variables.tf#L108) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | +| [iam_bindings_additive](variables.tf#L123) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | +| [ingress_policies](variables.tf#L138) | Ingress policy definitions that can be referenced in perimeters. | map(object({…})) | | {} | +| [service_perimeters_bridge](variables.tf#L170) | Bridge service perimeters. | map(object({…})) | | {} | +| [service_perimeters_regular](variables.tf#L180) | Regular service perimeters. | map(object({…})) | | {} | ## Outputs diff --git a/modules/vpc-sc/iam.tf b/modules/vpc-sc/iam.tf new file mode 100644 index 00000000..9b475b68 --- /dev/null +++ b/modules/vpc-sc/iam.tf @@ -0,0 +1,54 @@ +/** + * Copyright 2023 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. + */ + +# tfdoc:file:description IAM bindings + +resource "google_access_context_manager_access_policy_iam_binding" "authoritative" { + for_each = var.iam + name = local.access_policy + role = each.key + members = each.value +} + +resource "google_access_context_manager_access_policy_iam_binding" "bindings" { + for_each = var.iam_bindings + name = local.access_policy + role = each.value.role + members = each.value.members + 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_access_context_manager_access_policy_iam_member" "bindings" { + for_each = var.iam_bindings_additive + name = local.access_policy + role = each.value.role + member = each.value.member + dynamic "condition" { + for_each = each.value.condition == null ? [] : [""] + content { + expression = each.value.condition.expression + title = each.value.condition.title + description = each.value.condition.description + } + } +} diff --git a/modules/vpc-sc/variables.tf b/modules/vpc-sc/variables.tf index 8ce4b41e..008d7ae2 100644 --- a/modules/vpc-sc/variables.tf +++ b/modules/vpc-sc/variables.tf @@ -99,6 +99,42 @@ variable "egress_policies" { } } +variable "iam" { + description = "IAM bindings in {ROLE => [MEMBERS]} format." + type = map(list(string)) + default = {} +} + +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) + })) + })) + nullable = false + default = {} +} + +variable "iam_bindings_additive" { + description = "Individual additive IAM bindings. Keys are arbitrary." + type = map(object({ + member = string + role = string + condition = optional(object({ + expression = string + title = string + description = optional(string) + })) + })) + nullable = false + default = {} +} + variable "ingress_policies" { description = "Ingress policy definitions that can be referenced in perimeters." type = map(object({