Refactor vps-sc module for Terraform 1.3 (#963)
* wip * example tests * module tests * streamline example * fast * tfdoc * use collections.Counter in tests
This commit is contained in:
committed by
GitHub
parent
b7bfcf3575
commit
a9c47681d8
@@ -2,7 +2,7 @@
|
||||
|
||||
This module offers a unified interface to manage VPC Service Controls [Access Policy](https://cloud.google.com/access-context-manager/docs/create-access-policy), [Access Levels](https://cloud.google.com/access-context-manager/docs/manage-access-levels), and [Service Perimeters](https://cloud.google.com/vpc-service-controls/docs/service-perimeters).
|
||||
|
||||
Given the complexity of the underlying resources, the module intentionally mimics their interfaces to make it easier to map their documentation onto its variables, and reduce the internal complexity. The tradeoff is some verbosity, and a very complex type for the `service_perimeters_regular` variable (while [optional type attributes](https://www.terraform.io/language/expressions/type-constraints#experimental-optional-object-type-attributes) are still an experiment).
|
||||
Given the complexity of the underlying resources, the module intentionally mimics their interfaces to make it easier to map their documentation onto its variables, and reduce the internal complexity.
|
||||
|
||||
If you are using [Application Default Credentials](https://cloud.google.com/sdk/gcloud/reference/auth/application-default) with Terraform and run into permissions issues, make sure to check out the recommended provider configuration in the [VPC SC resources documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_access_level).
|
||||
|
||||
@@ -44,21 +44,16 @@ module "test" {
|
||||
access_policy = "12345678"
|
||||
access_levels = {
|
||||
a1 = {
|
||||
combining_function = null
|
||||
conditions = [{
|
||||
members = ["user:user1@example.com"], ip_subnetworks = null,
|
||||
negate = null, regions = null, required_access_levels = null
|
||||
}]
|
||||
conditions = [
|
||||
{ members = ["user:user1@example.com"] }
|
||||
]
|
||||
}
|
||||
a2 = {
|
||||
combining_function = "OR"
|
||||
conditions = [{
|
||||
regions = ["IT", "FR"], ip_subnetworks = null,
|
||||
members = null, negate = null, required_access_levels = null
|
||||
},{
|
||||
ip_subnetworks = ["101.101.101.0/24"], members = null,
|
||||
negate = null, regions = null, required_access_levels = null
|
||||
}]
|
||||
conditions = [
|
||||
{ regions = ["IT", "FR"] },
|
||||
{ ip_subnetworks = ["101.101.101.0/24"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,12 +80,9 @@ module "test" {
|
||||
access_policy = "12345678"
|
||||
service_perimeters_bridge = {
|
||||
b1 = {
|
||||
status_resources = ["projects/111110", "projects/111111"]
|
||||
spec_resources = null
|
||||
use_explicit_dry_run_spec = false
|
||||
status_resources = ["projects/111110", "projects/111111"]
|
||||
}
|
||||
b2 = {
|
||||
status_resources = null
|
||||
spec_resources = ["projects/222220", "projects/222221"]
|
||||
use_explicit_dry_run_spec = true
|
||||
}
|
||||
@@ -107,65 +99,61 @@ module "test" {
|
||||
access_policy = "12345678"
|
||||
access_levels = {
|
||||
a1 = {
|
||||
combining_function = null
|
||||
conditions = [{
|
||||
members = ["user:user1@example.com"], ip_subnetworks = null,
|
||||
negate = null, regions = null, required_access_levels = null
|
||||
}]
|
||||
conditions = [
|
||||
{ members = ["user:user1@example.com"] }
|
||||
]
|
||||
}
|
||||
a2 = {
|
||||
combining_function = null
|
||||
conditions = [{
|
||||
members = ["user:user2@example.com"], ip_subnetworks = null,
|
||||
negate = null, regions = null, required_access_levels = null
|
||||
}]
|
||||
conditions = [
|
||||
{ members = ["user:user2@example.com"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
egress_policies = {
|
||||
# allow writing to external GCS bucket from a specific SA
|
||||
gcs-sa-foo = {
|
||||
from = {
|
||||
identities = [
|
||||
"serviceAccount:foo@myproject.iam.gserviceaccount.com"
|
||||
]
|
||||
}
|
||||
to = {
|
||||
operations = [{
|
||||
method_selectors = ["*"]
|
||||
service_name = "storage.googleapis.com"
|
||||
}]
|
||||
resources = ["projects/123456789"]
|
||||
}
|
||||
}
|
||||
}
|
||||
ingress_policies = {
|
||||
# allow management from external automation SA
|
||||
sa-tf-test = {
|
||||
from = {
|
||||
identities = [
|
||||
"serviceAccount:test-tf@myproject.iam.gserviceaccount.com",
|
||||
],
|
||||
source_access_levels = ["*"]
|
||||
}
|
||||
to = {
|
||||
operations = [{ service_name = "*" }]
|
||||
resources = ["*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
service_perimeters_regular = {
|
||||
r1 = {
|
||||
spec = null
|
||||
status = {
|
||||
access_levels = [module.test.access_level_names["a1"], "a2"]
|
||||
access_levels = ["a1", "a2"]
|
||||
resources = ["projects/11111", "projects/111111"]
|
||||
restricted_services = ["storage.googleapis.com"]
|
||||
# example: allow writing to external GCS bucket
|
||||
egress_policies = [
|
||||
{
|
||||
egress_from = {
|
||||
identity_type = null
|
||||
identities = [
|
||||
"serviceAccount:foo@myproject.iam.gserviceaccount.com"
|
||||
]
|
||||
}
|
||||
egress_to = {
|
||||
operations = [{
|
||||
method_selectors = ["*"], service_name = "storage.googleapis.com"
|
||||
}]
|
||||
resources = ["projects/123456789"]
|
||||
}
|
||||
}
|
||||
]
|
||||
# example: allow management from external automation SA
|
||||
ingress_policies = [
|
||||
{
|
||||
ingress_from = {
|
||||
identities = [
|
||||
"serviceAccount:test-tf@myproject.iam.gserviceaccount.com",
|
||||
],
|
||||
source_access_levels = ["*"], identity_type = null, source_resources = null
|
||||
}
|
||||
ingress_to = {
|
||||
operations = [{ method_selectors = [], service_name = "*" }]
|
||||
resources = ["*"]
|
||||
}
|
||||
}
|
||||
]
|
||||
egress_policies = ["gcs-sa-foo"]
|
||||
ingress_policies = ["sa-tf-test"]
|
||||
vpc_accessible_services = {
|
||||
allowed_services = ["storage.googleapis.com"]
|
||||
enable_restriction = true
|
||||
}
|
||||
}
|
||||
use_explicit_dry_run_spec = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,17 +167,33 @@ module "test" {
|
||||
## TODO
|
||||
|
||||
- [ ] implement support for the `google_access_context_manager_gcp_user_access_binding` resource
|
||||
|
||||
<!-- TFDOC OPTS files:1 -->
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Files
|
||||
|
||||
| name | description | resources |
|
||||
|---|---|---|
|
||||
| [access-levels.tf](./access-levels.tf) | Access level resources. | <code>google_access_context_manager_access_level</code> |
|
||||
| [main.tf](./main.tf) | Module-level locals and resources. | <code>google_access_context_manager_access_policy</code> |
|
||||
| [outputs.tf](./outputs.tf) | Module outputs. | |
|
||||
| [service-perimeters-bridge.tf](./service-perimeters-bridge.tf) | Bridge service perimeter resources. | <code>google_access_context_manager_service_perimeter</code> |
|
||||
| [service-perimeters-regular.tf](./service-perimeters-regular.tf) | Regular service perimeter resources. | <code>google_access_context_manager_service_perimeter</code> |
|
||||
| [variables.tf](./variables.tf) | Module variables. | |
|
||||
| [versions.tf](./versions.tf) | Version pins. | |
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [access_policy](variables.tf#L55) | Access Policy name, leave null to use auto-created one. | <code>string</code> | ✓ | |
|
||||
| [access_levels](variables.tf#L17) | Map of access levels in name => [conditions] format. | <code title="map(object({ combining_function = string conditions = list(object({ ip_subnetworks = list(string) members = list(string) negate = bool regions = list(string) required_access_levels = list(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [access_policy_create](variables.tf#L60) | Access Policy configuration, fill in to create. Parent is in 'organizations/123456' format. | <code title="object({ parent = string title = string })">object({…})</code> | | <code>null</code> |
|
||||
| [service_perimeters_bridge](variables.tf#L69) | Bridge service perimeters. | <code title="map(object({ spec_resources = list(string) status_resources = list(string) use_explicit_dry_run_spec = bool }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [service_perimeters_regular](variables.tf#L79) | Regular service perimeters. | <code title="map(object({ spec = object({ access_levels = list(string) resources = list(string) restricted_services = list(string) egress_policies = list(object({ egress_from = object({ identity_type = string identities = list(string) }) egress_to = object({ operations = list(object({ method_selectors = list(string) service_name = string })) resources = list(string) }) })) ingress_policies = list(object({ ingress_from = object({ identity_type = string identities = list(string) source_access_levels = list(string) source_resources = list(string) }) ingress_to = object({ operations = list(object({ method_selectors = list(string) service_name = string })) resources = list(string) }) })) vpc_accessible_services = object({ allowed_services = list(string) enable_restriction = bool }) }) status = object({ access_levels = list(string) resources = list(string) restricted_services = list(string) egress_policies = list(object({ egress_from = object({ identity_type = string identities = list(string) }) egress_to = object({ operations = list(object({ method_selectors = list(string) service_name = string })) resources = list(string) }) })) ingress_policies = list(object({ ingress_from = object({ identity_type = string identities = list(string) source_access_levels = list(string) source_resources = list(string) }) ingress_to = object({ operations = list(object({ method_selectors = list(string) service_name = string })) resources = list(string) }) })) vpc_accessible_services = object({ allowed_services = list(string) enable_restriction = bool }) }) use_explicit_dry_run_spec = bool }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [access_policy](variables.tf#L56) | Access Policy name, set to null if creating one. | <code>string</code> | ✓ | |
|
||||
| [access_levels](variables.tf#L17) | Access level definitions. | <code title="map(object({ combining_function = optional(string) conditions = optional(list(object({ device_policy = optional(object({ allowed_device_management_levels = optional(list(string)) allowed_encryption_statuses = optional(list(string)) require_admin_approval = bool require_corp_owned = bool require_screen_lock = optional(bool) os_constraints = optional(list(object({ os_type = string minimum_version = optional(string) require_verified_chrome_os = optional(bool) }))) })) ip_subnetworks = optional(list(string), []) members = optional(list(string), []) negate = optional(bool) regions = optional(list(string), []) required_access_levels = optional(list(string), []) })), []) description = optional(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [access_policy_create](variables.tf#L61) | Access Policy configuration, fill in to create. Parent is in 'organizations/123456' format. | <code title="object({ parent = string title = string })">object({…})</code> | | <code>null</code> |
|
||||
| [egress_policies](variables.tf#L70) | Egress policy definitions that can be referenced in perimeters. | <code title="map(object({ from = object({ identity_type = optional(string, "ANY_IDENTITY") identities = optional(list(string)) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) resource_type_external = optional(bool, false) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [ingress_policies](variables.tf#L99) | Ingress policy definitions that can be referenced in perimeters. | <code title="map(object({ from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [service_perimeters_bridge](variables.tf#L130) | Bridge service perimeters. | <code title="map(object({ spec_resources = optional(list(string)) status_resources = optional(list(string)) use_explicit_dry_run_spec = optional(bool, false) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [service_perimeters_regular](variables.tf#L140) | Regular service perimeters. | <code title="map(object({ spec = optional(object({ access_levels = optional(list(string)) resources = optional(list(string)) restricted_services = optional(list(string)) egress_policies = optional(list(string)) ingress_policies = optional(list(string)) vpc_accessible_services = optional(object({ allowed_services = list(string) enable_restriction = bool })) }), {}) status = optional(object({ access_levels = optional(list(string)) resources = optional(list(string)) restricted_services = optional(list(string)) egress_policies = optional(list(string)) ingress_policies = optional(list(string)) vpc_accessible_services = optional(object({ allowed_services = list(string) enable_restriction = bool })) }), {}) use_explicit_dry_run_spec = optional(bool, false) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user