ce7cb702218693d08ea6d83464d2457c9250027c

This commit is contained in:
ms2k 2026-11-12 20:46:28 +09:00
commit 34c5f8963c
46 changed files with 145336 additions and 0 deletions

View file

@ -0,0 +1,63 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "5.22.0"
constraints = "5.22.0"
hashes = [
"h1:EOm3pWL+XqsFNVhupvcedWz7XrYurk52G6ElTSJ+Fxk=",
"h1:H3XmcpcMLeDyuGU6QsBXeVOB2CQGnIVRt6PJf7hfrtE=",
"h1:IqMMtu1KnqHhdRt3He18R1VZ6yijKjCVGL+qvGh5wbM=",
"h1:Mj/TBYAK+oLz4qkb3RBX6qMnCPA215ToNzH1b5VRIE8=",
"h1:RPY1abVjmPNOL79CeRmh1wgpgxoSXskz11HOU01ZX9c=",
"h1:bEk4C6AqKLPIUFijHpzP4yxim+hybvDX15smKqhlL1M=",
"h1:dEU3MBWyHJQh3OHGYi4QTiBxWtcuQKtijYa403txMaM=",
"h1:u3j/+0nmwTHvVg4lTziT8c9YvzGLlJOmFEOv/42yPuQ=",
"zh:45f3b7c50254b1da1dc21e77e03cd1e931cab40fb75c7cba822a53ed54cd232e",
"zh:8437138c0af1a1a557b516ca42dae54499933cc81072396abe7eefd267218f79",
"zh:9140044a3c909e1a2767c8b2dd95370b8152bcbc7cb26c47e376e81f75512d32",
"zh:b69a80d2bb33059e93dec94490065fe210c621d8bdf32d745b1d1972aa85abbf",
"zh:ca4bf16742a7e59319a482f003d32f6f6abbc5fbf862916ce1a136278e6d420d",
"zh:cd767016ea7382e384e560f6ddb302637ecb1b53ece15c9326032010effe6c33",
"zh:d952f92ae1a688ed376757127ae1aa3b625571bf1fc606214a5822eae98213e0",
"zh:f5213814c8ca0d736623438b283143b9a7f98e72ca4992eb906966e7f8cc383b",
"zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32",
]
}
provider "registry.opentofu.org/hashicorp/vault" {
version = "5.10.1"
constraints = "5.10.1"
hashes = [
"h1:/wVGPEJV4FjoW9C4h3M0pqN4Ie9b03anjUJWeylaciU=",
"h1:2kBWbk7XTUlZv6SkvGEkIKXtp7iUeHCcxX8u/bVaq5w=",
"h1:4TgeO1IDWziuoDs8zeB2WG2qovoJu6b8HLAg2b4hzF8=",
"h1:HsmCwrH+qhRXcU3CIAB316NLPiw0t3alufc0MCJVzus=",
"h1:Jv/4vkNUymS3yTTwA72G59IN74auixEOq9C6dN12ZIM=",
"h1:WUy6Ea+dhkj8k79vo0qz9/vAyjripwTsf6DqIzzk5Y4=",
"h1:bX8M1tM4MD/ZRiazv9JUG0vzZG2IFOHeEDkvE9vVoMY=",
"h1:hu9CF1CrQGOCEF9sZEendFKRqbEXuHY4Rz2enypS/FE=",
"h1:id6Hv41s6c/JBc1iK/HUA/0L36nQ8MNTnmoXosQRyGU=",
"h1:nrNJNXmVUnx/gp6dG24S5Wx6gJJmQ5IpUBdJldWNsgk=",
"h1:swXi7Yx24kZY53o7fuWeUe7QX4rNOGixx/fLL9sO3bE=",
"h1:tcy+THs72hvdeNLgYicSgK0kA7dpgymaF1ylkg8Bjvw=",
"h1:tp2AHrZv9QWX70YYqsk9EFcRJdXm0M4lMEpHE7MoxeI=",
"h1:uxfYlF3C4XEdD3a2hEN7aoaEYeTg+bQuvjBePp6H0nU=",
"h1:wo5cTkl/1nlxMfdn1yEDIHNoRLMczuK6COH2Id4/zeY=",
"zh:0abf976c01f0c0732d0ccc6481e52008be5ee9c8e3d9b5eba0573c640fcf7019",
"zh:2aff4d7ee7ba9eb3de2cd5cda16ba92b4ec7a2b43232aec180984241a323b216",
"zh:2cc186fd0bfc44e100a22b0b40ae8ddcd0ec210a53c1da65d310ee758b1d2b08",
"zh:3f8fb8594736b34af4b26437dd4df4dd4042ad4905223995cfebb8a1f10682ec",
"zh:47fb41b18b74073f557dbcd6aad2183e416293405ccd70c0691a279cfe97f8cd",
"zh:517e2f2764d671c22d22def0384fdfc521b456458189189c0363375495d114dc",
"zh:5a49a2003636f2b8a547d494a6c06d43d62a68299775305408c52eff22b1c11f",
"zh:66d4e716920ada84b0c768f4aca4c8948388995462923349a01bd3818d82b618",
"zh:7599f652e89a3f18fa4b76a59d115cc63255cc36ce6b273850509ba25031abca",
"zh:9c3e38ae7e670de973b6255d7050f526cd2b3ca7c383d7ba7226fc204d97c507",
"zh:d04b046023fa9fd69def678f27e001c298ea34fc99ba51f835cda82e496fdb57",
"zh:d9acd8810f6660cd51bb4c25596632984ae18e93340c82a102d074c6eac95151",
"zh:e161bcb9a22607270b980eeff2ba693335fb62d6978516dff93dd4c91cda99b3",
"zh:ef47502f08cfcb5311b7b16a7905e0052bf28359e07cc00ed080ef454e0946cf",
"zh:f0640ddb52e7e90c5006ff571f6ad0554e593665320c764c57a3d8b7ec31b490",
]
}

