diff --git a/cloudflare/.terraform.lock.hcl b/cloudflare/.terraform.lock.hcl new file mode 100644 index 0000000..fc20846 --- /dev/null +++ b/cloudflare/.terraform.lock.hcl @@ -0,0 +1,35 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/cloudflare/cloudflare" { + version = "5.10.1" + constraints = "~> 5.0" + hashes = [ + "h1:fZArdZ2UjlXNHB4cEsnUKDRS1+rxX2MOauNC8SFarQo=", + "zh:0f127587ae7a20a3de23bbb05b0859eb3e418912a6e2adef95f53f225f4f9da1", + "zh:2ba095c6f7aa71fd140e0f57866b3a5b34152354f13de53f99037cc8386d9803", + "zh:2d46cc0bc820e455e6386e3cf834b5876f9cacc8554733fd61ce4c758ca43d81", + "zh:47b9996d6e99e4b9a26d390baaa1dcc2e5c846c6a1423c2aed1bc945c4f447ad", + "zh:97c49f130edaac5ed4c17bd93706be88d5061a80b77484ae2e8f83d25df9b8ba", + "zh:bd6af14ffdb1330eb8fd31a7b5e5362b08390bec53c75eda448203a473e5b36a", + "zh:f77a6cc61754ee4406c765f198d13a465f9457ed546749cd3f49b8fe8378dfab", + "zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32", + "zh:f9324dc4f2e0a2e6abcd9ecabdd0a09dbb00e4ad9aa24437dfe1ea7a219fb2c8", + ] +} + +provider "registry.opentofu.org/hashicorp/cloudflare" { + version = "5.10.1" + hashes = [ + "h1:fZArdZ2UjlXNHB4cEsnUKDRS1+rxX2MOauNC8SFarQo=", + "zh:0f127587ae7a20a3de23bbb05b0859eb3e418912a6e2adef95f53f225f4f9da1", + "zh:2ba095c6f7aa71fd140e0f57866b3a5b34152354f13de53f99037cc8386d9803", + "zh:2d46cc0bc820e455e6386e3cf834b5876f9cacc8554733fd61ce4c758ca43d81", + "zh:47b9996d6e99e4b9a26d390baaa1dcc2e5c846c6a1423c2aed1bc945c4f447ad", + "zh:97c49f130edaac5ed4c17bd93706be88d5061a80b77484ae2e8f83d25df9b8ba", + "zh:bd6af14ffdb1330eb8fd31a7b5e5362b08390bec53c75eda448203a473e5b36a", + "zh:f77a6cc61754ee4406c765f198d13a465f9457ed546749cd3f49b8fe8378dfab", + "zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32", + "zh:f9324dc4f2e0a2e6abcd9ecabdd0a09dbb00e4ad9aa24437dfe1ea7a219fb2c8", + ] +} diff --git a/cloudflare/README.md b/cloudflare/README.md new file mode 100644 index 0000000..a052594 --- /dev/null +++ b/cloudflare/README.md @@ -0,0 +1,13 @@ +# README + +## TODO +- don't forget to mention namecheap -> cloudflare NS +NS lloyd.ns.cloudflare.com +NS meadow.ns.cloudflare.com + +Create token +https://developers.cloudflare.com/fundamentals/api/get-started/account-owned-tokens/ + +Token access +Kostiantyn Bukliei - Cloudflare Tunnel:Edit, Zero Trust:Edit, Access: Apps and Policies:Edit + madunde.ad - DNS:Edit diff --git a/cloudflare/dns/main.tf b/cloudflare/dns/main.tf new file mode 100644 index 0000000..4d62438 --- /dev/null +++ b/cloudflare/dns/main.tf @@ -0,0 +1,20 @@ +# Root A Record +resource "cloudflare_dns_record" "root_dns_record" { + zone_id = var.cloudflare_zone_id + name = "madunde.ad" + ttl = 3600 + type = "A" + content = "193.93.217.193" + proxied = false +} + +# CNAME Records for each service declared in services module +resource "cloudflare_dns_record" "cname_record" { + for_each = var.services + zone_id = var.cloudflare_zone_id + name = "${each.value.subdomain}.madunde.ad" + content = "${var.cloudflare_tunnel_id}.cfargotunnel.com" + type = "CNAME" + ttl = 1 + proxied = true +} diff --git a/cloudflare/dns/variables.tf b/cloudflare/dns/variables.tf new file mode 100644 index 0000000..ed85d73 --- /dev/null +++ b/cloudflare/dns/variables.tf @@ -0,0 +1,17 @@ +variable "cloudflare_zone_id" { + description = "Cloudflare Zone ID" + type = string + sensitive = true +} + +variable "cloudflare_tunnel_id" { + description = "Cloudflare Zone ID" + type = string + sensitive = true +} + +variable "services" { + description = "TODO" + type = map(any) + sensitive = false +} diff --git a/cloudflare/main.tf b/cloudflare/main.tf new file mode 100644 index 0000000..f8ac370 --- /dev/null +++ b/cloudflare/main.tf @@ -0,0 +1,60 @@ +terraform { + required_providers { + cloudflare = { + source = "cloudflare/cloudflare" + version = "~> 5" + } + } +} + +provider "cloudflare" { + api_token = var.cloudflare_api_token +} + +module "services" { + source = "./services" +} + +module "dns" { + source = "./dns" + services = module.services.services + cloudflare_zone_id = var.cloudflare_zone_id + cloudflare_tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.ratchet_tunnel.id +} + +module "policies" { + source = "./policies" + cloudflare_zone_id = var.cloudflare_zone_id + cloudflare_account_id = var.cloudflare_account_id + cloudflare_email = var.cloudflare_email +} + +resource "cloudflare_zero_trust_tunnel_cloudflared" "ratchet_tunnel" { + account_id = var.cloudflare_account_id + tunnel_secret = var.cloudflared_tunnel_secret + name = "cloudflare > ratchet tunnel" + config_src = "cloudflare" +} + +resource "cloudflare_zero_trust_tunnel_cloudflared_config" "ratchet_tunnel_config" { + account_id = var.cloudflare_account_id + tunnel_id = cloudflare_zero_trust_tunnel_cloudflared.ratchet_tunnel.id + config = { + ingress = concat([for k, v in module.services.services : { hostname = "${v.subdomain}.madunde.ad", service = v.service }], [{ service = "http_status:404" }]) + } +} + +resource "cloudflare_zero_trust_access_application" "access_application" { + for_each = module.services.services + account_id = var.cloudflare_account_id + zone_id = var.cloudflare_zone_id + domain = "${each.value.subdomain}.madunde.ad" + type = "self_hosted" + name = "Access application for ${each.value.subdomain}.madunde.ad" + policies = [ + { + id = module.policies[each.value.policy].id + precedence = 1 + } + ] +} diff --git a/cloudflare/output.tf b/cloudflare/output.tf new file mode 100644 index 0000000..9906994 --- /dev/null +++ b/cloudflare/output.tf @@ -0,0 +1,5 @@ +output "tunnel_secret" { + description = "TODO" + value = cloudflare_zero_trust_tunnel_cloudflared.ratchet_tunnel.tunnel_secret + sensitive = true +} diff --git a/cloudflare/policies/main.tf b/cloudflare/policies/main.tf new file mode 100644 index 0000000..dd2b957 --- /dev/null +++ b/cloudflare/policies/main.tf @@ -0,0 +1,46 @@ +resource "cloudflare_zero_trust_list" "family_emails" { + account_id = var.cloudflare_account_id + name = "Me & Family" + type = "EMAIL" + items = [ + { + value = "madundead@gmail.com", + }, + { + value = "mail.elenka@gmail.com" + } + ] +} + +resource "cloudflare_zero_trust_access_policy" "allow_myself" { + account_id = var.cloudflare_account_id + name = "Allow myself, by OTP via email" + decision = "allow" + include = [ + { + email = { + email = var.cloudflare_email + } + } + ] +} + +resource "cloudflare_zero_trust_access_policy" "allow_myself_and_family" { + account_id = var.cloudflare_account_id + name = "Allow myself & Olena by OTP via email" + decision = "allow" + include = [ + { + email_list = cloudflare_zero_trust_list.family_emails + } + ] +} + +resource "cloudflare_zero_trust_access_policy" "allow_everyone" { + account_id = var.cloudflare_account_id + name = "Allow everyone" + decision = "bypass" + include = [{ + everyone = {} + }] +} diff --git a/cloudflare/policies/output.tf b/cloudflare/policies/output.tf new file mode 100644 index 0000000..19a7bf3 --- /dev/null +++ b/cloudflare/policies/output.tf @@ -0,0 +1,15 @@ +output "allow_myself" { + description = "TODO" + value = cloudflare_zero_trust_access_policy.allow_myself +} + +output "allow_myself_and_family" { + description = "TODO" + value = cloudflare_zero_trust_access_policy.allow_myself_and_family +} + + +output "allow_everyone" { + description = "TODO" + value = cloudflare_zero_trust_access_policy.allow_everyone +} diff --git a/cloudflare/policies/variables.tf b/cloudflare/policies/variables.tf new file mode 100644 index 0000000..b34d3af --- /dev/null +++ b/cloudflare/policies/variables.tf @@ -0,0 +1,14 @@ +variable "cloudflare_zone_id" { + type = string + sensitive = true +} + +variable "cloudflare_account_id" { + type = string + sensitive = true +} + +variable "cloudflare_email" { + type = string + sensitive = true +} diff --git a/cloudflare/services/output.tf b/cloudflare/services/output.tf new file mode 100644 index 0000000..99da9c4 --- /dev/null +++ b/cloudflare/services/output.tf @@ -0,0 +1,4 @@ +output "services" { + description = "TODO" + value = local.services +} diff --git a/cloudflare/services/services.tf b/cloudflare/services/services.tf new file mode 100644 index 0000000..3ba052c --- /dev/null +++ b/cloudflare/services/services.tf @@ -0,0 +1,14 @@ +locals { + services = { + homer = { + subdomain = "home" + service = "http://192.168.0.101:8888" + policy = "allow_myself_and_family" + }, + gitea = { + subdomain = "git" + service = "http://192.168.0.101:3000" + policy = "allow_everyone" + } + } +} diff --git a/cloudflare/variables.tf b/cloudflare/variables.tf new file mode 100644 index 0000000..8d32c73 --- /dev/null +++ b/cloudflare/variables.tf @@ -0,0 +1,27 @@ +variable "cloudflare_zone_id" { + description = "Zone ID for your domain" + type = string +} + +variable "cloudflare_account_id" { + description = "Account ID for your Cloudflare account" + type = string + sensitive = true +} + +variable "cloudflare_email" { + description = "Email address for your Cloudflare account" + type = string +} + +variable "cloudflare_api_token" { + description = "Cloudflare API token" + type = string + sensitive = true +} + +variable "cloudflared_tunnel_secret" { + description = "Cloudflare cloudflared auth secret" + type = string + sensitive = true +}