glux
glux

Reputation: 532

Terraform Shared VPC on GCP - Static Internal IP address

I am attempting to write automation to deploy instances in a shared VPC on GCP. I have a host network project and a service project. I can create a static internal IP address resource in the host project (resource "google_compute_address" "internal") in which I specify the VPC host project (NET_HUB_PROJ) but I am unable to use it when creating the instance. I receive the following error:

google_compute_instance.compute: Error creating instance: googleapi: 
Error 400: Invalid value for field 
'resource.networkInterfaces[0].networkIP': '10.128.0.10'. IP address 
'projects/prototype-network-hub/regions/us-central1/addresses/bh-int- 
ip' (10.128.0.10) is reserved by another project., invalid

My compute module:

data "google_compute_image" "image" {
  name    = "${var.IMAGE_NAME}"
  project = "${var.IMAGE_PROJECT}"
}

resource "google_compute_address" "internal" {
  name         = "${var.NAME}-int-ip"
  address_type = "INTERNAL"
  address      = "${var.PRIVATE_IP}"
  subnetwork   = "${var.NET_HUB_SUBNETWORK}"
  region       = "${var.NET_HUB_REGION}"
  project      = "${var.NET_HUB_PROJ}"
}

resource "google_compute_address" "external" {
  count        = "${var.EXT_IP_CREATE ? 1 : 0}"
  name         = "${var.NAME}-ext-ip"
  address_type = "EXTERNAL"
  region       = "${var.REGION}"
}

resource "google_compute_instance" "compute" {
   depends_on  = ["google_compute_address.external"] 
   name = "${var.NAME}"
   machine_type = "${var.MACHINE_TYPE}"
   zone = "${var.ZONE}"
   can_ip_forward = "${var.CAN_IP_FORWARD}"
   deletion_protection ="${var.DELETION_PROTECTION}"
   allow_stopping_for_update = "${var.ALLOW_STOPPING_FOR_UPDATE}"
   tags = ["allow-ssh"]
   metadata = {
    "network" = "${var.NETWORK}"
    "env" = "${var.ENV}"
    "role" = "${var.ROLE}"
    "region" = "${var.REGION}"
    "zone" = "${var.ZONE}"
   }
   labels = {
    "network" = "${var.NETWORK}"
    "env" = "${var.ENV}"
    "role" = "${var.ROLE}"
    "region" = "${var.REGION}"
    "zone" = "${var.ZONE}"
    }
   boot_disk {
      device_name = "${var.NAME}"
      auto_delete = "${var.BOOT_DISK_AUTO_DELETE}"
      initialize_params {
      size = "${var.BOOT_DISK_SIZE}"
      type = "${var.BOOT_DISK_TYPE}"
      image = "${data.google_compute_image.image.self_link}"
      }
   }

network_interface {
   network_ip = "${google_compute_address.internal.address}"
   subnetwork_project = "${var.NET_HUB_PROJ}"
   subnetwork   = "projects/prototype-network-hub/regions/us-central1/subnetworks/custom"
   access_config {
      nat_ip = "${element(concat(google_compute_address.external.*.address, list("")), 0)}"
   }
}
service_account {
   scopes = ["service-control", "service-management", "logging-write", "monitoring-write", "storage-ro", "https://www.googleapis.com/auth/trace.append" ]
   }
}

The end goal would be to accomplish the following: enter image description here

Upvotes: 3

Views: 5395

Answers (2)

jlim
jlim

Reputation: 1039

Adding my solution below:-


resource "google_compute_address" "internal_ip" {
  count        = 1
  name         = "${local.cluster_name}-int-ip-${count.index}"
  project      = <service project id>
  subnetwork   = <host project subnet self_link>
  address_type = "INTERNAL"
  region       = "asia-northeast1"
  purpose      = "GCE_ENDPOINT"
}

output "internal_ipaddr_info" {
  value = google_compute_address.internal_ip
}


resource "google_compute_instance" "test" {
  project        = module.gcp_service_project.project_id
  name           = "eps-gce-vm-d-swmgr-ane1-test"
  machine_type   = "n1-standard-1"
  zone           = "asia-northeast1-a"
  can_ip_forward = true
  boot_disk {
    initialize_params {
      image = "centos7"
    }
  }

  network_interface {
    subnetwork = <host project subnet self_link>
    network_ip = google_compute_address.internal_ip[0].self_link

  }

}

Upvotes: 1

Colin Garcia
Colin Garcia

Reputation: 51

EDIT (new answer): Per the GCP documentation, the static internal IP must belong to the service project (not the host network project as in your code) if you're looking to reserve internal IP on a shared VPC in a different project. See here: https://cloud.google.com/vpc/docs/provisioning-shared-vpc#reserve_internal_ip

Seeing as a shared-vpc is unlikely to be found in your TF codebase, you'll have to use data to get the self_link of the subnetwork to use for google_compute_address. Something like the following:

data "google_compute_subnetwork" "subnet" {
  name    = "${var.NET_HUB_SUBNETWORK}"
  project = "${var.NET_HUB_PROJ}"
  region  = "${var.NET_HUB_REGION}"
}

resource "google_compute_address" "internal" {
  name         = "${var.NAME}-int-ip"
  address_type = "INTERNAL"
  address      = "${var.PRIVATE_IP}"
  subnetwork   = "${data.google_compute_subnetwork.subnet.self_link}"
}

This should create the resource under your service project, yet with an address within the designated subnet.

When you deploy your instance you should see it referenced under the internal_ip column on your VM instances tab for the assigned instance.

(old answer for posterity): Unfortunately, google_compute_address doesn't contain a subnetwork_project like google_compute_instance. A fix around this is to provide a full URL to the subnetwork field in google_compute_address. Something like the following:

resource "google_compute_address" "internal" {
  name         = "${var.NAME}-int-ip"
  address_type = "INTERNAL"
  address      = "${var.PRIVATE_IP}"
  subnetwork   = "https://www.googleapis.com/compute/v1/projects/${var.NET_HUB_PROJ}/regions/${var.NET_HUB_REGION}/subnetworks/${var.NET_HUB_SUBNETWORK}"
}

Upvotes: 5

Related Questions