View file

@ -0,0 +1,49 @@
resource "cloudflare_pages_project" "home" {
account_id = var.account_id
name = "quorate-home"
production_branch = "master"
}
resource "cloudflare_pages_domain" "home" {
account_id = var.account_id
project_name = cloudflare_pages_project.home.name
name = "quorate.dev"
}
resource "cloudflare_dns_record" "home" {
zone_id = var.zone_id
name = cloudflare_pages_domain.home.name
type = "CNAME"
content = cloudflare_pages_project.home.subdomain
ttl = 1
proxied = true
}
resource "cloudflare_pages_project" "mc_pack" {
account_id = var.account_id
name = "mc-pack"
production_branch = "master"
}
resource "cloudflare_pages_domain" "mc_pack" {
account_id = var.account_id
project_name = cloudflare_pages_project.mc_pack.name
name = "mc-pack.quorate.dev"
}
resource "cloudflare_dns_record" "mc_pack" {
zone_id = var.zone_id
name = cloudflare_pages_domain.mc_pack.name
type = "CNAME"
content = cloudflare_pages_project.mc_pack.subdomain
ttl = 1
proxied = true
}
output "mc_pack_url" {
value = "https://${cloudflare_pages_domain.mc_pack.name}/e10c.mrpack"
}
output "mc_shaders_url" {
value = "https://${cloudflare_pages_domain.mc_pack.name}/e10c-shaders.mrpack"
}

View file

@ -0,0 +1,30 @@
terraform {
required_version = ">= 1.11.0, < 2.0.0"
backend "pg" {
conn_str = "postgres://10.234.158.153:5432/tf_state?sslmode=require"
schema_name = "ext_cf_pages"
}
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "5.22.0"
}
vault = {
source = "hashicorp/vault"
version = "5.10.1"
}
}
}
provider "vault" {}
ephemeral "vault_kv_secret_v2" "pages" {
mount = "secret"
name = "cloudflare/pages-infrastructure"
}
provider "cloudflare" {
api_token = ephemeral.vault_kv_secret_v2.pages.data["api-token"]
}

View file

@ -0,0 +1,9 @@
variable "account_id" {
type = string
default = "********"
}
variable "zone_id" {
type = string
default = "********"
}

View file

@ -0,0 +1,63 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "5.22.0"
constraints = "5.22.0"
hashes = [
"h1:EOm3pWL+XqsFNVhupvcedWz7XrYurk52G6ElTSJ+Fxk=",
"h1:H3XmcpcMLeDyuGU6QsBXeVOB2CQGnIVRt6PJf7hfrtE=",
"h1:IqMMtu1KnqHhdRt3He18R1VZ6yijKjCVGL+qvGh5wbM=",
"h1:Mj/TBYAK+oLz4qkb3RBX6qMnCPA215ToNzH1b5VRIE8=",
"h1:RPY1abVjmPNOL79CeRmh1wgpgxoSXskz11HOU01ZX9c=",
"h1:bEk4C6AqKLPIUFijHpzP4yxim+hybvDX15smKqhlL1M=",
"h1:dEU3MBWyHJQh3OHGYi4QTiBxWtcuQKtijYa403txMaM=",
"h1:u3j/+0nmwTHvVg4lTziT8c9YvzGLlJOmFEOv/42yPuQ=",
"zh:45f3b7c50254b1da1dc21e77e03cd1e931cab40fb75c7cba822a53ed54cd232e",
"zh:8437138c0af1a1a557b516ca42dae54499933cc81072396abe7eefd267218f79",
"zh:9140044a3c909e1a2767c8b2dd95370b8152bcbc7cb26c47e376e81f75512d32",
"zh:b69a80d2bb33059e93dec94490065fe210c621d8bdf32d745b1d1972aa85abbf",
"zh:ca4bf16742a7e59319a482f003d32f6f6abbc5fbf862916ce1a136278e6d420d",
"zh:cd767016ea7382e384e560f6ddb302637ecb1b53ece15c9326032010effe6c33",
"zh:d952f92ae1a688ed376757127ae1aa3b625571bf1fc606214a5822eae98213e0",
"zh:f5213814c8ca0d736623438b283143b9a7f98e72ca4992eb906966e7f8cc383b",
"zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32",
]
}
provider "registry.opentofu.org/hashicorp/vault" {
version = "5.10.1"
constraints = "5.10.1"
hashes = [
"h1:/wVGPEJV4FjoW9C4h3M0pqN4Ie9b03anjUJWeylaciU=",
"h1:2kBWbk7XTUlZv6SkvGEkIKXtp7iUeHCcxX8u/bVaq5w=",
"h1:4TgeO1IDWziuoDs8zeB2WG2qovoJu6b8HLAg2b4hzF8=",
"h1:HsmCwrH+qhRXcU3CIAB316NLPiw0t3alufc0MCJVzus=",
"h1:Jv/4vkNUymS3yTTwA72G59IN74auixEOq9C6dN12ZIM=",
"h1:WUy6Ea+dhkj8k79vo0qz9/vAyjripwTsf6DqIzzk5Y4=",
"h1:bX8M1tM4MD/ZRiazv9JUG0vzZG2IFOHeEDkvE9vVoMY=",
"h1:hu9CF1CrQGOCEF9sZEendFKRqbEXuHY4Rz2enypS/FE=",
"h1:id6Hv41s6c/JBc1iK/HUA/0L36nQ8MNTnmoXosQRyGU=",
"h1:nrNJNXmVUnx/gp6dG24S5Wx6gJJmQ5IpUBdJldWNsgk=",
"h1:swXi7Yx24kZY53o7fuWeUe7QX4rNOGixx/fLL9sO3bE=",
"h1:tcy+THs72hvdeNLgYicSgK0kA7dpgymaF1ylkg8Bjvw=",
"h1:tp2AHrZv9QWX70YYqsk9EFcRJdXm0M4lMEpHE7MoxeI=",
"h1:uxfYlF3C4XEdD3a2hEN7aoaEYeTg+bQuvjBePp6H0nU=",
"h1:wo5cTkl/1nlxMfdn1yEDIHNoRLMczuK6COH2Id4/zeY=",
"zh:0abf976c01f0c0732d0ccc6481e52008be5ee9c8e3d9b5eba0573c640fcf7019",
"zh:2aff4d7ee7ba9eb3de2cd5cda16ba92b4ec7a2b43232aec180984241a323b216",
"zh:2cc186fd0bfc44e100a22b0b40ae8ddcd0ec210a53c1da65d310ee758b1d2b08",
"zh:3f8fb8594736b34af4b26437dd4df4dd4042ad4905223995cfebb8a1f10682ec",
"zh:47fb41b18b74073f557dbcd6aad2183e416293405ccd70c0691a279cfe97f8cd",
"zh:517e2f2764d671c22d22def0384fdfc521b456458189189c0363375495d114dc",
"zh:5a49a2003636f2b8a547d494a6c06d43d62a68299775305408c52eff22b1c11f",
"zh:66d4e716920ada84b0c768f4aca4c8948388995462923349a01bd3818d82b618",
"zh:7599f652e89a3f18fa4b76a59d115cc63255cc36ce6b273850509ba25031abca",
"zh:9c3e38ae7e670de973b6255d7050f526cd2b3ca7c383d7ba7226fc204d97c507",
"zh:d04b046023fa9fd69def678f27e001c298ea34fc99ba51f835cda82e496fdb57",
"zh:d9acd8810f6660cd51bb4c25596632984ae18e93340c82a102d074c6eac95151",
"zh:e161bcb9a22607270b980eeff2ba693335fb62d6978516dff93dd4c91cda99b3",
"zh:ef47502f08cfcb5311b7b16a7905e0052bf28359e07cc00ed080ef454e0946cf",
"zh:f0640ddb52e7e90c5006ff571f6ad0554e593665320c764c57a3d8b7ec31b490",
]
}

