Adds terraform/edge, a root module with two providers: - Cloudflare 5.28.1: CNAMEs to the existing tunnel, plus an opt-in resource that can take the tunnel ingress list over when manage_tunnel_config is true. It is off by default because that resource REPLACES the whole list, and the tunnel is remotely managed from the dashboard today. - Tencent Cloud 1.83.38: VPC, subnet, security group with three rules, key pair, one CVM relay with cloud-init (WireGuard listener, forwarding sysctls, Caddy), and DNSPod A records for the .cn hostnames. The design keeps the homelab inbound-free: the relay terminates TLS in China and forwards over a WireGuard tunnel the cluster dials outbound. Cloudflare keeps serving every existing hostname untouched. Verified: terraform init succeeds for both providers, fmt clean, validate reports 0 errors, and plan resolves to 10 creates with placeholder variables. Provider-side name validation caught a real bug during that run: key pair and security group names allow only letters, digits and underscore, so the derived names use underscores. Not applied. Credentials come from CLOUDFLARE_API_TOKEN, TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY; the WireGuard private key is TF_VAR only. State is local and git-ignored like terraform/zitadel. Blocked on facts this module cannot invent: the real .cn domain, whether it has an ICP filing, the CVM image ID, the operator CIDR, and the homelab WireGuard public key.
137 lines
4.4 KiB
Terraform
137 lines
4.4 KiB
Terraform
variable "cloudflare_api_token" {
|
|
description = "Cloudflare API token with Zone:DNS:Edit and, for tunnel config, Account:Cloudflare Tunnel:Edit."
|
|
type = string
|
|
sensitive = true
|
|
default = null
|
|
}
|
|
|
|
variable "cloudflare_zone_id" {
|
|
description = "Zone ID of the existing public zone (riotpiao.com)."
|
|
type = string
|
|
}
|
|
|
|
variable "cloudflare_account_id" {
|
|
description = "Account ID. Required only when manage_tunnel_config is true."
|
|
type = string
|
|
default = null
|
|
}
|
|
|
|
variable "tunnel_id" {
|
|
description = "UUID of the cloudflared tunnel that the DNS records point at."
|
|
type = string
|
|
}
|
|
|
|
# The dashboard remains the source of truth for the remotely-managed tunnel
|
|
# today. Setting this true hands that config to Terraform, which then rewrites
|
|
# the whole ingress list: every hostname not listed in tunnel_ingress is
|
|
# removed from the tunnel. Import first and read the plan before applying.
|
|
variable "manage_tunnel_config" {
|
|
description = "Take ownership of the remotely-managed tunnel configuration."
|
|
type = bool
|
|
default = false
|
|
}
|
|
|
|
variable "tunnel_ingress" {
|
|
description = "hostname => origin service, used only when manage_tunnel_config is true."
|
|
type = map(string)
|
|
default = {}
|
|
}
|
|
|
|
# ── DNS records managed in the Cloudflare zone ───────────────────────────────
|
|
# These names already exist, created by hand in the dashboard. Adopt them with
|
|
# `terraform import` before the first apply, or Terraform will try to create a
|
|
# second record with the same name and Cloudflare will reject it.
|
|
variable "cloudflare_tunnel_hostnames" {
|
|
description = "Hostnames in the Cloudflare zone that must CNAME to the tunnel."
|
|
type = list(string)
|
|
default = []
|
|
}
|
|
|
|
# ── China edge ───────────────────────────────────────────────────────────────
|
|
variable "china_domain" {
|
|
description = "The .cn domain served from Tencent Cloud, without a trailing dot."
|
|
type = string
|
|
}
|
|
|
|
variable "china_hostnames" {
|
|
description = "Subdomains of china_domain that point at the Tencent relay."
|
|
type = list(string)
|
|
default = ["paperless", "img"]
|
|
}
|
|
|
|
variable "tencent_secret_id" {
|
|
description = "Tencent Cloud SecretId. Prefer TENCENTCLOUD_SECRET_ID in the environment."
|
|
type = string
|
|
sensitive = true
|
|
default = null
|
|
}
|
|
|
|
variable "tencent_secret_key" {
|
|
description = "Tencent Cloud SecretKey. Prefer TENCENTCLOUD_SECRET_KEY in the environment."
|
|
type = string
|
|
sensitive = true
|
|
default = null
|
|
}
|
|
|
|
variable "tencent_region" {
|
|
description = "Tencent Cloud region for the relay. Mainland regions need an ICP filing for the domain."
|
|
type = string
|
|
default = "ap-guangzhou"
|
|
}
|
|
|
|
variable "tencent_availability_zone" {
|
|
description = "Availability zone inside tencent_region."
|
|
type = string
|
|
default = "ap-guangzhou-6"
|
|
}
|
|
|
|
variable "relay_instance_type" {
|
|
description = "CVM spec for the relay. A relay only terminates TLS and forwards bytes."
|
|
type = string
|
|
default = "S5.SMALL2"
|
|
}
|
|
|
|
variable "relay_image_id" {
|
|
description = "CVM image ID. Find one with: tencentcloud images --image-name 'Ubuntu 24.04' (or the console)."
|
|
type = string
|
|
}
|
|
|
|
variable "relay_ssh_public_key" {
|
|
description = "Public key injected into the relay for break-glass SSH. Never the private key."
|
|
type = string
|
|
}
|
|
|
|
variable "relay_admin_cidr" {
|
|
description = "CIDR allowed to reach SSH on the relay. Keep it to the operator, not 0.0.0.0/0."
|
|
type = string
|
|
}
|
|
|
|
variable "wireguard_port" {
|
|
description = "UDP port of the WireGuard listener on the relay."
|
|
type = number
|
|
default = 51820
|
|
}
|
|
|
|
variable "wireguard_relay_private_key" {
|
|
description = "WireGuard private key of the relay side. Generate with `wg genkey`; pass via TF_VAR_wireguard_relay_private_key."
|
|
type = string
|
|
sensitive = true
|
|
}
|
|
|
|
variable "wireguard_homelab_public_key" {
|
|
description = "WireGuard public key of the homelab peer that dials the relay."
|
|
type = string
|
|
}
|
|
|
|
variable "wireguard_relay_address" {
|
|
description = "Tunnel address of the relay side."
|
|
type = string
|
|
default = "10.88.0.1/24"
|
|
}
|
|
|
|
variable "wireguard_homelab_address" {
|
|
description = "Tunnel address of the homelab side."
|
|
type = string
|
|
default = "10.88.0.2/24"
|
|
}
|