diff --git a/README.md b/README.md index 6c19273..0f31a0a 100644 --- a/README.md +++ b/README.md @@ -785,6 +785,11 @@ The following dependencies must be available: A service account with the following permission must be used to provision the resources of this module: +- compute.networkEdgeSecurityServices.create +- compute.networkEdgeSecurityServices.update +- compute.networkEdgeSecurityServices.get +- compute.networkEdgeSecurityServices.delete +- compute.networkEdgeSecurityServices.list - compute.securityPolicies.create - compute.securityPolicies.delete - compute.securityPolicies.get diff --git a/examples/advanced-network-ddos-protection/main.tf b/examples/advanced-network-ddos-protection/main.tf index 6cfde4e..e390661 100644 --- a/examples/advanced-network-ddos-protection/main.tf +++ b/examples/advanced-network-ddos-protection/main.tf @@ -24,6 +24,6 @@ module "advanced_network_ddos_protection" { project_id = var.project_id regions = ["us-central1", "us-east1"] - policy_name = "adv-network-ddos-protection-${random_id.suffix.hex}" - network_edge_security_service_name = "adv-network-ddos-protection-${random_id.suffix.hex}" + policy_name = "test-adv-network-ddos-protection-${random_id.suffix.hex}" + network_edge_security_service_name = "test-network-edge-security-svc-${random_id.suffix.hex}" } diff --git a/examples/network-edge-security-policy/README.md b/examples/network-edge-security-policy/README.md new file mode 100644 index 0000000..e26b1d8 --- /dev/null +++ b/examples/network-edge-security-policy/README.md @@ -0,0 +1,33 @@ +# Enable Cloud Armor Network Edge Security Policy + +This example creates network edge security policy with policy rules. Feature is only availalable to projects enrolled in [Cloud Armor Enterprise](https://cloud.google.com/armor/docs/armor-enterprise-overview) with [Advanced network DDoS protection](https://cloud.google.com/armor/docs/advanced-network-ddos#activate-advanced-ddos-protection) enabled. You can use [example](../advanced-network-ddos-protection/) to deploy advanced newtork ddos protection. + +## Usage + +To run this example you need to execute: + +```bash +export TF_VAR_project_id="your_project_id" +``` + +```bash +terraform init +terraform plan +terraform apply +``` + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| project\_id | The project in which the resource belongs | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| policy\_rules | Security policy rules created | +| security\_policy | Regional Network Security policy created | + + diff --git a/examples/network-edge-security-policy/main.tf b/examples/network-edge-security-policy/main.tf new file mode 100644 index 0000000..ba70fb5 --- /dev/null +++ b/examples/network-edge-security-policy/main.tf @@ -0,0 +1,84 @@ +/** + * 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. + */ + +resource "random_id" "suffix" { + byte_length = 4 +} + +module "network_edge_security_policy" { + source = "GoogleCloudPlatform/cloud-armor/google//modules/network-edge-security-policy" + version = "~> 2.0" + + project_id = var.project_id + region = "us-central1" + policy_name = "test-nw-edge-security-policy-${random_id.suffix.hex}" + + policy_user_defined_fields = [ + { + name = "SIG1_AT_0" + base = "UDP" + offset = 8 + size = 2 + mask = "0x8F00" + }, + { + name = "SIG2_AT_8" + base = "TCP" + offset = 16 + size = 4 + mask = "0xFFFFFFFF" + }, + { + name = "IPv4-TTL" + base = "IPV4" + offset = 8 + size = 1 + mask = "0xFF" + }, + + ] + + policy_rules = [ + { + priority = 100 + action = "deny" + preview = true + description = "custom rule 100" + src_ip_ranges = ["10.10.0.0/16"] + src_asns = [15169] + src_region_codes = ["AU"] + ip_protocols = ["TCP"] + src_ports = [80] + dest_ports = ["8080"] + dest_ip_ranges = ["10.100.0.0/16"] + user_defined_fields = [ + { + name = "SIG1_AT_0" + values = ["0x8F00"] + }, + ] + }, + { + priority = 200 + action = "deny" + preview = false + priority = 200 + src_asns = [15269] + dest_ports = ["80"] + dest_ip_ranges = ["10.100.0.0/16"] + }, + ] +} diff --git a/examples/network-edge-security-policy/outputs.tf b/examples/network-edge-security-policy/outputs.tf new file mode 100644 index 0000000..7e6b1b4 --- /dev/null +++ b/examples/network-edge-security-policy/outputs.tf @@ -0,0 +1,25 @@ +/** + * 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. + */ + +output "security_policy" { + value = module.network_edge_security_policy.security_policy + description = "Regional Network Security policy created" +} + +output "policy_rules" { + value = module.network_edge_security_policy.policy_rules + description = "Security policy rules created" +} diff --git a/examples/network-edge-security-policy/variables.tf b/examples/network-edge-security-policy/variables.tf new file mode 100644 index 0000000..e11d5d8 --- /dev/null +++ b/examples/network-edge-security-policy/variables.tf @@ -0,0 +1,20 @@ +/** + * 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. + */ + +variable "project_id" { + description = "The project in which the resource belongs" + type = string +} diff --git a/modules/advanced-network-ddos-protection/README.md b/modules/advanced-network-ddos-protection/README.md index 9b3bd3b..e4ff87a 100644 --- a/modules/advanced-network-ddos-protection/README.md +++ b/modules/advanced-network-ddos-protection/README.md @@ -1,4 +1,4 @@ -# Cloud Armor Terraform Module +# Enable Cloud Armor Advanced Network DDoS Protection This module enables [advanced network DDoS protection](https://cloud.google.com/armor/docs/armor-enterprise-overview#advanced_network_ddos_protection) in specified region(s). Advanced network DDoS protection is only availalable to projects enrolled in [Cloud Armor Enterprise](https://cloud.google.com/armor/docs/armor-enterprise-overview). Advanced network DDoS protection feature protects workloads using [external passthrough Network Load Balancers](https://cloud.google.com/load-balancing/docs/network), [protocol forwarding](https://cloud.google.com/load-balancing/docs/protocol-forwarding), or VMs with public IP addresses. When enabled for a particular region, Google Cloud Armor provides always-on targeted volumetric attack detection and mitigation for external passthrough Network Load Balancer, protocol forwarding, and VMs with public IP addresses in that region. This module creates security policy of type `CLOUD_ARMOR_NETWORK` and a a network edge security service in the specified region(s). ## Compatibility @@ -45,46 +45,3 @@ module "advanced_network_ddos_protection" { | network\_edge\_security\_services | Network edge security services created | - -## Requirements - -These sections describe requirements for using this module. - -### Software - -The following dependencies must be available: - -- [Terraform][terraform] v1.3+ -- [Terraform Provider for GCP][terraform-provider-gcp] plugin v4.80+ - -### Service Account - -A service account with the following permission must be used to provision -the resources of this module: - -- compute.networkEdgeSecurityServices.create -- compute.networkEdgeSecurityServices.update -- compute.networkEdgeSecurityServices.get -- compute.networkEdgeSecurityServices.delete -- compute.networkEdgeSecurityServices.list -- compute.regionSecurityPolicies.create -- compute.regionSecurityPolicies.delete -- compute.regionSecurityPolicies.get -- compute.regionSecurityPolicies.list -- compute.regionSecurityPolicies.use -- compute.regionSecurityPolicies.update - -Following roles contain above mentioned permissions. You can either assing one of the following role or create custom roles with above permissions. - -- Compute Security Admin: `roles/compute.securityAdmin` -- Compute Admin: `roles/compute.admin` - -### Enable API's -In order to operate with the Service Account you must activate the following API on the project where the Service Account was created: - -- Compute Engine API - compute.googleapis.com - -## Contributing - -Refer to the [contribution guidelines](./CONTRIBUTING.md) for -information on contributing to this module. diff --git a/modules/advanced-network-ddos-protection/main.tf b/modules/advanced-network-ddos-protection/main.tf index ec74329..822baae 100644 --- a/modules/advanced-network-ddos-protection/main.tf +++ b/modules/advanced-network-ddos-protection/main.tf @@ -14,8 +14,6 @@ * limitations under the License. */ -### Adding custom rules to network security policies requires advanced network DDoS protection to be enabled in the region. Advanced protection can be enabled in preview mode. - resource "google_compute_region_security_policy" "adv_ddos_protection" { provider = google-beta for_each = toset(var.regions) diff --git a/modules/network-edge-security-policy/README.md b/modules/network-edge-security-policy/README.md new file mode 100644 index 0000000..7cdf95f --- /dev/null +++ b/modules/network-edge-security-policy/README.md @@ -0,0 +1,194 @@ +# Cloud Armor Terraform Module +This module creates [network edge security policy](https://cloud.google.com/armor/docs/network-edge-policies) in specified region. Network edge security policy is only availalable to projects enrolled in [Cloud Armor Enterprise](https://cloud.google.com/armor/docs/armor-enterprise-overview) with [Advanced network DDoS protection](https://cloud.google.com/armor/docs/advanced-network-ddos#activate-advanced-ddos-protection) enabled. You can use [this](../advanced-network-ddos-protection/) sub-module to deploy `advanced network ddos protection `. + +You can attch network edge security policy to [external passthrough Network Load Balancers](https://cloud.google.com/load-balancing/docs/network), [protocol forwarding](https://cloud.google.com/load-balancing/docs/protocol-forwarding), or VMs with public IP addresses. Network edge security policy supports [byte offset filtering](https://cloud.google.com/armor/docs/network-edge-policies#byte-offset). This module creates security policy of type `CLOUD_ARMOR_NETWORK` optionally attach security policy rules to the policy. + +## Module Format + +``` +module "network_edge_security_policy" { + source = "GoogleCloudPlatform/cloud-armor/google//modules/advanced-network-ddos-protection" + version = "~> 2.0" + + project_id = var.project_id + region = "us-central1" + policy_name = "test-nw-edge-security-policy-${random_id.suffix.hex}" + + policy_user_defined_fields = [ + {}, + {}, + ] + + policy_rules = [ + {}, + {}, + ] +} +``` + +`policy_rules` details and Sample Code for each type of rule is available [here](#Rules) + +## Usage +There are examples included in the [examples](https://github.com/GoogleCloudPlatform/terraform-google-cloud-armor/tree/main/examples) folder but simple usage is as follows: + + +``` +module "network_edge_security_policy" { + source = "GoogleCloudPlatform/cloud-armor/google//modules/advanced-network-ddos-protection" + version = "~> 2.0" + + project_id = var.project_id + region = "us-central1" + policy_name = "test-nw-edge-security-policy-${random_id.suffix.hex}" + + policy_user_defined_fields = [ + { + name = "SIG1_AT_0" + base = "UDP" + offset = 8 + size = 2 + mask = "0x8F00" + }, + { + name = "SIG2_AT_8" + base = "TCP" + offset = 16 + size = 4 + mask = "0xFFFFFFFF" + }, + ] + + policy_rules = [ + { + priority = 100 + action = "deny" + preview = true + description = "custom rule 100" + src_ip_ranges = ["10.10.0.0/16"] + src_asns = [15169] + src_region_codes = ["AU"] + ip_protocols = ["TCP"] + src_ports = [80] + dest_ports = ["8080"] + dest_ip_ranges = ["10.100.0.0/16"] + user_defined_fields = [ + { + name = "SIG1_AT_0" + values = ["0x8F00"] + }, + ] + }, + { + priority = 200 + action = "deny" + preview = false + priority = 200 + src_asns = [15269] + dest_ports = ["80"] + dest_ip_ranges = ["10.100.0.0/16"] + }, + ] + +} +``` + + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| policy\_description | An optional description of advanced network ddos protection security policy | `string` | `"CA Advance DDoS protection"` | no | +| policy\_name | Name of the advanced network ddos protection security policy. Name must be 1-63 characters long and match the regular expression a-z? which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash | `string` | `"adv-network-ddos-protection"` | no | +| policy\_rules | Policy Rules |
list(object({
priority = number
action = string
preview = optional(bool)
description = optional(string)
src_ip_ranges = optional(list(string))
src_asns = optional(list(string))
src_region_codes = optional(list(string))
ip_protocols = optional(list(string))
src_ports = optional(list(string))
dest_ports = optional(list(string))
dest_ip_ranges = optional(list(string))

user_defined_fields = optional(list(object({
name = optional(string)
values = optional(list(string))
})))
}))
| `null` | no | +| policy\_user\_defined\_fields | Definitions of user-defined fields for CLOUD\_ARMOR\_NETWORK policies. A user-defined field consists of up to 4 bytes extracted from a fixed offset in the packet, relative to the IPv4, IPv6, TCP, or UDP header, with an optional mask to select certain bits |
list(object({
name = optional(string)
base = string
offset = optional(number)
size = optional(number)
mask = optional(string)
}))
| `null` | no | +| project\_id | The project in which the resource belongs. | `string` | n/a | yes | +| region | The region in which enablesecurity policy is created | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| policy\_rules | Security policy rules created | +| security\_policy | Regional network Security policy created | + + + +## Rules + +`policy_rules` is a list of objects with following parameters: +- `priority`: An integer indicating the priority of a rule in the list. The priority must be a positive value between 0 and 2147483647. Rules are evaluated from highest to lowest priority where 0 is the highest priority and 2147483647 is the lowest priority. +- `action`: The Action to perform when the rule is matched. The following are the valid actions: + - allow: allow access to target. + - deny(STATUS): deny access to target, returns the HTTP response code specified. Valid values for STATUS are 403, 404, and 502. +- `preview`: If set to true, the specified action is not enforced +- `description`: An optional description of this resource. Provide this property when you create the resource +- `src_ip_ranges`: list of source IPv4/IPv6 addresses or CIDR prefixes, in standard text format +- `src_asns`: list of BGP Autonomous System Number associated with the source IP address +- `src_region_codes`: list of Two-letter ISO 3166-1 alpha-2 country code associated with the source IP address +- `ip_protocols`: list of IPv4 protocol / IPv6 next header (after extension headers). Each element can be an 8-bit unsigned decimal number (e.g. "6"), range (e.g. "253-254"), or one of the following protocol names: "tcp", "udp", "icmp", "esp", "ah", "ipip", or "sctp" +- `src_ports`: Source port numbers for TCP/UDP/SCTP. Each element can be a 16-bit unsigned decimal number (e.g. "80") or range (e.g. "0-1023") +- `dest_ports`: Destination port numbers for TCP/UDP/SCTP. Each element can be a 16-bit unsigned decimal number (e.g. "80") or range (e.g. "0-1023") +- `dest_ip_ranges`: Destination IPv4/IPv6 addresses or CIDR prefixes, in standard text format +- `user_defined_fields`:User-defined fields. Each element names a defined field and lists the matching values for that field. Support following fields: + - `name`: Name of the user-defined field, as given in the definition + - `values`: Matching values of the field. Each element can be a 32-bit unsigned decimal or hexadecimal (starting with "0x") number (e.g. "64") or range (e.g. "0x400-0x7ff") + +### Format: + +``` +[ + { + priority = 100 + action = "deny" + preview = true + description = "custom rule 100" + src_ip_ranges = ["10.10.0.0/16"] + src_asns = [15169] + src_region_codes = ["AU"] + ip_protocols = ["TCP"] + src_ports = [80] + dest_ports = ["8080"] + dest_ip_ranges = ["10.100.0.0/16"] + user_defined_fields = [ + {}, + ] + }, +] +``` + + +### Sample: + +``` + policy_rules = [ + { + priority = 100 + action = "deny" + preview = true + description = "custom rule 100" + src_ip_ranges = ["10.10.0.0/16"] + src_asns = [15169] + src_region_codes = ["AU"] + ip_protocols = ["TCP"] + src_ports = [80] + dest_ports = ["8080"] + dest_ip_ranges = ["10.100.0.0/16"] + user_defined_fields = [ + { + name = "SIG1_AT_0" + values = ["0x8F00"] + }, + ] + }, + { + priority = 200 + action = "deny" + preview = false + priority = 200 + src_asns = [15269] + dest_ports = ["80"] + dest_ip_ranges = ["10.100.0.0/16"] + }, + ] +``` \ No newline at end of file diff --git a/modules/network-edge-security-policy/main.tf b/modules/network-edge-security-policy/main.tf new file mode 100644 index 0000000..d771da2 --- /dev/null +++ b/modules/network-edge-security-policy/main.tf @@ -0,0 +1,67 @@ +/** + * 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. + */ + +### Adding custom rules to network dge security policies requires advanced network DDoS protection to be enabled in the region. + +resource "google_compute_region_security_policy" "security_policy" { + provider = google-beta + project = var.project_id + + + name = var.policy_name + description = var.policy_description + type = "CLOUD_ARMOR_NETWORK" + region = var.region + + dynamic "user_defined_fields" { + for_each = var.policy_user_defined_fields == null ? [] : var.policy_user_defined_fields + content { + name = lookup(user_defined_fields.value, "name", null) + base = user_defined_fields.value.base + offset = lookup(user_defined_fields.value, "offset", null) + size = lookup(user_defined_fields.value, "size", null) + mask = lookup(user_defined_fields.value, "mask", null) + } + + } +} + +resource "google_compute_region_security_policy_rule" "policy_rules" { + provider = google-beta + for_each = var.policy_rules == null ? {} : { for x in var.policy_rules : x.priority => x } + project = var.project_id + region = var.region + security_policy = google_compute_region_security_policy.security_policy.name + description = each.value.description + priority = each.value.priority + network_match { + src_ip_ranges = lookup(each.value, "source_ip_ranges", null) + src_asns = lookup(each.value, "src_asns", null) + src_region_codes = lookup(each.value, "src_region_codes", null) + ip_protocols = lookup(each.value, "ip_protocols", null) + dest_ports = lookup(each.value, "dest_ports", null) + dest_ip_ranges = lookup(each.value, "dest_ip_ranges", null) + dynamic "user_defined_fields" { + for_each = lookup(each.value, "user_defined_fields", null) == null ? [] : lookup(each.value, "user_defined_fields") + content { + name = lookup(user_defined_fields.value, "name", null) + values = lookup(user_defined_fields.value, "values", null) + } + } + } + action = each.value.action + preview = each.value.preview +} diff --git a/modules/network-edge-security-policy/outputs.tf b/modules/network-edge-security-policy/outputs.tf new file mode 100644 index 0000000..830a35d --- /dev/null +++ b/modules/network-edge-security-policy/outputs.tf @@ -0,0 +1,25 @@ +/** + * 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. + */ + +output "security_policy" { + value = google_compute_region_security_policy.security_policy + description = "Regional network Security policy created" +} + +output "policy_rules" { + value = google_compute_region_security_policy_rule.policy_rules + description = "Security policy rules created" +} diff --git a/modules/network-edge-security-policy/variables.tf b/modules/network-edge-security-policy/variables.tf new file mode 100644 index 0000000..c89408e --- /dev/null +++ b/modules/network-edge-security-policy/variables.tf @@ -0,0 +1,73 @@ +/** + * 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. + */ + +variable "project_id" { + description = "The project in which the resource belongs." + type = string +} + +variable "region" { + description = "The region in which enablesecurity policy is created" + type = string +} + + +variable "policy_name" { + description = "Name of the advanced network ddos protection security policy. Name must be 1-63 characters long and match the regular expression a-z? which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash" + type = string + default = "adv-network-ddos-protection" +} + +variable "policy_description" { + description = "An optional description of advanced network ddos protection security policy" + type = string + default = "CA Advance DDoS protection" +} + +variable "policy_user_defined_fields" { + description = "Definitions of user-defined fields for CLOUD_ARMOR_NETWORK policies. A user-defined field consists of up to 4 bytes extracted from a fixed offset in the packet, relative to the IPv4, IPv6, TCP, or UDP header, with an optional mask to select certain bits" + type = list(object({ + name = optional(string) + base = string + offset = optional(number) + size = optional(number) + mask = optional(string) + })) + default = null +} + +variable "policy_rules" { + description = "Policy Rules" + type = list(object({ + priority = number + action = string + preview = optional(bool) + description = optional(string) + src_ip_ranges = optional(list(string)) + src_asns = optional(list(string)) + src_region_codes = optional(list(string)) + ip_protocols = optional(list(string)) + src_ports = optional(list(string)) + dest_ports = optional(list(string)) + dest_ip_ranges = optional(list(string)) + + user_defined_fields = optional(list(object({ + name = optional(string) + values = optional(list(string)) + }))) + })) + default = null +} diff --git a/modules/network-edge-security-policy/versions.tf b/modules/network-edge-security-policy/versions.tf new file mode 100644 index 0000000..2d32775 --- /dev/null +++ b/modules/network-edge-security-policy/versions.tf @@ -0,0 +1,35 @@ +/** + * 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. + */ + +terraform { + required_version = ">= 1.3.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 4.80, < 6" + } + google-beta = { + source = "hashicorp/google-beta" + version = ">= 4.80, < 6" + } + } + provider_meta "google" { + module_name = "blueprints/terraform/terraform-google-cloud-armor:advanced-network-ddos-protection/v2.1.0" + } + provider_meta "google-beta" { + module_name = "blueprints/terraform/terraform-google-cloud-armor:advanced-network-ddos-protection/v2.1.0" + } +}