terraform/main.tf (330 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" {
alias = "impersonation"
scopes = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email",
]
}
data "google_service_account_access_token" "default" {
provider = google.impersonation
target_service_account = var.terraform_service_account
scopes = [
"userinfo-email",
"cloud-platform"]
lifetime = "1200s"
}
provider "google" {
project = var.project
region = var.compute_region
access_token = data.google_service_account_access_token.default.access_token
request_timeout = "60s"
}
provider "google-beta" {
project = var.project
region = var.compute_region
access_token = data.google_service_account_access_token.default.access_token
request_timeout = "60s"
}
data "google_project" "project" {}
locals {
cloud_scheduler_sa = "service-${data.google_project.project.number}@gcp-sa-cloudscheduler.iam.gserviceaccount.com"
common_labels = {
"app" = var.application_name
"provisioned_by" = "terraform"
}
common_cloud_run_variables = [
{
name = "PROJECT_ID",
value = var.project,
},
{
name = "COMPUTE_REGION_ID",
value = var.compute_region,
},
{
name = "DATA_REGION_ID",
value = var.data_region,
},
{
name = "GCS_FLAGS_BUCKET",
value = module.gcs.create_gcs_flags_bucket_name
},
{
name = "GCS_BACKUP_POLICIES_BUCKET",
value = module.gcs.create_gcs_backup_policies_bucket_name
},
{
name = "APPLICATION_NAME",
value = var.application_name
}
]
fallback_policy_default_level_backup_op_project = lookup(lookup(var.fallback_policy, "default_policy") , "backup_operation_project", null)
fallback_policy_folder_level_backup_op_projects = [for k, v in lookup(var.fallback_policy, "folder_overrides"): lookup(v,"backup_operation_project", null)]
fallback_policy_project_level_backup_op_projects = [for k, v in lookup(var.fallback_policy, "project_overrides"): lookup(v,"backup_operation_project", null)]
fallback_policy_dataset_level_backup_op_projects = [for k, v in lookup(var.fallback_policy, "dataset_overrides"): lookup(v,"backup_operation_project", null)]
fallback_policy_table_level_backup_op_projects = [for k, v in lookup(var.fallback_policy, "table_overrides"): lookup(v,"backup_operation_project", null)]
fallback_policy_backup_op_projects = distinct(concat(
[local.fallback_policy_default_level_backup_op_project],
local.fallback_policy_folder_level_backup_op_projects,
local.fallback_policy_project_level_backup_op_projects,
local.fallback_policy_dataset_level_backup_op_projects,
local.fallback_policy_table_level_backup_op_projects
))
all_backup_op_projects = [for e in distinct(concat(var.additional_backup_operation_projects, local.fallback_policy_backup_op_projects)): e if e != null]
}
module "iam" {
source = "./modules/iam"
project = var.project
sa_dispatcher = var.sa_dispatcher
sa_dispatcher_tasks = var.sa_dispatcher_tasks
sa_snapshoter_bq = var.sa_snapshoter_bq
sa_snapshoter_bq_tasks = var.sa_snapshoter_bq_tasks
sa_snapshoter_gcs = var.sa_snapshoter_gcs
sa_snapshoter_gcs_tasks = var.sa_snapshoter_gcs_tasks
sa_tagger = var.sa_tagger
sa_tagger_tasks = var.sa_tagger_tasks
sa_configurator = var.sa_configurator
sa_configurator_tasks = var.sa_configurator_tasks
}
module "gcs" {
source = "./modules/gcs"
gcs_flags_bucket_name = "${var.project}-${var.gcs_flags_bucket_name}"
project = var.project
# because it's used by the cloud run services
# both dispatchers should be admins. Add the inspection-dispatcher-sa only if it's being deployed
gcs_flags_bucket_admins = [
"serviceAccount:${module.iam.sa_dispatcher_email}",
"serviceAccount:${module.iam.sa_configurator_email}",
"serviceAccount:${module.iam.sa_snapshoter_bq_email}",
"serviceAccount:${module.iam.sa_snapshoter_gcs_email}",
"serviceAccount:${module.iam.sa_tagger_email}",
]
common_labels = local.common_labels
gcs_backup_policies_bucket_admins = [
"serviceAccount:${module.iam.sa_configurator_email}",
"serviceAccount:${module.iam.sa_tagger_email}",
]
gcs_backup_policies_bucket_name = "${var.project}-${var.gcs_backup_policies_bucket_name}"
compute_region = var.compute_region
data_region = var.data_region
}
module "bigquery" {
source = "./modules/bigquery"
project = var.project
region = var.data_region
dataset = var.bigquery_dataset_name
logging_sink_sa = module.cloud_logging.service_account
common_labels = local.common_labels
gcs_backup_policies_bucket_name = module.gcs.create_gcs_backup_policies_bucket_name
}
module "cloud_logging" {
source = "./modules/cloud-logging"
dataset = module.bigquery.results_dataset
project = var.project
log_sink_name = var.log_sink_name
application_name = var.application_name
}
### Cloud Run Services
module "cloud-run-dispatcher" {
source = "./modules/cloud-run"
project = var.project
region = var.compute_region
service_image = var.dispatcher_service_image
service_name = var.dispatcher_service_name
service_account_email = module.iam.sa_dispatcher_email
invoker_service_account_email = module.iam.sa_dispatcher_tasks_email
# Dispatcher could take time to list large number of tables
timeout_seconds = var.dispatcher_service_timeout_seconds
# We don't need high conc for the entry point
max_containers = 1
# We need more than 1 CPU to help accelerate processing of large BigQuery Scan scope
max_cpu = 2
# Use the common variables.tf in addition to specific variables.tf for this service
environment_variables = concat(local.common_cloud_run_variables, [
{
name = "OUTPUT_TOPIC",
value = module.pubsub-configurator.topic-name,
},
]
)
common_labels = local.common_labels
vpc_access_connector = module.vpc_connector.id
}
module "cloud-run-configurator" {
source = "./modules/cloud-run"
project = var.project
region = var.compute_region
service_image = var.configurator_service_image
service_name = var.configurator_service_name
service_account_email = module.iam.sa_configurator_email
invoker_service_account_email = module.iam.sa_configurator_tasks_email
timeout_seconds = var.configurator_service_timeout_seconds
max_cpu = 2
# Use the common variables.tf in addition to specific variables.tf for this service
environment_variables = concat(local.common_cloud_run_variables, [
{
name = "SNAPSHOTER_BQ_OUTPUT_TOPIC",
value = module.pubsub-snapshoter-bq.topic-name,
},
{
name = "SNAPSHOTER_GCS_OUTPUT_TOPIC",
value = module.pubsub-snapshoter-gcs.topic-name,
},
{
name = "BACKUP_POLICY_JSON",
value = jsonencode(var.fallback_policy)
},
{
name = "BACKUP_TAG_TEMPLATE_ID",
value = module.data-catalog.tag_template_id
}
]
)
common_labels = local.common_labels
vpc_access_connector = module.vpc_connector.id
}
module "cloud-run-snapshoter-bq" {
source = "./modules/cloud-run"
project = var.project
region = var.compute_region
service_image = var.snapshoter_bq_service_image
service_name = var.snapshoter_bq_service_name
service_account_email = module.iam.sa_snapshoter_bq_email
invoker_service_account_email = module.iam.sa_snapshoter_bq_tasks_email
timeout_seconds = var.snapshoter_bq_service_timeout_seconds
max_cpu = 2
# Use the common variables.tf in addition to specific variables.tf for this service
environment_variables = concat(local.common_cloud_run_variables, [
{
name = "OUTPUT_TOPIC",
value = module.pubsub-tagger.topic-name,
}
]
)
common_labels = local.common_labels
vpc_access_connector = module.vpc_connector.id
}
module "cloud-run-snapshoter-gcs" {
source = "./modules/cloud-run"
project = var.project
region = var.compute_region
service_image = var.snapshoter_gcs_service_image
service_name = var.snapshoter_gcs_service_name
service_account_email = module.iam.sa_snapshoter_gcs_email
invoker_service_account_email = module.iam.sa_snapshoter_gcs_tasks_email
timeout_seconds = var.snapshoter_gcs_service_timeout_seconds
max_cpu = 2
# Use the common variables.tf in addition to specific variables.tf for this service
environment_variables = concat(local.common_cloud_run_variables, [
{
name = "OUTPUT_TOPIC",
value = module.pubsub-tagger.topic-name,
}
]
)
common_labels = local.common_labels
vpc_access_connector = module.vpc_connector.id
}
module "cloud-run-tagger" {
source = "./modules/cloud-run"
project = var.project
region = var.compute_region
service_image = var.tagger_service_image
service_name = var.tagger_service_name
service_account_email = module.iam.sa_tagger_email
invoker_service_account_email = module.iam.sa_tagger_tasks_email
timeout_seconds = var.tagger_service_timeout_seconds
# Use the common variables.tf in addition to specific variables.tf for this service
environment_variables = concat(local.common_cloud_run_variables, [
{
name = "TAG_TEMPLATE_ID",
value = module.data-catalog.tag_template_id,
},
]
)
common_labels = local.common_labels
vpc_access_connector = module.vpc_connector.id
}
# PubSub Resources
module "pubsub-dispatcher" {
source = "./modules/pubsub"
project = var.project
subscription_endpoint = module.cloud-run-dispatcher.service_endpoint
subscription_name = var.dispatcher_pubsub_sub
subscription_service_account = module.iam.sa_dispatcher_tasks_email
topic = var.dispatcher_pubsub_topic
topic_publishers_sa_emails = [local.cloud_scheduler_sa]
# use a deadline large enough to process BQ listing for large scopes
subscription_ack_deadline_seconds = var.dispatcher_subscription_ack_deadline_seconds
# avoid resending dispatcher messages if things went wrong and the msg was NAK (e.g. timeout expired, app error, etc)
# min value must be at equal to the ack_deadline_seconds
subscription_message_retention_duration = var.dispatcher_subscription_message_retention_duration
common_labels = local.common_labels
}
module "pubsub-configurator" {
source = "./modules/pubsub"
project = var.project
subscription_endpoint = module.cloud-run-configurator.service_endpoint
subscription_name = var.configurator_pubsub_sub
subscription_service_account = module.iam.sa_configurator_tasks_email
topic = var.configurator_pubsub_topic
topic_publishers_sa_emails = [
module.iam.sa_dispatcher_email]
subscription_ack_deadline_seconds = var.configurator_subscription_ack_deadline_seconds
# How long to retain unacknowledged messages in the subscription's backlog, from the moment a message is published.
# In case of unexpected problems we want to avoid a buildup that re-trigger functions
subscription_message_retention_duration = var.configurator_subscription_message_retention_duration
common_labels = local.common_labels
}
module "pubsub-snapshoter-bq" {
source = "./modules/pubsub"
project = var.project
subscription_endpoint = module.cloud-run-snapshoter-bq.service_endpoint
subscription_name = var.snapshoter_bq_pubsub_sub
subscription_service_account = module.iam.sa_snapshoter_bq_tasks_email
topic = var.snapshoter_bq_pubsub_topic
topic_publishers_sa_emails = [
module.iam.sa_configurator_email]
subscription_ack_deadline_seconds = var.snapshoter_bq_subscription_ack_deadline_seconds
# How long to retain unacknowledged messages in the subscription's backlog, from the moment a message is published.
# In case of unexpected problems we want to avoid a buildup that re-trigger functions
subscription_message_retention_duration = var.snapshoter_bq_subscription_message_retention_duration
common_labels = local.common_labels
}
module "pubsub-snapshoter-gcs" {
source = "./modules/pubsub"
project = var.project
subscription_endpoint = module.cloud-run-snapshoter-gcs.service_endpoint
subscription_name = var.snapshoter_gcs_pubsub_sub
subscription_service_account = module.iam.sa_snapshoter_gcs_tasks_email
topic = var.snapshoter_gcs_pubsub_topic
topic_publishers_sa_emails = [
module.iam.sa_configurator_email]
subscription_ack_deadline_seconds = var.snapshoter_gcs_subscription_ack_deadline_seconds
# How long to retain unacknowledged messages in the subscription's backlog, from the moment a message is published.
# In case of unexpected problems we want to avoid a buildup that re-trigger functions
subscription_message_retention_duration = var.snapshoter_gcs_subscription_message_retention_duration
common_labels = local.common_labels
}
module "pubsub-tagger" {
source = "./modules/pubsub"
project = var.project
subscription_endpoint = module.cloud-run-tagger.service_endpoint
subscription_name = var.tagger_pubsub_sub
subscription_service_account = module.iam.sa_tagger_tasks_email
topic = var.tagger_pubsub_topic
topic_publishers_sa_emails = [
module.iam.sa_snapshoter_bq_email,
module.iam.sa_snapshoter_gcs_email]
# Tagger is using BigQuery queries in BATCH mode to avoid INTERACTIVE query concurency limits and they might take longer time to execute under heavy load
# 10m is max allowed
subscription_ack_deadline_seconds = var.tagger_subscription_ack_deadline_seconds
# How long to retain unacknowledged messages in the subscription's backlog, from the moment a message is published.
# In case of unexpected problems we want to avoid a buildup that re-trigger functions
subscription_message_retention_duration = var.tagger_subscription_message_retention_duration
common_labels = local.common_labels
}
module "cloud-scheduler" {
source = "./modules/cloud-scheduler"
count = length(var.schedulers)
project = var.project
target_uri = module.pubsub-dispatcher.topic-id
scheduler_name = lookup(var.schedulers[count.index], "name")
cron_expression = lookup(var.schedulers[count.index], "cron")
payload = lookup(var.schedulers[count.index], "payload")
}
module "data-catalog" {
source = "./modules/data-catalog"
project = var.project
region = var.data_region
tagTemplateUsers = [module.iam.sa_tagger_email]
}
module "async-gcs-snapshoter" {
count = length(local.all_backup_op_projects)
source = "./modules/async-gcs-snapshoter"
application_name = var.application_name
log_project = local.all_backup_op_projects[count.index]
host_project = var.project
log_sink_name = "bq_backup_manager_gcs_export_pubsub_sink"
pubsub_topic_name = module.pubsub-tagger.topic-name
}
module "firestore" {
source = "./modules/firestore"
project = var.project
region = var.compute_region # store cache data next to the services
}