hashicorp / terraform-provider-google

Terraform Provider for Google Cloud Platform
https://registry.terraform.io/providers/hashicorp/google/latest/docs
Mozilla Public License 2.0
2.29k stars 1.72k forks source link

google_compute_instance not respecting shared-VPC granular subnetwork-permissions #9520

Open pritho opened 3 years ago

pritho commented 3 years ago

Community Note

Terraform Version

0.15.5

Affected Resource(s)

Terraform Configuration Files

resource "google_compute_instance" "instance" {
  name     = local.hostname
  machine_type = var.machine_type
  zone         = var.gcp_zone
  boot_disk {
    source = google_compute_disk.rootvol.name
  }
  network_interface {
    subnetwork         = var.subnetwork
    subnetwork_project = var.subnetwork_project
  }
}

Expected Behavior

Instance should be able to be created

Actual Behavior

Error: Error updating network interface: googleapi: Error 403: Required 'compute.networks.use' permission for 'projects/HOST/global/networks/X', forbidden

Steps to Reproduce

  1. Create a shared network X in Project HOST
  2. Attach a project SERVICE
  3. Create a service account CHILD in project SERVICE
  4. Create subnetwork Y in network X in HOST
  5. Share subnetwork Y with user CHILD from project HOST with IAM subnet-policy and role "roles/compute.networkUser"
  6. Create an instance in project SERVICE using service account CHILD in shared subnetwork Y

Important Factoids

When granting the global permission "roles/compute.networkUser" via IAM in project HOST to service account CHILD, the setup works, but this on the other hand gives direct permissions to use all subnetworks.

b/308756106

karolgorc commented 2 weeks ago

Couldn't recreate the issue. None of the permissions are provided in terraform code so i'd suggest checking out if they are pointing to the right projects

The compute.networkUser permission worked

resource "google_project_iam_custom_role" "custom_role_child" {
  role_id = "test"
  title   = "test-child"
  permissions = [
    "compute.instances.create",
    "compute.disks.create",
    "compute.subnetworks.use",
  ]
  project = var.project_child
}

resource "google_project_iam_member" "service_account_role_host" {
  for_each = toset(["roles/compute.networkUser", "roles/viewer"])
  project  = var.project_host
  role     = each.key
  member   = "serviceAccount:${google_service_account.service_account.email}"
}

resource "google_project_iam_member" "service_account_role_child" {
  for_each = toset(["${google_project_iam_custom_role.custom_role_child.id}", "roles/viewer"])
  project  = var.project_child
  role     = each.key
  member   = "serviceAccount:${google_service_account.service_account.email}"
}

And here is a more granular version that also works

resource "google_project_iam_custom_role" "custom_role_host" {
  role_id = "test"
  title   = "test-host"
  permissions = [
    "compute.networks.use",
    "compute.subnetworks.use",
  ]
  project = var.project_host
}

resource "google_project_iam_custom_role" "custom_role_child" {
  role_id = "test"
  title   = "test-child"
  permissions = [
    "compute.instances.create",
    "compute.disks.create",
    "compute.subnetworks.use",
  ]
  project = var.project_child
}

resource "google_project_iam_member" "service_account_role_host" {
  for_each = toset(["${google_project_iam_custom_role.custom_role_host.id}", "roles/viewer"])
  project  = var.project_host
  role     = each.key
  member   = "serviceAccount:${google_service_account.service_account.email}"
}

resource "google_project_iam_member" "service_account_role_child" {
  for_each = toset(["${google_project_iam_custom_role.custom_role_child.id}", "roles/viewer"])
  project  = var.project_child
  role     = each.key
  member   = "serviceAccount:${google_service_account.service_account.email}"
}

@edwardmedia I think this issue can be closed