View file

@ -0,0 +1,126 @@
locals {
code_host = "http.host eq \"${var.forge_code_hostname}\""
code_path = <<-EOT
(${local.code_host})
and not ends_with(http.request.uri.path, "/info/refs")
and not ends_with(http.request.uri.path, "/git-upload-pack")
and not ends_with(http.request.uri.path, "/git-receive-pack")
and not ends_with(http.request.uri.path, "/HEAD")
and not http.request.uri.path contains "/objects/"
EOT
# Forgejo parses multipart GET bodies, including HTTP/2 bodies without Content-Length.
code_read = <<-EOT
(${local.code_path})
and http.request.method in {"GET" "HEAD"}
and not any(lower(http.request.headers.names[*])[*] in {"content-type" "content-length" "transfer-encoding"})
EOT
code_response = <<-EOT
(${local.code_read})
and http.response.code in {200 206 304}
and not any(http.response.headers["cache-control"][*] contains "no-store")
EOT
}
resource "cloudflare_ruleset" "code_requests" {
provider = cloudflare.cache
zone_id = var.zone_id
name = "forge-code-requests"
kind = "zone"
phase = "http_request_cache_settings"
rules = [
{
ref = "code_bypass"
expression = local.code_host
action = "set_cache_settings"
action_parameters = {
cache = false
}
},
{
# Include Cloudflare's internal PURGE method so URL purges use the same cache settings.
ref = "code_reads"
expression = "((${local.code_path}) and http.request.method eq \"PURGE\") or ((${local.code_read}) and not http.request.headers.truncated)"
action = "set_cache_settings"
action_parameters = {
cache = true
edge_ttl = {
mode = "respect_origin"
}
browser_ttl = {
mode = "respect_origin"
}
vary = {
default = {
action = "bypass"
}
headers = {
accept = {
action = "passthrough"
}
accept-language = {
action = "passthrough"
}
accept-encoding = {
action = "normalize"
}
}
}
}
},
]
}
resource "cloudflare_ruleset" "code_responses" {
provider = cloudflare.cache
zone_id = var.zone_id
name = "forge-code-responses"
kind = "zone"
phase = "http_response_cache_settings"
rules = [
{
ref = "code_errors"
expression = "(${local.code_host}) and not http.response.code in {200 206 304}"
action = "set_cache_control"
action_parameters = {
no_store = {
operation = "set"
cloudflare_only = true
}
}
},
{
ref = "code_public"
expression = local.code_response
action = "set_cache_control"
action_parameters = {
private = {
operation = "remove"
cloudflare_only = true
}
public = {
operation = "set"
cloudflare_only = true
}
s_maxage = {
operation = "set"
value = 300
cloudflare_only = true
}
}
},
{
ref = "code_assets"
expression = "(${local.code_response}) and starts_with(http.request.uri.path, \"/assets/\")"
action = "set_cache_control"
action_parameters = {
s_maxage = {
operation = "set"
value = 21600
cloudflare_only = true
}
}
},
]
}

View file

