variable "availability_domain_index" { description = "Availability-domain index selected from the compartment." type = number default = 0 } variable "shape" { description = "OCI compute shape for the relay." type = string default = "VM.Standard.A1.Flex" } variable "ocpus" { description = "OCPUs assigned to the flexible relay shape." type = number default = 1 } variable "memory_in_gbs" { description = "Memory assigned to the flexible relay shape." type = number default = 4 } variable "image_builder_ssh_source_cidr" { description = "Current operator IPv4 /32 admitted for Packer image builders." type = string default = null nullable = true validation { condition = ( var.image_builder_ssh_source_cidr == null || (can(cidrhost(var.image_builder_ssh_source_cidr, 0)) && endswith(var.image_builder_ssh_source_cidr, "/32")) ) error_message = "image_builder_ssh_source_cidr must be null or an IPv4 /32." } } variable "budget_amount" { description = "Monthly relay-compartment budget in the tenancy rate-card currency." type = number default = 35 } variable "log_ingest_hostname" { description = "Gateway R hostname used for authenticated relay log ingestion." type = string default = "relay-logs.quorate.dev" validation { condition = can(regex("^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$", var.log_ingest_hostname)) error_message = "log_ingest_hostname must be a lower-case DNS hostname." } } variable "monitoring_source_ipv4" { description = "Exact OCI Health Checks source IPv4 addresses admitted ahead of geographic filtering." type = list(string) default = [ "13.114.80.229", "13.115.206.223", "20.191.152.138", "20.198.221.215", "35.226.104.15", "130.211.189.141", ] validation { condition = ( length(var.monitoring_source_ipv4) >= 3 && length(distinct(var.monitoring_source_ipv4)) == length(var.monitoring_source_ipv4) && alltrue([for address in var.monitoring_source_ipv4 : can(cidrhost("${address}/32", 0))]) ) error_message = "monitoring_source_ipv4 must contain at least three unique IPv4 addresses." } } variable "image_ocid" { description = "Pinned OCI Osaka platform-image OCID for the relay instance." type = string default = "********" } variable "vcn_cidr" { description = "IPv4 CIDR for the relay VCN." type = string default = "10.27.161.96/24" } variable "subnet_cidr" { description = "IPv4 CIDR for the public relay subnet." type = string default = "10.27.161.96/28" } variable "wireguard_listen_port" { description = "Public UDP listen port for the OCI WireGuard peer." type = number default = 51820 validation { condition = var.wireguard_listen_port >= 1024 && var.wireguard_listen_port <= 65535 error_message = "wireguard_listen_port must be between 1024 and 65535." } } variable "relay_tunnel_address" { description = "OCI WireGuard interface address with prefix length." type = string default = "10.40.68.115/30" } variable "relay_metrics_port" { description = "TCP port for relay metrics on the WireGuard interface." type = number default = 19100 validation { condition = var.relay_metrics_port >= 1024 && var.relay_metrics_port <= 65535 error_message = "relay_metrics_port must be between 1024 and 65535." } } variable "relay_conntrack_sample_denominator" { description = "Deterministic one-in-N sampling denominator for completed accepted relay connections." type = number default = 10 validation { condition = var.relay_conntrack_sample_denominator >= 1 && var.relay_conntrack_sample_denominator <= 10000 error_message = "relay_conntrack_sample_denominator must be between 1 and 10000." } } variable "relay_conntrack_emission_rate_per_second" { description = "Maximum sustained completed-connection records emitted per second." type = number default = 1 validation { condition = var.relay_conntrack_emission_rate_per_second >= 1 && var.relay_conntrack_emission_rate_per_second <= 100 error_message = "relay_conntrack_emission_rate_per_second must be between 1 and 100." } } variable "relay_conntrack_emission_burst" { description = "Maximum burst of completed-connection records emitted before rate limiting." type = number default = 10 validation { condition = var.relay_conntrack_emission_burst >= 1 && var.relay_conntrack_emission_burst <= 1000 error_message = "relay_conntrack_emission_burst must be between 1 and 1000." } } variable "relay_conntrack_event_buffer" { description = "In-memory completed-connection event buffer between netlink decoding and bounded emission." type = number default = 4096 validation { condition = var.relay_conntrack_event_buffer >= 1 && var.relay_conntrack_event_buffer <= 65536 error_message = "relay_conntrack_event_buffer must be between 1 and 65536." } } variable "gateway_relay_address" { description = "Gateway R LoadBalancer IPv4 address." type = string default = "10.104.40.127" } variable "mail_relay_enabled" { description = "Configure mail forwarding on the relay guest." type = bool default = true } variable "smtp_ingress_source_cidrs" { description = "IPv4 source CIDRs admitted by the OCI NSG to SMTP TCP/25." type = set(string) default = ["0.0.0.0/0"] validation { condition = alltrue([ for cidr in var.smtp_ingress_source_cidrs : can(cidrhost(cidr, 0)) && can(regex("^[0-9.]+/[0-9]+$", cidr)) ]) error_message = "smtp_ingress_source_cidrs must contain only IPv4 CIDRs." } } variable "submissions_ingress_source_cidrs" { description = "IPv4 source CIDRs admitted by the OCI NSG to submissions TCP/465." type = set(string) default = ["0.0.0.0/0"] validation { condition = alltrue([ for cidr in var.submissions_ingress_source_cidrs : can(cidrhost(cidr, 0)) && can(regex("^[0-9.]+/[0-9]+$", cidr)) ]) error_message = "submissions_ingress_source_cidrs must contain only IPv4 CIDRs." } } variable "imaps_ingress_source_cidrs" { description = "IPv4 source CIDRs admitted by the OCI NSG to IMAPS TCP/993." type = set(string) default = ["0.0.0.0/0"] validation { condition = alltrue([ for cidr in var.imaps_ingress_source_cidrs : can(cidrhost(cidr, 0)) && can(regex("^[0-9.]+/[0-9]+$", cidr)) ]) error_message = "imaps_ingress_source_cidrs must contain only IPv4 CIDRs." } } variable "smtp_health_check_enabled" { description = "Enable the non-submitting OCI TCP/25 health check and admit its source addresses." type = bool default = true } variable "submissions_health_check_enabled" { description = "Enable the non-submitting OCI TCP/465 health check and admit its source addresses." type = bool default = true } variable "imaps_health_check_enabled" { description = "Enable the non-submitting OCI TCP/993 health check and admit its source addresses." type = bool default = true } variable "mail_https_health_check_enabled" { description = "Enable the non-submitting OCI mail HTTPS health check." type = bool default = true } variable "relay_rate_limit_mbit" { description = "Traffic-control ceiling for inner traffic sent toward home." type = number default = 150 } variable "relay_tunnel_mtu" { description = "WireGuard inner MTU shared with the home relay peer." type = number default = 1420 validation { condition = var.relay_tunnel_mtu >= 1280 && var.relay_tunnel_mtu <= 1500 error_message = "relay_tunnel_mtu must be between 1280 and 1500." } } variable "relay_web_syn_rate_per_minute" { description = "Per-source TCP SYN rate on ports 80 and 443 that increments the over-limit counter." type = number default = 120 validation { condition = var.relay_web_syn_rate_per_minute >= 1 error_message = "relay_web_syn_rate_per_minute must be positive." } } variable "relay_web_syn_burst" { description = "Per-source TCP SYN burst accepted before the over-limit counter increments." type = number default = 120 validation { condition = var.relay_web_syn_burst >= 1 error_message = "relay_web_syn_burst must be positive." } } variable "relay_web_syn_aggregate_rate_per_second" { description = "Aggregate public web SYN rate admitted before excess packets are dropped." type = number default = 1000 validation { condition = var.relay_web_syn_aggregate_rate_per_second >= 1 error_message = "relay_web_syn_aggregate_rate_per_second must be positive." } } variable "relay_web_syn_aggregate_burst" { description = "Aggregate public web SYN burst admitted before excess packets are dropped." type = number default = 1000 validation { condition = var.relay_web_syn_aggregate_burst >= 1 error_message = "relay_web_syn_aggregate_burst must be positive." } } variable "relay_web_packet_aggregate_rate_per_second" { description = "Aggregate public web packet rate admitted before conntrack and DNAT." type = number default = 20000 validation { condition = var.relay_web_packet_aggregate_rate_per_second >= 1000 error_message = "relay_web_packet_aggregate_rate_per_second must be at least 1000." } } variable "relay_web_packet_aggregate_burst" { description = "Aggregate public web packet burst admitted before excess packets are dropped." type = number default = 20000 validation { condition = var.relay_web_packet_aggregate_burst >= var.relay_web_packet_aggregate_rate_per_second error_message = "relay_web_packet_aggregate_burst must be at least the per-second packet rate." } } variable "relay_smtp_syn_rate_per_minute" { description = "Per-source TCP/25 SYN rate before a source enters temporary transport quarantine." type = number default = 60 validation { condition = var.relay_smtp_syn_rate_per_minute >= 1 error_message = "relay_smtp_syn_rate_per_minute must be positive." } } variable "relay_smtp_syn_burst" { description = "Per-source TCP/25 SYN burst allowed before transport quarantine." type = number default = 20 validation { condition = var.relay_smtp_syn_burst >= 1 error_message = "relay_smtp_syn_burst must be positive." } } variable "relay_smtp_syn_aggregate_rate_per_second" { description = "Aggregate TCP/25 SYN rate admitted before excess packets are dropped." type = number default = 500 validation { condition = var.relay_smtp_syn_aggregate_rate_per_second >= 1 error_message = "relay_smtp_syn_aggregate_rate_per_second must be positive." } } variable "relay_smtp_syn_aggregate_burst" { description = "Aggregate TCP/25 SYN burst admitted before excess packets are dropped." type = number default = 500 validation { condition = var.relay_smtp_syn_aggregate_burst >= 1 error_message = "relay_smtp_syn_aggregate_burst must be positive." } } variable "relay_smtp_packet_aggregate_rate_per_second" { description = "Aggregate TCP/25 packet rate admitted before conntrack and DNAT." type = number default = 10000 validation { condition = var.relay_smtp_packet_aggregate_rate_per_second >= 1 error_message = "relay_smtp_packet_aggregate_rate_per_second must be positive." } } variable "relay_smtp_packet_aggregate_burst" { description = "Aggregate TCP/25 packet burst admitted before excess packets are dropped." type = number default = 10000 validation { condition = var.relay_smtp_packet_aggregate_burst >= var.relay_smtp_packet_aggregate_rate_per_second error_message = "relay_smtp_packet_aggregate_burst must cover at least one second." } } variable "relay_auth_syn_rate_per_minute" { description = "Per-source authenticated-mail SYN rate before a source enters temporary transport quarantine." type = number default = 30 validation { condition = var.relay_auth_syn_rate_per_minute >= 1 error_message = "relay_auth_syn_rate_per_minute must be positive." } } variable "relay_auth_syn_burst" { description = "Per-source authenticated-mail SYN burst allowed before transport quarantine." type = number default = 15 validation { condition = var.relay_auth_syn_burst >= 1 error_message = "relay_auth_syn_burst must be positive." } } variable "relay_auth_syn_aggregate_rate_per_second" { description = "Aggregate authenticated-mail SYN rate admitted before excess packets are dropped." type = number default = 200 validation { condition = var.relay_auth_syn_aggregate_rate_per_second >= 1 error_message = "relay_auth_syn_aggregate_rate_per_second must be positive." } } variable "relay_auth_syn_aggregate_burst" { description = "Aggregate authenticated-mail SYN burst admitted before excess packets are dropped." type = number default = 200 validation { condition = var.relay_auth_syn_aggregate_burst >= 1 error_message = "relay_auth_syn_aggregate_burst must be positive." } } variable "relay_auth_packet_aggregate_rate_per_second" { description = "Aggregate authenticated-mail packet rate admitted before conntrack and DNAT." type = number default = 5000 validation { condition = var.relay_auth_packet_aggregate_rate_per_second >= 1 error_message = "relay_auth_packet_aggregate_rate_per_second must be positive." } } variable "relay_auth_packet_aggregate_burst" { description = "Aggregate authenticated-mail packet burst admitted before excess packets are dropped." type = number default = 5000 validation { condition = var.relay_auth_packet_aggregate_burst >= var.relay_auth_packet_aggregate_rate_per_second error_message = "relay_auth_packet_aggregate_burst must cover at least one second." } } variable "relay_http_quarantine_enabled" { description = "Temporarily deny port 80 after repeated attempts without a recent port 443 connection." type = bool default = true } variable "relay_http_quarantine_minutes" { description = "Lifetime of an HTTP-only quarantine." type = number default = 30 validation { condition = var.relay_http_quarantine_minutes >= 1 && var.relay_http_quarantine_minutes <= 1440 error_message = "relay_http_quarantine_minutes must be between 1 and 1440." } } variable "relay_https_recent_minutes" { description = "Period during which a port 443 connection exempts a source from HTTP-only quarantine." type = number default = 10 validation { condition = var.relay_https_recent_minutes >= 1 && var.relay_https_recent_minutes <= 1440 error_message = "relay_https_recent_minutes must be between 1 and 1440." } } variable "relay_unmatched_http_rate_per_hour" { description = "Port 80 attempt rate without recent HTTPS that triggers HTTP-only quarantine." type = number default = 30 validation { condition = var.relay_unmatched_http_rate_per_hour >= 1 error_message = "relay_unmatched_http_rate_per_hour must be positive." } } variable "relay_unmatched_http_burst" { description = "Immediate unmatched port 80 attempts accepted before HTTP-only quarantine." type = number default = 5 validation { condition = var.relay_unmatched_http_burst >= 1 error_message = "relay_unmatched_http_burst must be positive." } } variable "relay_tracker_max_sources" { description = "Maximum per-source entries retained by each nftables ingress tracker." type = number default = 65536 validation { condition = var.relay_tracker_max_sources >= 1024 && var.relay_tracker_max_sources <= 1048576 error_message = "relay_tracker_max_sources must be between 1024 and 1048576." } } variable "web_allow_bundle_object" { description = "Private Object Storage key containing the current normalized web allow bundle." type = string default = "web-allow/v1/current.json.gz" } variable "web_allow_minimum_addresses" { description = "Minimum admitted IPv4 addresses accepted from an update bundle." type = number default = 1000000000 validation { condition = var.web_allow_minimum_addresses >= 1 && var.web_allow_minimum_addresses <= 4294967296 error_message = "web_allow_minimum_addresses must be between 1 and the IPv4 address-space size." } } variable "web_allow_maximum_addresses" { description = "Maximum admitted IPv4 addresses accepted from an update bundle." type = number default = 3500000000 validation { condition = ( var.web_allow_maximum_addresses >= var.web_allow_minimum_addresses && var.web_allow_maximum_addresses <= 4294967296 ) error_message = "web_allow_maximum_addresses must be at least the minimum and no larger than the IPv4 address space." } } variable "web_allow_minimum_intervals" { description = "Minimum admitted IPv4 intervals accepted from an update bundle." type = number default = 10000 validation { condition = var.web_allow_minimum_intervals >= 1 && var.web_allow_minimum_intervals <= 500000 error_message = "web_allow_minimum_intervals must be between 1 and 500000." } } variable "smtp_deny_bundle_object" { description = "Private Object Storage key containing the current SMTP deny bundle." type = string default = "smtp-deny/v1/current.json.gz" } variable "smtp_deny_minimum_observations" { description = "Minimum transport observations required for each SMTP deny entry." type = number default = 20 validation { condition = var.smtp_deny_minimum_observations >= 1 error_message = "smtp_deny_minimum_observations must be positive." } } variable "smtp_deny_maximum_addresses" { description = "Maximum IPv4 addresses covered by an SMTP deny bundle." type = number default = 4096 validation { condition = var.smtp_deny_maximum_addresses >= 1 && var.smtp_deny_maximum_addresses <= 4294967296 error_message = "smtp_deny_maximum_addresses must be between 1 and the IPv4 address-space size." } } variable "smtp_deny_maximum_intervals" { description = "Maximum IPv4 intervals in an SMTP deny bundle." type = number default = 1024 validation { condition = var.smtp_deny_maximum_intervals >= 1 && var.smtp_deny_maximum_intervals <= 100000 error_message = "smtp_deny_maximum_intervals must be between 1 and 100000." } } variable "smtp_deny_maximum_lifetime_seconds" { description = "Maximum lifetime of an SMTP deny bundle or entry." type = number default = 86400 validation { condition = var.smtp_deny_maximum_lifetime_seconds >= 300 && var.smtp_deny_maximum_lifetime_seconds <= 604800 error_message = "smtp_deny_maximum_lifetime_seconds must be between 300 and 604800." } } variable "smtp_deny_maximum_observation_window_seconds" { description = "Maximum observation window represented by one SMTP deny entry." type = number default = 600 validation { condition = ( var.smtp_deny_maximum_observation_window_seconds >= 60 && var.smtp_deny_maximum_observation_window_seconds <= var.smtp_deny_maximum_lifetime_seconds ) error_message = "smtp_deny_maximum_observation_window_seconds must be at least 60 and no greater than the maximum lifetime." } } variable "smtp_evidence_snapshot_interval_seconds" { description = "Cadence for local SMTP deny evidence snapshots." type = number default = 60 validation { condition = contains([30, 60], var.smtp_evidence_snapshot_interval_seconds) error_message = "smtp_evidence_snapshot_interval_seconds must be a tested 30 or 60 second cadence." } } variable "freeform_tags" { description = "Free-form tags applied to OCI relay resources." type = map(string) default = { managed-by = "opentofu" service = "oci-l4-relay" } } variable "email_approved_senders" { description = "Approved Stalwart sender addresses; enable @quorate.dev only after OCI DKIM becomes active." type = list(string) default = ["@quorate.dev"] validation { condition = alltrue([ for sender in var.email_approved_senders : sender == "@quorate.dev" || can(regex("^[^@[:space:]]+@quorate\\.dev$", sender)) ]) error_message = "email_approved_senders may contain @quorate.dev or addresses within quorate.dev." } }