dialogflow-cx/vpc-sc-demo/deploy/terraform/vpc-network/main.tf (322 lines of code) (raw):
# Copyright 2022 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_providers {
google = {
source = "hashicorp/google"
version = ">= 4.77.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = ">= 4.77.0"
}
archive = {
source = "hashicorp/archive"
version = ">= 2.4.0"
}
time = {
source = "hashicorp/time"
version = ">= 0.9.1"
}
}
required_version = ">= 1.2.0"
}
variable "project_id" {
description = "Project ID"
type = string
}
variable "access_token" {
description = "Access Token"
type = string
sensitive = true
}
variable "webhook_name" {
description = "webhook_name"
type = string
}
variable "region" {
description = "Region"
type = string
}
variable "vpc_subnetwork" {
description = "VPC Subnetwork"
type = string
default = "webhook-subnet"
}
variable "vpc_network" {
description = "VPC Network"
type = string
default = "webhook-net"
}
variable "proxy_server_src" {
description = "proxy_server_src"
type = string
}
variable "reverse_proxy_server_ip" {
description = "reverse_proxy_server_ip"
type = string
default = "10.10.20.2"
}
variable "proxy_permission_storage" {
type = object({})
}
variable "proxy_permission_registry" {
type = object({})
}
variable "proxy_permission_invoke" {
type = object({})
}
variable "bucket" {
type = object({})
}
variable "iam_api" {
type = object({})
}
variable "dialogflow_api" {
type = object({})
}
variable "compute_api" {
type = object({})
}
variable "artifactregistry_api" {
type = object({})
}
variable "pubsub_api" {
type = object({})
}
variable "cloudbuild_api" {
type = object({})
}
variable "bucket_name" {
description = "bucket_name"
type = string
}
resource "google_compute_network" "vpc_network" {
name = var.vpc_network
project = var.project_id
auto_create_subnetworks = false
depends_on = [
var.proxy_permission_storage,
var.proxy_permission_registry,
var.proxy_permission_invoke,
var.compute_api,
]
}
resource "google_compute_router" "nat_router" {
name = "nat-router"
network = google_compute_network.vpc_network.name
region = var.region
}
resource "google_compute_router_nat" "nat_manual" {
name = "nat-config"
router = google_compute_router.nat_router.name
region = google_compute_router.nat_router.region
nat_ip_allocate_option = "AUTO_ONLY"
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
log_config {
enable = true
filter = "ALL"
}
}
resource "google_compute_firewall" "allow_dialogflow" {
name = "allow-dialogflow"
network = google_compute_network.vpc_network.name
direction = "INGRESS"
priority = 1000
allow {
protocol = "tcp"
ports = ["443"]
}
source_ranges = ["35.199.192.0/19"]
target_tags = ["webhook-reverse-proxy-vm"]
}
resource "google_compute_firewall" "allow" {
name = "allow"
network = google_compute_network.vpc_network.name
allow {
protocol = "tcp"
ports = ["443", "3389", "22"]
}
allow {
protocol = "icmp"
}
source_ranges = ["0.0.0.0/0"]
}
resource "google_compute_subnetwork" "reverse_proxy_subnetwork" {
name = var.vpc_subnetwork
ip_cidr_range = "10.10.20.0/28"
project = var.project_id
region = var.region
network = google_compute_network.vpc_network.name
private_ip_google_access = true
}
resource "google_compute_address" "reverse_proxy_address" {
name = "webhook-reverse-proxy-address"
subnetwork = google_compute_subnetwork.reverse_proxy_subnetwork.id
address_type = "INTERNAL"
purpose = "GCE_ENDPOINT"
region = var.region
address = var.reverse_proxy_server_ip
}
data "archive_file" "proxy_server_source" {
type = "zip"
source_dir = var.proxy_server_src
output_path = abspath("./tmp/server.zip")
}
resource "google_storage_bucket_object" "proxy_server_source" {
name = "server.zip"
bucket = var.bucket_name
source = data.archive_file.proxy_server_source.output_path
depends_on = [
var.bucket
]
}
resource "google_pubsub_topic" "reverse_proxy_server_build" {
name = "build"
depends_on = [
var.pubsub_api
]
}
resource "google_artifact_registry_repository" "webhook_registry" {
location = var.region
repository_id = "webhook-registry"
format = "DOCKER"
project = var.project_id
depends_on = [
var.artifactregistry_api
]
}
resource "google_cloudbuild_trigger" "reverse_proxy_server" {
pubsub_config {
topic = google_pubsub_topic.reverse_proxy_server_build.id
}
build {
source {
storage_source {
bucket = var.bucket_name
object = google_storage_bucket_object.proxy_server_source.name
}
}
logs_bucket = "gs://${var.bucket_name}"
step {
name = "gcr.io/cloud-builders/docker"
timeout = "120s"
args = ["build", "--network", "cloudbuild", "--no-cache", "-t", "${var.region}-docker.pkg.dev/${var.project_id}/webhook-registry/webhook-server-image:latest", "."]
}
artifacts {
images = ["${var.region}-docker.pkg.dev/${var.project_id}/webhook-registry/webhook-server-image:latest"]
}
}
depends_on = [
google_artifact_registry_repository.webhook_registry,
var.bucket,
var.cloudbuild_api,
]
provisioner "local-exec" {
interpreter = [
"/bin/bash", "-c"
]
command = "source /root/.bashrc && export CLOUDSDK_AUTH_ACCESS_TOKEN=${var.access_token} && gcloud --project=${var.project_id} pubsub topics publish build --message=build"
}
}
resource "time_sleep" "wait_for_build" {
create_duration = "60s"
depends_on = [
google_cloudbuild_trigger.reverse_proxy_server
]
}
resource "google_project_service_identity" "dfsa" {
provider = google-beta
project = var.project_id
service = "dialogflow.googleapis.com"
depends_on = [
var.iam_api,
var.dialogflow_api,
]
}
resource "google_project_iam_member" "dfsa_sd_viewer" {
project = var.project_id
role = "roles/servicedirectory.viewer"
member = "serviceAccount:${google_project_service_identity.dfsa.email}"
}
resource "google_project_iam_member" "dfsa_sd_pscAuthorizedService" {
project = var.project_id
role = "roles/servicedirectory.pscAuthorizedService"
member = "serviceAccount:${google_project_service_identity.dfsa.email}"
}
resource "google_service_account" "rpcsa_service_account" {
account_id = "rps-sa"
display_name = "Reverse Proxy Server Service Account"
depends_on = [
var.iam_api,
]
}
resource "google_project_iam_member" "rpcsa_artifactregistry" {
project = var.project_id
role = "roles/artifactregistry.reader"
member = "serviceAccount:${google_service_account.rpcsa_service_account.email}"
}
resource "google_project_iam_member" "rpcsa_cfinvoker" {
project = var.project_id
role = "roles/cloudfunctions.invoker"
member = "serviceAccount:${google_service_account.rpcsa_service_account.email}"
}
resource "google_project_iam_member" "rpcsa_storage_admin" {
project = var.project_id
role = "roles/storage.admin"
member = "serviceAccount:${google_service_account.rpcsa_service_account.email}"
}
resource "google_compute_instance" "reverse_proxy_server" {
name = "webhook-server"
project = var.project_id
zone = "${var.region}-a"
machine_type = "n1-standard-1"
tags = ["webhook-reverse-proxy-vm"]
service_account {
scopes = [
"compute-ro",
"logging-write",
"monitoring-write",
"storage-rw",
"trace",
]
email = google_service_account.rpcsa_service_account.email
}
boot_disk {
auto_delete = true
device_name = "instance-1"
mode = "READ_WRITE"
initialize_params {
image = "projects/debian-cloud/global/images/debian-10-buster-v20220719"
size = 10
}
}
network_interface {
network = google_compute_network.vpc_network.name
subnetwork = google_compute_subnetwork.reverse_proxy_subnetwork.name
network_ip = google_compute_address.reverse_proxy_address.address
}
metadata = {
bucket = var.bucket_name
image = "${var.region}-docker.pkg.dev/${var.project_id}/webhook-registry/webhook-server-image:latest"
bot_user = google_project_service_identity.dfsa.email
webhook_trigger_uri = "https://${var.region}-${var.project_id}.cloudfunctions.net/${var.webhook_name}"
}
metadata_startup_script = file("${path.module}/startup_script.sh")
provisioner "local-exec" {
interpreter = [
"/bin/bash", "-c"
]
command = "source /root/.bashrc && /deploy/terraform/vpc-network/wait_until_server_ready.sh --zone=${self.zone} --project_id=${var.project_id} --token=${var.access_token}"
}
depends_on = [
time_sleep.wait_for_build,
var.bucket,
google_project_iam_member.dfsa_sd_viewer,
google_project_iam_member.dfsa_sd_pscAuthorizedService,
google_project_iam_member.rpcsa_artifactregistry,
google_project_iam_member.rpcsa_cfinvoker,
google_project_iam_member.rpcsa_storage_admin,
google_compute_router_nat.nat_manual,
google_compute_firewall.allow_dialogflow,
google_compute_firewall.allow,
]
}