@ -0,0 +1,74 @@
resource "cloudflare_zero_trust_tunnel_cloudflared" "main" {
provider = cloudflare.tunnel
account_id = var.account_id
name = "quorate-main"
config_src = "cloudflare"
lifecycle {
prevent_destroy = true
}
}
resource "cloudflare_zero_trust_tunnel_cloudflared_config" "main" {
provider = cloudflare.tunnel
account_id = var.account_id
tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.main.id
config = {
ingress = [
{
hostname = var.canary_hostname
service = var.canary_origin
},
{
hostname = var.mta_sts_hostname
service = var.mta_sts_origin
},
{
hostname = var.forge_code_hostname
service = var.forge_code_origin
},
{
hostname = "health.quorate.dev"
service = "http://cluster-health-api.cluster-health.svc.cluster.local:8080"
},
{
service = "http_status:404"
},
]
}
}
resource "cloudflare_dns_record" "tier_o_canary" {
provider = cloudflare.public_dns
zone_id = var.zone_id
name = var.canary_hostname
type = "CNAME"
content = "${cloudflare_zero_trust_tunnel_cloudflared.main.id}.cfargotunnel.com"
ttl = 1
proxied = true
}
resource "cloudflare_dns_record" "mta_sts" {
provider = cloudflare.public_dns
zone_id = var.zone_id
name = var.mta_sts_hostname
type = "CNAME"
content = "${cloudflare_zero_trust_tunnel_cloudflared.main.id}.cfargotunnel.com"
ttl = 1
proxied = true
}
resource "cloudflare_dns_record" "forge_code" {
provider = cloudflare.public_dns
zone_id = var.zone_id
name = var.forge_code_hostname
type = "CNAME"
content = "${cloudflare_zero_trust_tunnel_cloudflared.main.id}.cfargotunnel.com"
ttl = 1
proxied = true
}

View file

@ -0,0 +1,19 @@
output "tunnel_id" {
description = "Tier O tunnel identifier used to retrieve or rotate its connector token."
value = cloudflare_zero_trust_tunnel_cloudflared.main.id
}
output "canary_hostname" {
description = "Exact Tier O canary hostname."
value = cloudflare_dns_record.tier_o_canary.name
}
output "mta_sts_hostname" {
description = "Exact Tier O hostname serving the MTA-STS policy."
value = cloudflare_dns_record.mta_sts.name
}
output "forge_code_hostname" {
description = "Exact anonymous Forgejo hostname exposed through Tier O."
value = cloudflare_dns_record.forge_code.name
}

View file

@ -0,0 +1,61 @@
terraform {
required_version = ">= 1.11.0, < 2.0.0"
backend "pg" {
conn_str = "postgres://10.234.158.153:5432/tf_state?sslmode=require"
schema_name = "ext_cf_tunnel"
}
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "5.22.0"
}
vault = {
source = "hashicorp/vault"
version = "5.10.1"
}
}
}
provider "vault" {}
ephemeral "vault_kv_secret_v2" "tunnel_configuration" {
mount = "secret"
name = "cloudflare/tier-o-tunnel-config"
}
ephemeral "vault_kv_secret_v2" "public_dns" {
mount = "secret"
name = "cloudflare/pages-infrastructure"
}
ephemeral "vault_kv_secret_v2" "cache_rules" {
mount = "secret"
name = "cloudflare/forge-cache"
}
ephemeral "vault_kv_secret_v2" "waf_edit" {
mount = "secret"
name = "cloudflare/waf-edit"
}
provider "cloudflare" {
alias = "tunnel"
api_token = ephemeral.vault_kv_secret_v2.tunnel_configuration.data["api-token"]
}
provider "cloudflare" {
alias = "public_dns"
api_token = ephemeral.vault_kv_secret_v2.public_dns.data["api-token"]
}
provider "cloudflare" {
alias = "cache"
api_token = ephemeral.vault_kv_secret_v2.cache_rules.data["api-token"]
}
provider "cloudflare" {
alias = "waf"
api_token = ephemeral.vault_kv_secret_v2.waf_edit.data["api-token"]
}

View file

@ -0,0 +1,47 @@
variable "account_id" {
description = "Cloudflare account identifier."
type = string
default = "********"
}
variable "zone_id" {
description = "Cloudflare zone identifier for quorate.dev."
type = string
default = "********"
}
variable "canary_hostname" {
description = "Exact public hostname assigned to the Tier O canary."
type = string
default = "canary.quorate.dev"
}
variable "canary_origin" {
description = "In-cluster HTTP origin reached by cloudflared."
type = string
default = "http://tier-o-canary.tier-o-canary.svc.cluster.local:8080"
}
variable "mta_sts_hostname" {
description = "Exact public hostname serving the MTA-STS policy."
type = string
default = "mta-sts.quorate.dev"
}
variable "mta_sts_origin" {
description = "In-cluster MTA-STS policy origin reached by cloudflared."
type = string
default = "http://mta-sts.mta-sts.svc.cluster.local:8080"
}
variable "forge_code_hostname" {
description = "Exact public hostname assigned to the anonymous Forgejo facade."
type = string
default = "code.quorate.dev"
}
variable "forge_code_origin" {
description = "In-cluster anonymous Forgejo facade reached by cloudflared."
type = string
default = "http://forge-code-facade.forgejo-public.svc.cluster.local.:8080"
}

View file

@ -0,0 +1,21 @@
resource "cloudflare_ruleset" "code_firewall" {
provider = cloudflare.waf
zone_id = var.zone_id
name = "forge-code-waf"
kind = "zone"
phase = "http_request_firewall_custom"
rules = [
{
ref = "meta_login"
description = "Block Meta-ExternalAgent requests to login pages. Added due to frequent robots.txt violations."
expression = <<-EOT
(${local.code_host})
and lower(http.user_agent) contains "meta-externalagent"
and http.request.uri.path in {"/user/login" "/login-disabled"}
EOT
action = "block"
enabled = true
},
]
}

