aa-integration-backend/terraform/main.tf (255 lines of code) (raw):
# 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
#
# https://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.
provider "google-beta" {
project = var.gcp_project_id
region = var.service_region
}
# Enable GCP Services
resource "google_project_service" "gcp_services" {
for_each = toset(var.gcp_services)
project = var.gcp_project_id
service = each.key
# Do not disable serives when the Terraform resource is destroyed.
disable_dependent_services = false
disable_on_destroy = false
}
## ---------------------------------------------------------------------------------------------------------------------
## Create Service Accounts
## ---------------------------------------------------------------------------------------------------------------------
# Create service account for UI Connector service runtime.
resource "google_service_account" "connector_service_account" {
project = var.gcp_project_id
account_id = var.connector_service_account_name
create_ignore_already_exists = true
}
# Add necessary IAM roles for UI Connector service account.
resource "google_project_iam_binding" "connector_service_account" {
project = var.gcp_project_id
for_each = toset(var.connector_service_account_roles)
role = each.key
members = ["serviceAccount:${google_service_account.connector_service_account.email}"]
}
# Create service account for Cloud Pub/Sub Interceptor service runtime.
resource "google_service_account" "interceptor_service_account" {
project = var.gcp_project_id
account_id = var.interceptor_service_account_name
create_ignore_already_exists = true
}
# Add necessary IAM roles for Cloud Pub/Sub Interceptor service account.
resource "google_project_iam_binding" "interceptor_service_account" {
project = var.gcp_project_id
for_each = toset(var.interceptor_service_account_roles)
role = each.key
members = ["serviceAccount:${google_service_account.interceptor_service_account.email}"]
}
## ---------------------------------------------------------------------------------------------------------------------
## Create a JWT Secret Key
## ---------------------------------------------------------------------------------------------------------------------
resource "random_uuid" "jwt_secret_key" {
}
resource "google_secret_manager_secret" "default" {
project = var.gcp_project_id
secret_id = var.jwt_secret_name
replication {
user_managed {
replicas {
location = var.service_region
}
}
}
}
resource "google_secret_manager_secret_version" "default" {
secret = google_secret_manager_secret.default.name
secret_data = random_uuid.jwt_secret_key.result
}
## ---------------------------------------------------------------------------------------------------------------------
## Setup Memorystore for Redis
## ---------------------------------------------------------------------------------------------------------------------
# Create a Redis instance in the same region as your Cloud Run services.
resource "google_redis_instance" "aa_integration_redis_instance" {
project = var.gcp_project_id
name = var.redis_instance_id
memory_size_gb = 5
region = var.service_region
}
# Create a Serverless VPC Access connector with a custom IP range.
# Deprecated. Direct VPC egress is used instead. https://cloud.google.com/run/docs/configuring/vpc-direct-vpc
# resource "google_vpc_access_connector" "aa_integration_vpc" {
# project = var.gcp_project_id
# name = var.vpc_connector_name
# ip_cidr_range = var.redis_ip_range
# network = var.vpc_network
# region = var.service_region
# }
## ---------------------------------------------------------------------------------------------------------------------
## Deploy UI Connector Service
## ---------------------------------------------------------------------------------------------------------------------
resource "google_cloud_run_v2_service" "ui_connector" {
project = var.gcp_project_id
name = var.connector_service_name
location = var.service_region
launch_stage = "BETA"
client = "terraform"
template {
volumes {
name = "my-service-volume"
secret {
secret = google_secret_manager_secret.default.secret_id
items {
version = "latest"
path = "jwt_secret_key"
mode = 0 # use default 0444
}
}
}
containers {
image = var.ui_connector_docker_image
volume_mounts {
name = "my-service-volume"
mount_path = "/secret"
}
env {
name = "REDISHOST"
value = google_redis_instance.aa_integration_redis_instance.host
}
env {
name = "REDISPORT"
value = google_redis_instance.aa_integration_redis_instance.port
}
env {
name = "GCP_PROJECT_ID"
value = var.gcp_project_id
}
env {
name = "AUTH_OPTION"
value = var.auth_option
}
}
service_account = google_service_account.connector_service_account.email
timeout = "3600s"
scaling {
min_instance_count = 1
# Add to prevent violation: "max_instance_count: must be greater or equal than min_instance_count.""
max_instance_count = 100
}
vpc_access {
network_interfaces {
network = "default"
subnetwork = "default"
}
egress = "PRIVATE_RANGES_ONLY"
}
}
}
resource "google_cloud_run_service_iam_binding" "ui_connector_invoker_binding" {
project = var.gcp_project_id
location = google_cloud_run_v2_service.ui_connector.location
service = google_cloud_run_v2_service.ui_connector.name
role = "roles/run.invoker"
members = [
"allUsers"
]
}
## ---------------------------------------------------------------------------------------------------------------------
## Deploy Cloud PubSub Interceptor Service
## ---------------------------------------------------------------------------------------------------------------------
resource "google_cloud_run_v2_service" "cloud_pubsub_interceptor" {
project = var.gcp_project_id
name = var.interceptor_service_name
location = var.service_region
client = "terraform"
launch_stage = "BETA"
ingress = "INGRESS_TRAFFIC_INTERNAL_ONLY"
template {
containers {
image = var.cloud_pubsub_interceptor_docker_image
env {
name = "REDISHOST"
value = google_redis_instance.aa_integration_redis_instance.host
}
env {
name = "REDISPORT"
value = google_redis_instance.aa_integration_redis_instance.port
}
}
service_account = google_service_account.interceptor_service_account.email
scaling {
min_instance_count = 1
# Add to prevent violation: "max_instance_count: must be greater or equal than min_instance_count.""
max_instance_count = 100
}
vpc_access {
network_interfaces {
network = "default"
subnetwork = "default"
}
egress = "ALL_TRAFFIC"
}
}
}
## ---------------------------------------------------------------------------------------------------------------------
## Configure Cloud PubSub Topic Subscriptions
## ---------------------------------------------------------------------------------------------------------------------
# Create a service account to represent the Pub/Sub subscription identity.
resource "google_service_account" "pubsub_service_account" {
project = var.gcp_project_id
account_id = var.cloud_run_pubsub_invoker_name
display_name = "Cloud Run Pub/Sub Invoker"
create_ignore_already_exists = true
}
# Give the service account permission to invoke your interceptor service.
resource "google_cloud_run_service_iam_binding" "pubsub_invoker_binding" {
project = var.gcp_project_id
location = google_cloud_run_v2_service.cloud_pubsub_interceptor.location
service = google_cloud_run_v2_service.cloud_pubsub_interceptor.name
role = "roles/run.invoker"
members = ["serviceAccount:${google_service_account.pubsub_service_account.email}"]
}
# Create a subscription for the Pub/Sub topic you configured for new suggestions.
resource "google_pubsub_topic" "suggestion_topic" {
project = var.gcp_project_id
name = var.agent_assist_notifications_topic_id
}
resource "google_pubsub_subscription" "suggestion_subscription" {
project = var.gcp_project_id
name = var.agent_assist_notifications_subscription_id
topic = google_pubsub_topic.suggestion_topic.name
push_config {
push_endpoint = "${google_cloud_run_v2_service.cloud_pubsub_interceptor.uri}/human-agent-assistant-event"
oidc_token {
service_account_email = google_service_account.pubsub_service_account.email
}
attributes = {
x-goog-version = "v1"
}
}
expiration_policy {
ttl = ""
}
depends_on = [google_cloud_run_v2_service.cloud_pubsub_interceptor]
}
# Create a subscription for the Pub/Sub topic you configured for new message events.
resource "google_pubsub_topic" "new_message_topic" {
project = var.gcp_project_id
name = var.new_message_notifications_topic_id
}
resource "google_pubsub_subscription" "new_message_subscription" {
project = var.gcp_project_id
name = var.new_message_notifications_subscription_id
topic = google_pubsub_topic.new_message_topic.name
push_config {
push_endpoint = "${google_cloud_run_v2_service.cloud_pubsub_interceptor.uri}/new-message-event"
oidc_token {
service_account_email = google_service_account.pubsub_service_account.email
}
attributes = {
x-goog-version = "v1"
}
}
expiration_policy {
ttl = ""
}
depends_on = [google_cloud_run_v2_service.cloud_pubsub_interceptor]
}
# Create a subscription for the Pub/Sub topic you configured for conversation lifecycle events.
resource "google_pubsub_topic" "conversation_lifecycle_topic" {
project = var.gcp_project_id
name = var.conversation_lifecycle_notifications_topic_id
}
resource "google_pubsub_subscription" "conversation_lifecycle_subscription" {
project = var.gcp_project_id
name = var.conversation_lifecycle_notifications_subscription_id
topic = google_pubsub_topic.conversation_lifecycle_topic.name
push_config {
push_endpoint = "${google_cloud_run_v2_service.cloud_pubsub_interceptor.uri}/conversation-lifecycle-event"
oidc_token {
service_account_email = google_service_account.pubsub_service_account.email
}
attributes = {
x-goog-version = "v1"
}
}
expiration_policy {
ttl = ""
}
depends_on = [google_cloud_run_v2_service.cloud_pubsub_interceptor]
}
# Create a subscription for the Pub/Sub topic you configured for new recognition result notification events.
resource "google_pubsub_topic" "new_recognition_result_notification_topic" {
project = var.gcp_project_id
name = var.new_recognition_result_notification_topic_id
}
resource "google_pubsub_subscription" "new_recognition_result_notification_subscription" {
project = var.gcp_project_id
name = var.new_recognition_result_notification_subscription_id
topic = google_pubsub_topic.new_recognition_result_notification_topic.name
push_config {
push_endpoint = "${google_cloud_run_v2_service.cloud_pubsub_interceptor.uri}/new-recognition-result-notification-event"
oidc_token {
service_account_email = google_service_account.pubsub_service_account.email
}
attributes = {
x-goog-version = "v1"
}
}
expiration_policy {
ttl = ""
}
depends_on = [google_cloud_run_v2_service.cloud_pubsub_interceptor]
}