Add support for `iam_additive` and simplify factory interface in net VPC module (#1259)
* initial implementation, no tests * change interface, align tests * add examples ToC * fix variable type, test module-level variable
This commit is contained in:
parent
50adf1da2a
commit
8a8b7ea35f
|
@ -1,10 +1,20 @@
|
|||
# Minimalistic VPC module
|
||||
# VPC module
|
||||
|
||||
This module allows creation and management of VPC networks including subnetworks and subnetwork IAM bindings, Shared VPC activation and service project registration, and one-to-one peering.
|
||||
This module allows creation and management of VPC networks including subnetworks and subnetwork IAM bindings, and most features and options related to VPCs and subnets.
|
||||
|
||||
## Examples
|
||||
|
||||
The module allows for several different VPC configurations, some of the most common are shown below.
|
||||
- [Simple VPC](#simple-vpc)
|
||||
- [Subnet Options](#subnet-options)
|
||||
- [Subnet IAM](#subnet-iam)
|
||||
- [Peering](#peering)
|
||||
- [Shared VPC](#shared-vpc)
|
||||
- [Private Service Networking](#private-service-networking)
|
||||
- [Private Service Networking with Peering Routes](#private-service-networking-with-peering-routes)
|
||||
- [Subnets for Private Service Connect, Proxy-only subnets](#subnets-for-private-service-connect-proxy-only-subnets)
|
||||
- [DNS Policies](#dns-policies)
|
||||
- [Subnet Factory](#subnet-factory)
|
||||
- [Custom Routes](#custom-routes)
|
||||
|
||||
### Simple VPC
|
||||
|
||||
|
@ -105,6 +115,8 @@ module "vpc" {
|
|||
"user:user1@example.com", "group:group1@example.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
subnet_iam_additive = {
|
||||
"europe-west1/subnet-2" = {
|
||||
"roles/compute.networkUser" = [
|
||||
"user:user2@example.com", "group:group2@example.com"
|
||||
|
@ -112,7 +124,7 @@ module "vpc" {
|
|||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=5 inventory=subnet-iam.yaml
|
||||
# tftest modules=1 resources=6 inventory=subnet-iam.yaml
|
||||
```
|
||||
|
||||
### Peering
|
||||
|
@ -315,7 +327,7 @@ module "vpc" {
|
|||
name = "my-network"
|
||||
data_folder = "config/subnets"
|
||||
}
|
||||
# tftest modules=1 resources=7 files=subnet-simple,subnet-simple-2,subnet-detailed,subnet-proxy,subnet-psc inventory=factory.yaml
|
||||
# tftest modules=1 resources=9 files=subnet-simple,subnet-simple-2,subnet-detailed,subnet-proxy,subnet-psc inventory=factory.yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
|
@ -339,9 +351,13 @@ description: Sample description
|
|||
ip_cidr_range: 10.0.0.0/24
|
||||
# optional attributes
|
||||
enable_private_access: false # defaults to true
|
||||
iam_users: ["foobar@example.com"] # grant compute/networkUser to users
|
||||
iam_groups: ["lorem@example.com"] # grant compute/networkUser to groups
|
||||
iam_service_accounts: ["fbz@prj.iam.gserviceaccount.com"]
|
||||
iam: # grant roles/compute.networkUser
|
||||
- group:lorem@example.com
|
||||
- serviceAccount:fbz@prj.iam.gserviceaccount.com
|
||||
- user:foobar@example.com
|
||||
iam_additive: # grant roles/compute.networkUser
|
||||
- user:foo@example.com
|
||||
- serviceAccount:fbx@prj.iam.gserviceaccount.com
|
||||
secondary_ip_ranges: # map of secondary ip ranges
|
||||
secondary-range-a: 192.168.0.0/24
|
||||
flow_logs: # enable, set to empty map to use defaults
|
||||
|
@ -402,6 +418,7 @@ module "vpc" {
|
|||
}
|
||||
# tftest modules=5 resources=15 inventory=routes.yaml
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
|
@ -422,10 +439,11 @@ module "vpc" {
|
|||
| [shared_vpc_host](variables.tf#L121) | Enable shared VPC for this project. | <code>bool</code> | | <code>false</code> |
|
||||
| [shared_vpc_service_projects](variables.tf#L127) | Shared VPC service projects to register with this host. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [subnet_iam](variables.tf#L133) | Subnet IAM bindings in {REGION/NAME => {ROLE => [MEMBERS]} format. | <code>map(map(list(string)))</code> | | <code>{}</code> |
|
||||
| [subnets](variables.tf#L139) | Subnet configuration. | <code title="list(object({ name = string ip_cidr_range = string region = string description = optional(string) enable_private_access = optional(bool, true) flow_logs_config = optional(object({ aggregation_interval = optional(string) filter_expression = optional(string) flow_sampling = optional(number) metadata = optional(string) metadata_fields = optional(list(string)) })) ipv6 = optional(object({ access_type = optional(string) enable_private_access = optional(bool, true) })) secondary_ip_ranges = optional(map(string)) }))">list(object({…}))</code> | | <code>[]</code> |
|
||||
| [subnets_proxy_only](variables.tf#L164) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | <code title="list(object({ name = string ip_cidr_range = string region = string description = optional(string) active = bool }))">list(object({…}))</code> | | <code>[]</code> |
|
||||
| [subnets_psc](variables.tf#L176) | List of subnets for Private Service Connect service producers. | <code title="list(object({ name = string ip_cidr_range = string region = string description = optional(string) }))">list(object({…}))</code> | | <code>[]</code> |
|
||||
| [vpc_create](variables.tf#L187) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> |
|
||||
| [subnet_iam_additive](variables.tf#L139) | Subnet IAM additive bindings in {REGION/NAME => {ROLE => [MEMBERS]}} format. | <code>map(map(list(string)))</code> | | <code>{}</code> |
|
||||
| [subnets](variables.tf#L146) | Subnet configuration. | <code title="list(object({ name = string ip_cidr_range = string region = string description = optional(string) enable_private_access = optional(bool, true) flow_logs_config = optional(object({ aggregation_interval = optional(string) filter_expression = optional(string) flow_sampling = optional(number) metadata = optional(string) metadata_fields = optional(list(string)) })) ipv6 = optional(object({ access_type = optional(string) enable_private_access = optional(bool, true) })) secondary_ip_ranges = optional(map(string)) }))">list(object({…}))</code> | | <code>[]</code> |
|
||||
| [subnets_proxy_only](variables.tf#L171) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | <code title="list(object({ name = string ip_cidr_range = string region = string description = optional(string) active = bool }))">list(object({…}))</code> | | <code>[]</code> |
|
||||
| [subnets_psc](variables.tf#L183) | List of subnets for Private Service Connect service producers. | <code title="list(object({ name = string ip_cidr_range = string region = string description = optional(string) }))">list(object({…}))</code> | | <code>[]</code> |
|
||||
| [vpc_create](variables.tf#L194) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
@ -445,4 +463,3 @@ module "vpc" {
|
|||
| [subnets_psc](outputs.tf#L112) | Private Service Connect subnet resources. | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
The key format is `subnet_region/subnet_name`. For example `europe-west1/my_subnet`.
|
||||
|
|
|
@ -31,24 +31,39 @@ locals {
|
|||
flow_logs_config = try(v.flow_logs, null)
|
||||
ipv6 = try(v.ipv6, null)
|
||||
secondary_ip_ranges = try(v.secondary_ip_ranges, null)
|
||||
iam_groups = try(v.iam_groups, [])
|
||||
iam_users = try(v.iam_users, [])
|
||||
iam_service_accounts = try(v.iam_service_accounts, [])
|
||||
iam = try(v.iam, [])
|
||||
iam_additive = try(v.iam_additive, [])
|
||||
purpose = try(v.purpose, null)
|
||||
active = try(v.active, null)
|
||||
}
|
||||
}
|
||||
_factory_subnets_iam_additive = flatten([
|
||||
for k, v in local._factory_subnets : [
|
||||
for member in lookup(v, "iam_additive", []) : {
|
||||
member = member
|
||||
subnet = k
|
||||
role = "roles/compute.networkUser"
|
||||
}
|
||||
] if v.purpose == null
|
||||
])
|
||||
_factory_subnets_iam = [
|
||||
for k, v in local._factory_subnets : {
|
||||
subnet = k
|
||||
role = "roles/compute.networkUser"
|
||||
members = concat(
|
||||
formatlist("group:%s", lookup(v, "iam_groups", [])),
|
||||
formatlist("user:%s", lookup(v, "iam_users", [])),
|
||||
formatlist("serviceAccount:%s", lookup(v, "iam_service_accounts", []))
|
||||
)
|
||||
} if v.purpose == null
|
||||
members = v.iam
|
||||
} if v.purpose == null && v.iam != null
|
||||
]
|
||||
_subnet_iam_additive_members = flatten([
|
||||
for subnet, roles in var.subnet_iam_additive : [
|
||||
for role, members in roles : [
|
||||
for member in members : {
|
||||
member = member
|
||||
role = role
|
||||
subnet = subnet
|
||||
}
|
||||
]
|
||||
]
|
||||
])
|
||||
_subnet_iam_members = flatten([
|
||||
for subnet, roles in(var.subnet_iam == null ? {} : var.subnet_iam) : [
|
||||
for role, members in roles : {
|
||||
|
@ -58,6 +73,10 @@ locals {
|
|||
}
|
||||
]
|
||||
])
|
||||
subnet_iam_additive_members = concat(
|
||||
local._factory_subnets_iam_additive,
|
||||
local._subnet_iam_additive_members
|
||||
)
|
||||
subnet_iam_members = concat(
|
||||
[for k in local._factory_subnets_iam : k if length(k.members) > 0],
|
||||
local._subnet_iam_members
|
||||
|
@ -151,3 +170,15 @@ resource "google_compute_subnetwork_iam_binding" "binding" {
|
|||
role = each.value.role
|
||||
members = each.value.members
|
||||
}
|
||||
|
||||
resource "google_compute_subnetwork_iam_member" "binding" {
|
||||
for_each = {
|
||||
for binding in local.subnet_iam_additive_members :
|
||||
"${binding.subnet}.${binding.role}.${binding.member}" => binding
|
||||
}
|
||||
project = var.project_id
|
||||
subnetwork = google_compute_subnetwork.subnetwork[each.value.subnet].name
|
||||
region = google_compute_subnetwork.subnetwork[each.value.subnet].region
|
||||
role = each.value.role
|
||||
member = each.value.member
|
||||
}
|
||||
|
|
|
@ -136,6 +136,13 @@ variable "subnet_iam" {
|
|||
default = {}
|
||||
}
|
||||
|
||||
variable "subnet_iam_additive" {
|
||||
description = "Subnet IAM additive bindings in {REGION/NAME => {ROLE => [MEMBERS]}} format."
|
||||
type = map(map(list(string)))
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "subnets" {
|
||||
description = "Subnet configuration."
|
||||
type = list(object({
|
||||
|
|
|
@ -34,11 +34,16 @@ values:
|
|||
region: europe-west1
|
||||
role: roles/compute.networkUser
|
||||
subnetwork: subnet-1
|
||||
module.vpc.google_compute_subnetwork_iam_binding.binding["europe-west1/subnet-2.roles/compute.networkUser"]:
|
||||
module.vpc.google_compute_subnetwork_iam_member.binding["europe-west1/subnet-2.roles/compute.networkUser.user:user2@example.com"]:
|
||||
condition: []
|
||||
members:
|
||||
- group:group2@example.com
|
||||
- user:user2@example.com
|
||||
member: user:user2@example.com
|
||||
project: my-project
|
||||
region: europe-west1
|
||||
role: roles/compute.networkUser
|
||||
subnetwork: subnet-2
|
||||
module.vpc.google_compute_subnetwork_iam_member.binding["europe-west1/subnet-2.roles/compute.networkUser.group:group2@example.com"]:
|
||||
condition: []
|
||||
member: group:group2@example.com
|
||||
project: my-project
|
||||
region: europe-west1
|
||||
role: roles/compute.networkUser
|
||||
|
@ -47,8 +52,7 @@ values:
|
|||
counts:
|
||||
google_compute_network: 1
|
||||
google_compute_subnetwork: 2
|
||||
google_compute_subnetwork_iam_binding: 2
|
||||
modules: 1
|
||||
resources: 5
|
||||
google_compute_subnetwork_iam_binding: 1
|
||||
google_compute_subnetwork_iam_member: 2
|
||||
|
||||
outputs: {}
|
||||
|
|
Loading…
Reference in New Issue