63
terraform/external/cloudflare/.terraform.lock.hcl generated vendored Normal file
View file

@ -0,0 +1,63 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "5.22.0"
constraints = "~> 5.0"
hashes = [
"h1:EOm3pWL+XqsFNVhupvcedWz7XrYurk52G6ElTSJ+Fxk=",
"h1:H3XmcpcMLeDyuGU6QsBXeVOB2CQGnIVRt6PJf7hfrtE=",
"h1:IqMMtu1KnqHhdRt3He18R1VZ6yijKjCVGL+qvGh5wbM=",
"h1:Mj/TBYAK+oLz4qkb3RBX6qMnCPA215ToNzH1b5VRIE8=",
"h1:RPY1abVjmPNOL79CeRmh1wgpgxoSXskz11HOU01ZX9c=",
"h1:bEk4C6AqKLPIUFijHpzP4yxim+hybvDX15smKqhlL1M=",
"h1:dEU3MBWyHJQh3OHGYi4QTiBxWtcuQKtijYa403txMaM=",
"h1:u3j/+0nmwTHvVg4lTziT8c9YvzGLlJOmFEOv/42yPuQ=",
"zh:45f3b7c50254b1da1dc21e77e03cd1e931cab40fb75c7cba822a53ed54cd232e",
"zh:8437138c0af1a1a557b516ca42dae54499933cc81072396abe7eefd267218f79",
"zh:9140044a3c909e1a2767c8b2dd95370b8152bcbc7cb26c47e376e81f75512d32",
"zh:b69a80d2bb33059e93dec94490065fe210c621d8bdf32d745b1d1972aa85abbf",
"zh:ca4bf16742a7e59319a482f003d32f6f6abbc5fbf862916ce1a136278e6d420d",
"zh:cd767016ea7382e384e560f6ddb302637ecb1b53ece15c9326032010effe6c33",
"zh:d952f92ae1a688ed376757127ae1aa3b625571bf1fc606214a5822eae98213e0",
"zh:f5213814c8ca0d736623438b283143b9a7f98e72ca4992eb906966e7f8cc383b",
"zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32",
]
}
provider "registry.opentofu.org/hashicorp/vault" {
version = "5.10.1"
constraints = "5.10.1"
hashes = [
"h1:/wVGPEJV4FjoW9C4h3M0pqN4Ie9b03anjUJWeylaciU=",
"h1:2kBWbk7XTUlZv6SkvGEkIKXtp7iUeHCcxX8u/bVaq5w=",
"h1:4TgeO1IDWziuoDs8zeB2WG2qovoJu6b8HLAg2b4hzF8=",
"h1:HsmCwrH+qhRXcU3CIAB316NLPiw0t3alufc0MCJVzus=",
"h1:Jv/4vkNUymS3yTTwA72G59IN74auixEOq9C6dN12ZIM=",
"h1:WUy6Ea+dhkj8k79vo0qz9/vAyjripwTsf6DqIzzk5Y4=",
"h1:bX8M1tM4MD/ZRiazv9JUG0vzZG2IFOHeEDkvE9vVoMY=",
"h1:hu9CF1CrQGOCEF9sZEendFKRqbEXuHY4Rz2enypS/FE=",
"h1:id6Hv41s6c/JBc1iK/HUA/0L36nQ8MNTnmoXosQRyGU=",
"h1:nrNJNXmVUnx/gp6dG24S5Wx6gJJmQ5IpUBdJldWNsgk=",
"h1:swXi7Yx24kZY53o7fuWeUe7QX4rNOGixx/fLL9sO3bE=",
"h1:tcy+THs72hvdeNLgYicSgK0kA7dpgymaF1ylkg8Bjvw=",
"h1:tp2AHrZv9QWX70YYqsk9EFcRJdXm0M4lMEpHE7MoxeI=",
"h1:uxfYlF3C4XEdD3a2hEN7aoaEYeTg+bQuvjBePp6H0nU=",
"h1:wo5cTkl/1nlxMfdn1yEDIHNoRLMczuK6COH2Id4/zeY=",
"zh:0abf976c01f0c0732d0ccc6481e52008be5ee9c8e3d9b5eba0573c640fcf7019",
"zh:2aff4d7ee7ba9eb3de2cd5cda16ba92b4ec7a2b43232aec180984241a323b216",
"zh:2cc186fd0bfc44e100a22b0b40ae8ddcd0ec210a53c1da65d310ee758b1d2b08",
"zh:3f8fb8594736b34af4b26437dd4df4dd4042ad4905223995cfebb8a1f10682ec",
"zh:47fb41b18b74073f557dbcd6aad2183e416293405ccd70c0691a279cfe97f8cd",
"zh:517e2f2764d671c22d22def0384fdfc521b456458189189c0363375495d114dc",
"zh:5a49a2003636f2b8a547d494a6c06d43d62a68299775305408c52eff22b1c11f",
"zh:66d4e716920ada84b0c768f4aca4c8948388995462923349a01bd3818d82b618",
"zh:7599f652e89a3f18fa4b76a59d115cc63255cc36ce6b273850509ba25031abca",
"zh:9c3e38ae7e670de973b6255d7050f526cd2b3ca7c383d7ba7226fc204d97c507",
"zh:d04b046023fa9fd69def678f27e001c298ea34fc99ba51f835cda82e496fdb57",
"zh:d9acd8810f6660cd51bb4c25596632984ae18e93340c82a102d074c6eac95151",
"zh:e161bcb9a22607270b980eeff2ba693335fb62d6978516dff93dd4c91cda99b3",
"zh:ef47502f08cfcb5311b7b16a7905e0052bf28359e07cc00ed080ef454e0946cf",
"zh:f0640ddb52e7e90c5006ff571f6ad0554e593665320c764c57a3d8b7ec31b490",
]
}

