diff --git a/terraform/main.tf b/terraform/main.tf index 2f366fb46..4a8904a73 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -23,6 +23,17 @@ variable "tavern_container_image" { default = "spellshift/tavern:latest" } +variable "tavern_request_timeout_seconds" { + type = number + description = "How many seconds before a request is dropped, defaults to 3600 (the maximum) to accomodate reverse shells (which are killed when this timeout is reached)" + default = 3600 + + validation { + condition = var.tavern_request_timeout_seconds >= 1 && var.tavern_request_timeout_seconds <= 3600 + error_message = "tavern_request_timeout_seconds must be a value between 1 and 3600 seconds" + } +} + variable "gcp_project" { type = string description = "GCP Project ID for deployment" @@ -36,6 +47,25 @@ variable "gcp_region" { description = "GCP Region for deployment" default = "us-east4" } + +variable "disable_gcp_pubsub" { + type = bool + description = "Disables GCP pubsub setup and instead defaults to inmem pubsub, suitable for use-cases where only one tavern instance will exist and distributed orchestration is unnecessary" + default = false +} + +variable "gcp_pubsub_topic_shell_input" { + type = string + description = "Name of the GCP pubsub topic to create for shell input" + default = "shell_input" +} + +variable "gcp_pubsub_topic_shell_output" { + type = string + description = "Name of the GCP pubsub topic to create for shell output" + default = "shell_output" +} + variable "mysql_user" { type = string description = "Username to set for the configured MySQL instance" @@ -146,6 +176,25 @@ locals { prometheus_container_name = "prometheus-sidecar" } +resource "google_pubsub_topic" "shell_input" { + count = var.disable_gcp_pubsub ? 0 : 1 + name = var.gcp_pubsub_topic_shell_input +} +resource "google_pubsub_subscription" "shell_input-sub" { + count = var.disable_gcp_pubsub ? 0 : 1 + name = format("%s-sub", var.gcp_pubsub_topic_shell_input) + topic = google_pubsub_topic.shell_input[0].id +} +resource "google_pubsub_topic" "shell_output" { + count = var.disable_gcp_pubsub ? 0 : 1 + name = var.gcp_pubsub_topic_shell_output +} +resource "google_pubsub_subscription" "shell_output-sub" { + count = var.disable_gcp_pubsub ? 0 : 1 + name = format("%s-sub", var.gcp_pubsub_topic_shell_output) + topic = google_pubsub_topic.shell_output[0].id +} + resource "google_cloud_run_service" "tavern" { name = "tavern" location = var.gcp_region @@ -157,9 +206,13 @@ resource "google_cloud_run_service" "tavern" { template { spec { + // Controls request timeout, must be long-lived to enable reverse shell support + timeout_seconds = var.tavern_request_timeout_seconds + containers { name = local.tavern_container_name image = var.tavern_container_image + ports { container_port = 80 } @@ -195,6 +248,33 @@ resource "google_cloud_run_service" "tavern" { name = "OAUTH_DOMAIN" value = format("https://%s", var.oauth_domain) } + + // Only configure GCP pubsub if it is not disabled + dynamic "env" { + for_each = var.disable_gcp_pubsub ? [] : [ + { + name = "PUBSUB_TOPIC_SHELL_INPUT" + value = format("gcppubsub://%s", google_pubsub_topic.shell_input[0].id) + }, + { + name = "PUBSUB_SUBSCRIPTION_SHELL_INPUT" + value = format("gcppubsub://%s", google_pubsub_subscription.shell_input-sub[0].id) + }, + { + name = "PUBSUB_TOPIC_SHELL_OUTPUT" + value = format("gcppubsub://%s", google_pubsub_topic.shell_output[0].id) + }, + { + name = "PUBSUB_SUBSCRIPTION_SHELL_OUTPUT" + value = format("gcppubsub://%s", google_pubsub_subscription.shell_output-sub[0].id) + } + ] + content { + name = env.value.name + value = env.value.value + } + } + env { name = "ENABLE_METRICS" value = var.enable_metrics ? "1" : ""