Search code examples
google-cloud-platformterraformterraform-provider-gcp

terraform resource block loop


I am working on setting up VPC Service control in GCP using google_access_context_manager_service_perimeter provider. In this resource, within status block, I have to specify a list of google projects as resources value in the format "projects/123456789". I want to put the project numbers in a variable and created something like this.

variable "project_numbers_to_protect" {
  type = list(any)
  default = [
    "123456",
    "456789",
    "894321"
  ]
}

I am able to reference the variable as below.

resources = ["projects/${var.project_numbers_to_protect[0]}",
             "projects/${var.project_numbers_to_protect[1]}",
             "projects/${var.project_numbers_to_protect[2]}"]

But in my production case, I have a large number of projects in the list and I am looking for option to reference it dynamically. I tried count option, but that didn't work.

count = var.project_numbers_to_protect
resources = ["projects/${var.project_numbers_to_protect[count.index]}"]

Error message

vpc-sc-module $ terraform validate
╷
│ Error: Reference to "count" in non-counted context
│
│   on vpc-sc-copy.tf line 16, in resource "google_access_context_manager_service_perimeter" "regular_service_perimeter":
│   16:     resources = ["projects/${var.project_numbers_to_protect[count.index]}"]
│
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.
╵

Appreciate any help. Thanks.

Full Code

vpc-sc-copy.tf

resource "google_access_context_manager_service_perimeter" "regular_service_perimeter" {
  parent                    = "accessPolicies/${var.access_context_manager_policy_number}"
  name                      = "accessPolicies/${var.access_context_manager_policy_number}/servicePerimeters/${var.perimeter_name}"
  perimeter_type            = var.perimeter_type
  title                     = var.perimeter_name
  use_explicit_dry_run_spec = false
  status {
    restricted_services = var.restricted_services
    ## Below two lines works.
    # resources = ["projects/${var.project_numbers_to_protect[0]}",
    #   "projects/${var.project_numbers_to_protect[1]}",]
    ## Below option doesn't work
    count = var.project_numbers_to_protect
    resources = ["projects/${var.project_numbers_to_protect[count.index]}"]
    ingress_policies {
      ingress_from {
        identity_type = "ANY_IDENTITY"

        sources {
          access_level = "*"
        }
      }

      ingress_to {
        resources = [
            "*"
          ]
        dynamic "operations" {
          for_each = var.ingress_rule1_service_name
          content {
            service_name = operations.value
            method_selectors {
              method = "*"
            }
          }
        }


      }
    }
    egress_policies {
      egress_from {
        identities = ["serviceAccount:service-${var.project_number_to_protect}@gcp-sa-aiplatform-cc.iam.gserviceaccount.com"]
      }
      egress_to {
        resources = [
          "projects/${var.egress_rule1_project_number}"
        ]
        operations {
          service_name = "storage.googleapis.com"
          dynamic "method_selectors" {
            for_each = var.egress_rule1_methods
            content {
              method = method_selectors.value
            }
          }
        }
      }
    }
    egress_policies {
      egress_from {
        identity_type = "ANY_IDENTITY"
      }
      egress_to {
        resources = [
          "projects/${var.egress_rule2_project_number}"
        ]
        operations {

          service_name = "storage.googleapis.com"
          dynamic "method_selectors" {
            for_each = var.egress_rule2_methods
            content {
              method = method_selectors.value
            }
          }
        }
      }
    }


  }
}

Relevant section of vars.tf

variable "project_numbers_to_protect" {
  type = list(any)
  default = [
    "123456",
    "456789",
    "894321"
  ]
}

Solution

  • As the error writes, you can't use count the way you want. Instead it should be:

    resource "google_access_context_manager_service_perimeter" "regular_service_perimeter" {
      parent                    = "accessPolicies/${var.access_context_manager_policy_number}"
      name                      = "accessPolicies/${var.access_context_manager_policy_number}/servicePerimeters/${var.perimeter_name}"
      perimeter_type            = var.perimeter_type
      title                     = var.perimeter_name
      use_explicit_dry_run_spec = false
      status {
        restricted_services = var.restricted_services
    
    
    
    
    
        resources = [for project_number in var.project_numbers_to_protect:
                     "projects/${project_number}" ]
    
    
    
    
    
        ingress_policies {
          ingress_from {
            identity_type = "ANY_IDENTITY"
    
            sources {
              access_level = "*"
            }
          }
    
          ingress_to {
            resources = [
                "*"
              ]
            dynamic "operations" {
              for_each = var.ingress_rule1_service_name
              content {
                service_name = operations.value
                method_selectors {
                  method = "*"
                }
              }
            }
    
    
          }
        }
        egress_policies {
          egress_from {
            identities = ["serviceAccount:service-${var.project_number_to_protect}@gcp-sa-aiplatform-cc.iam.gserviceaccount.com"]
          }
          egress_to {
            resources = [
              "projects/${var.egress_rule1_project_number}"
            ]
            operations {
              service_name = "storage.googleapis.com"
              dynamic "method_selectors" {
                for_each = var.egress_rule1_methods
                content {
                  method = method_selectors.value
                }
              }
            }
          }
        }
        egress_policies {
          egress_from {
            identity_type = "ANY_IDENTITY"
          }
          egress_to {
            resources = [
              "projects/${var.egress_rule2_project_number}"
            ]
            operations {
    
              service_name = "storage.googleapis.com"
              dynamic "method_selectors" {
                for_each = var.egress_rule2_methods
                content {
                  method = method_selectors.value
                }
              }
            }
          }
        }
    
    
      }
    }