162
terraform/external/cloudflare/dns.tf vendored Normal file
View file

@ -0,0 +1,162 @@
data "terraform_remote_state" "oci_relay" {
backend = "pg"
config = {
conn_str = "postgres://10.234.158.153:5432/tf_state?sslmode=require"
schema_name = "ext_oci_relay"
}
}
locals {
mta_sts_policy = "version: STSv1\nmode: testing\nmx: mail.quorate.dev\nmax_age: 86400\n"
mta_sts_policy_id = substr(sha256(local.mta_sts_policy), 0, 16)
}
data "cloudflare_dns_records" "zitadel" {
zone_id = var.zone_id
match = "all"
name = {
exact = "auth.quorate.dev"
}
}
data "cloudflare_dns_records" "forge_git" {
zone_id = var.zone_id
match = "all"
name = {
exact = "git.quorate.dev"
}
}
data "cloudflare_dns_records" "mail" {
zone_id = var.zone_id
match = "all"
name = {
exact = "mail.quorate.dev"
}
}
resource "cloudflare_dns_record" "zitadel" {
zone_id = var.zone_id
name = "auth.quorate.dev"
type = "A"
content = data.terraform_remote_state.oci_relay.outputs.public_ip
ttl = 120
proxied = false
}
resource "cloudflare_dns_record" "mail" {
count = var.mail_a_enabled ? 1 : 0
zone_id = var.zone_id
name = "mail.quorate.dev"
type = "A"
content = data.terraform_remote_state.oci_relay.outputs.public_ip
ttl = 120
proxied = false
}
resource "cloudflare_dns_record" "mail_mx" {
count = var.mail_mx_enabled ? 1 : 0
zone_id = var.zone_id
name = "quorate.dev"
type = "MX"
content = "mail.quorate.dev"
priority = 10
ttl = 120
}
resource "cloudflare_dns_record" "mail_dkim" {
zone_id = var.zone_id
name = trimsuffix(data.terraform_remote_state.oci_relay.outputs.email_dkim_dns_name, ".")
type = "CNAME"
content = data.terraform_remote_state.oci_relay.outputs.email_dkim_cname_target
ttl = 120
proxied = false
}
resource "cloudflare_dns_record" "mail_spf" {
zone_id = var.zone_id
name = "quorate.dev"
type = "TXT"
content = "v=spf1 include:ap.rp.oracleemaildelivery.com ~all"
ttl = 120
}
resource "cloudflare_dns_record" "google_postmaster" {
zone_id = var.zone_id
name = "quorate.dev"
type = "TXT"
content = "google-site-verification=********"
ttl = 120
}
resource "cloudflare_dns_record" "mail_dmarc" {
zone_id = var.zone_id
name = "_dmarc.quorate.dev"
type = "TXT"
content = "v=DMARC1; p=none; rua=mailto:[email protected]"
ttl = 120
}
resource "cloudflare_dns_record" "mail_mta_sts" {
zone_id = var.zone_id
name = "_mta-sts.quorate.dev"
type = "TXT"
content = "v=STSv1; id=${local.mta_sts_policy_id}"
ttl = 120
}
resource "cloudflare_dns_record" "mail_tlsrpt" {
zone_id = var.zone_id
name = "_smtp._tls.quorate.dev"
type = "TXT"
content = "v=TLSRPTv1; rua=mailto:[email protected]"
ttl = 120
}
resource "cloudflare_dns_record" "forge_git" {
zone_id = var.zone_id
name = "git.quorate.dev"
type = "A"
content = data.terraform_remote_state.oci_relay.outputs.public_ip
ttl = 120
proxied = false
}
check "zitadel_has_no_bypass" {
assert {
condition = (
length([for record in data.cloudflare_dns_records.zitadel.result : record if record.type == "A"]) == 1 &&
length([for record in data.cloudflare_dns_records.zitadel.result : record if record.type == "AAAA"]) == 0
)
error_message = "Zitadel must have exactly one A record and no AAAA record."
}
}
check "forge_git_has_no_bypass" {
assert {
condition = (
length([for record in data.cloudflare_dns_records.forge_git.result : record if record.type == "A"]) <= 1 &&
length([for record in data.cloudflare_dns_records.forge_git.result : record if record.type == "AAAA"]) == 0
)
error_message = "Authenticated public Forgejo must have at most one A record and no AAAA record before reconciliation."
}
}
resource "terraform_data" "mail_dns_activation" {
lifecycle {
precondition {
condition = !var.mail_mx_enabled || var.mail_a_enabled
error_message = "The authoritative MX record requires the mail host A record to remain enabled."
}
precondition {
condition = (
length([for record in data.cloudflare_dns_records.mail.result : record if record.type == "A"]) <= 1 &&
length([for record in data.cloudflare_dns_records.mail.result : record if record.type == "AAAA"]) == 0
)
error_message = "Stalwart must have at most one A record and no AAAA record before reconciliation."
}
}
}

16
terraform/external/cloudflare/health.tf vendored Normal file
View file

@ -0,0 +1,16 @@
data "terraform_remote_state" "cf_tunnel" {
backend = "pg"
config = {
conn_str = "postgres://10.234.158.153:5432/tf_state?sslmode=require"
schema_name = "ext_cf_tunnel"
}
}
resource "cloudflare_dns_record" "health" {
zone_id = var.zone_id
name = "health.quorate.dev"
type = "CNAME"
content = "${data.terraform_remote_state.cf_tunnel.outputs.tunnel_id}.cfargotunnel.com"
ttl = 1
proxied = true
}

