ce7cb702218693d08ea6d83464d2457c9250027c
This commit is contained in:
commit
34c5f8963c
7 changed files with 145336 additions and 0 deletions
63
terraform/external/cloudflare-tunnel/.terraform.lock.hcl
generated
vendored
Normal file
63
terraform/external/cloudflare-tunnel/.terraform.lock.hcl
generated
vendored
Normal 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",
|
||||
]
|
||||
}
|
||||
126
terraform/external/cloudflare-tunnel/cache.tf
vendored
Normal file
126
terraform/external/cloudflare-tunnel/cache.tf
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
74
terraform/external/cloudflare-tunnel/main.tf
vendored
Normal file
74
terraform/external/cloudflare-tunnel/main.tf
vendored
Normal 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
|
||||
}
|
||||
19
terraform/external/cloudflare-tunnel/outputs.tf
vendored
Normal file
19
terraform/external/cloudflare-tunnel/outputs.tf
vendored
Normal 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
|
||||
}
|
||||
61
terraform/external/cloudflare-tunnel/providers.tf
vendored
Normal file
61
terraform/external/cloudflare-tunnel/providers.tf
vendored
Normal 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"]
|
||||
}
|
||||
47
terraform/external/cloudflare-tunnel/variables.tf
vendored
Normal file
47
terraform/external/cloudflare-tunnel/variables.tf
vendored
Normal 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"
|
||||
}
|
||||
21
terraform/external/cloudflare-tunnel/waf.tf
vendored
Normal file
21
terraform/external/cloudflare-tunnel/waf.tf
vendored
Normal 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
|
||||
},
|
||||
]
|
||||
}
|
||||
Loading…
Reference in a new issue