View file

@ -0,0 +1,14 @@
output "zitadel_ipv4" {
description = "Declared Zitadel ingress address."
value = cloudflare_dns_record.zitadel.content
}
output "forge_git_ipv4" {
description = "Declared authenticated public Forgejo ingress address."
value = cloudflare_dns_record.forge_git.content
}
output "mail_ipv4" {
description = "Declared authoritative mail ingress address."
value = try(cloudflare_dns_record.mail[0].content, null)
}

View file

@ -0,0 +1,30 @@
terraform {
required_version = ">= 1.11.0, < 2.0.0"
backend "pg" {
conn_str = "postgres://10.234.158.153:5432/tf_state?sslmode=require"
schema_name = "ext_cloudflare"
}
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 5.0"
}
vault = {
source = "hashicorp/vault"
version = "5.10.1"
}
}
}
provider "vault" {}
ephemeral "vault_kv_secret_v2" "cloudflare_oci_relay_dns" {
mount = "secret"
name = "cloudflare/oci-relay-dns"
}
provider "cloudflare" {
api_token = ephemeral.vault_kv_secret_v2.cloudflare_oci_relay_dns.data["api-token"]
}

View file

@ -0,0 +1,17 @@
variable "zone_id" {
description = "Cloudflare zone identifier for quorate.dev."
type = string
default = "********"
}
variable "mail_a_enabled" {
description = "Publish the mail host A record after direct-IP qualification."
type = bool
default = true
}
variable "mail_mx_enabled" {
description = "Publish the authoritative MX record after mail host qualification."
type = bool
default = true
}

76
terraform/external/google/.terraform.lock.hcl generated vendored Normal file
View file

@ -0,0 +1,76 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/hashicorp/google" {
version = "7.41.0"
constraints = "7.41.0"
hashes = [
"h1:2jNl9wgqqpz9svKBVNE34pxoakD5KV/uS143GI4jhCo=",
"h1:3ccNofdUnIeP4G2e/h5dLxApo+v4ghM9QPNFBVgShkE=",
"h1:6ct8iH9RE/G2TX5impB1YQ+bRf8EbaYScSEy2uhgMRo=",
"h1:9AgR7lowWiq3zJ532kHf1nWEuPh7lvcfQLNxNmSIypg=",
"h1:G2Yngecxsy2UAbzqFxsifrII+iZONY1SflUN3+f2vnE=",
"h1:QOCB/w2toWrYUi7ErjYpugaaai2LPaocKFj4BarFpWE=",
"h1:T3Kj5M7Y8G/HCqzoE/sMhZC4aXuw2STZQU4W3Obv91s=",
"h1:X2IqtGMruu4K4Ao+NibQh+83cp9FNT9/WkWETjmUNFc=",
"h1:ZP/Ky3lyuGeKYp1uffDcVbH9jz5zpXHxesuvMuG2/mQ=",
"h1:fIlWDYlvm9eIHIANgO6dH9NDsUkcH59oFMmDVTj83Co=",
"h1:fUeb26hdXK7RtfdSp6ZlfILxpK3i3O82yC6AH7q//b4=",
"h1:iP2AmCQvMxJP9UR0z1zfWxGmQG1EMpDvJqrWp84hR10=",
"h1:nfRN927XZyTgIpdvYD1mSQycGU/8MtxUP6XKV0XP4bc=",
"h1:oByfVDwWpxwZ0firxEfful0620Af10d0zJze+8TU21A=",
"h1:qM9v/2sGPefclvMs3NJq8Obz3n4PuKZBlT7vM9W688c=",
"zh:19e5e6fc68195955d21ea11f2b784d13ba7e3b1a1a200d6b54bd4b332e530805",
"zh:1c6ef4992d19d268bdf53b5938974e030b27c775a5c9ac519c767156012332aa",
"zh:378e6d6f6341a3f757750257598f0643d5906a9e0d93eb52cd288df66273873d",
"zh:42c060a5da2cc0b9ba1afd99be5d467f29c399f4bb8cc97e6a827b792ee37494",
"zh:4d9db09267fb06c905bfeb1fafe03131166835bf9d8ffabf8ff82aad758a49c4",
"zh:742b661d8b6fa05c16e885ab25c025a27be4cdd287902b43a76d751510dde362",
"zh:9fa809a8d89eec61e89349f4d2676c35169f56fa13019792752996fdf09d987e",
"zh:aeb86675b2f697ab44aeb168ad34cacf507e29f29120f94b3fafb445b0d5ea1b",
"zh:b529bb2474a0b3b5a83d30f2bc5d11a0e29558aabe6f4f01ff0a5b5da1b5941d",
"zh:b9b1506695a456d04303b2e176a744db73495db51dd5d1e72cdc03867b5ea3b5",
"zh:be69568e605eb70552c3230db2c792a0ebf7ac04684dd79e80e7da647517a298",
"zh:d531bbdd06a8740c814b46e11cd190bc0c57282ef5a3247d4ea054c3623b4d4b",
"zh:de856ac303afeafb465ba795e1581f321767622cd17e135ad6723ff328a3d774",
"zh:ecaa4835f9aee26d0a8fc25abd4a360b71893dfc561dac5cd65a17a641c865d6",
"zh:ef54bcc25ce5e7ca34820a41991119d0ee0e3fbd7c8fe930cfa87d26c3e8c417",
]
}
provider "registry.opentofu.org/hashicorp/vault" {
version = "5.10.1"
constraints = "5.10.1"
hashes = [
"h1:/wVGPEJV4FjoW9C4h3M0pqN4Ie9b03anjUJWeylaciU=",
"h1:2kBWbk7XTUlZv6SkvGEkIKXtp7iUeHCcxX8u/bVaq5w=",
"h1:4TgeO1IDWziuoDs8zeB2WG2qovoJu6b8HLAg2b4hzF8=",
"h1:HsmCwrH+qhRXcU3CIAB316NLPiw0t3alufc0MCJVzus=",
"h1:Jv/4vkNUymS3yTTwA72G59IN74auixEOq9C6dN12ZIM=",
"h1:WUy6Ea+dhkj8k79vo0qz9/vAyjripwTsf6DqIzzk5Y4=",
"h1:bX8M1tM4MD/ZRiazv9JUG0vzZG2IFOHeEDkvE9vVoMY=",
"h1:hu9CF1CrQGOCEF9sZEendFKRqbEXuHY4Rz2enypS/FE=",
"h1:id6Hv41s6c/JBc1iK/HUA/0L36nQ8MNTnmoXosQRyGU=",
"h1:nrNJNXmVUnx/gp6dG24S5Wx6gJJmQ5IpUBdJldWNsgk=",
"h1:swXi7Yx24kZY53o7fuWeUe7QX4rNOGixx/fLL9sO3bE=",
"h1:tcy+THs72hvdeNLgYicSgK0kA7dpgymaF1ylkg8Bjvw=",
"h1:tp2AHrZv9QWX70YYqsk9EFcRJdXm0M4lMEpHE7MoxeI=",
"h1:uxfYlF3C4XEdD3a2hEN7aoaEYeTg+bQuvjBePp6H0nU=",
"h1:wo5cTkl/1nlxMfdn1yEDIHNoRLMczuK6COH2Id4/zeY=",
"zh:0abf976c01f0c0732d0ccc6481e52008be5ee9c8e3d9b5eba0573c640fcf7019",
"zh:2aff4d7ee7ba9eb3de2cd5cda16ba92b4ec7a2b43232aec180984241a323b216",
"zh:2cc186fd0bfc44e100a22b0b40ae8ddcd0ec210a53c1da65d310ee758b1d2b08",
"zh:3f8fb8594736b34af4b26437dd4df4dd4042ad4905223995cfebb8a1f10682ec",
"zh:47fb41b18b74073f557dbcd6aad2183e416293405ccd70c0691a279cfe97f8cd",
"zh:517e2f2764d671c22d22def0384fdfc521b456458189189c0363375495d114dc",
"zh:5a49a2003636f2b8a547d494a6c06d43d62a68299775305408c52eff22b1c11f",
"zh:66d4e716920ada84b0c768f4aca4c8948388995462923349a01bd3818d82b618",
"zh:7599f652e89a3f18fa4b76a59d115cc63255cc36ce6b273850509ba25031abca",
"zh:9c3e38ae7e670de973b6255d7050f526cd2b3ca7c383d7ba7226fc204d97c507",
"zh:d04b046023fa9fd69def678f27e001c298ea34fc99ba51f835cda82e496fdb57",
"zh:d9acd8810f6660cd51bb4c25596632984ae18e93340c82a102d074c6eac95151",
"zh:e161bcb9a22607270b980eeff2ba693335fb62d6978516dff93dd4c91cda99b3",
"zh:ef47502f08cfcb5311b7b16a7905e0052bf28359e07cc00ed080ef454e0946cf",
"zh:f0640ddb52e7e90c5006ff571f6ad0554e593665320c764c57a3d8b7ec31b490",
]
}

View file

@ -0,0 +1,32 @@
resource "google_project_service" "vertex_ai" {
project = var.project_id
service = "aiplatform.googleapis.com"
disable_on_destroy = false
}
resource "google_service_account" "agentgateway_vertex_ai" {
project = var.project_id
account_id = "********"
display_name = "Agentgateway Vertex AI"
}
resource "google_project_iam_member" "agentgateway_vertex_ai" {
project = var.project_id
role = "roles/aiplatform.user"
member = "serviceAccount:${google_service_account.agentgateway_vertex_ai.email}"
depends_on = [google_project_service.vertex_ai]
}
resource "google_service_account_key" "agentgateway_vertex_ai" {
service_account_id = google_service_account.agentgateway_vertex_ai.name
}
resource "vault_kv_secret_v2" "agentgateway_vertex_ai" {
mount = "secret"
name = "agentgateway/vertex-ai"
data_json = jsonencode({
credentials-json = base64decode(google_service_account_key.agentgateway_vertex_ai.private_key)
})
}

26
terraform/external/google/batch.tf vendored Normal file
View file

@ -0,0 +1,26 @@
data "google_project" "current" {
project_id = var.project_id
}
resource "google_storage_bucket" "batch" {
name = "${var.project_id}-vertex-batch"
location = "US-CENTRAL1"
uniform_bucket_level_access = true
public_access_prevention = "enforced"
soft_delete_policy {
retention_duration_seconds = 0
}
}
resource "google_storage_bucket_iam_member" "batch" {
bucket = google_storage_bucket.batch.name
role = "roles/storage.objectAdmin"
member = "serviceAccount:${google_service_account.agentgateway_vertex_ai.email}"
}
resource "google_storage_bucket_iam_member" "batch_vertex" {
bucket = google_storage_bucket.batch.name
role = "roles/storage.objectAdmin"
member = "serviceAccount:service-${data.google_project.current.number}@gcp-sa-aiplatform.iam.gserviceaccount.com"
}

Some files were not shown because too many files have changed in this diff Show more