diff --git a/.gitignore b/.gitignore index 704997f..2036315 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .terraform *.tfstate *.tfstate.backup +*.terraform.lock.hcl *.out *.backup secrets diff --git a/.terraform-version b/.terraform-version index 44ab23e..66c4c22 100644 --- a/.terraform-version +++ b/.terraform-version @@ -1 +1 @@ -0.11.13 +1.0.9 diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 0000000..69a00e4 --- /dev/null +++ b/HACKING.md @@ -0,0 +1,18 @@ +# Hacking on the thing + +Generate certs as per: + +https://gist.github.com/captn3m0/2c2e723b2dcd5cdaad733aad12be59a2 + +Copy ca.pem, server-cert.pem, server-key.pem to /etc/docker/certs. + +Make sure server-key.pem is 0400 in permissions. + +Run `systemctl edit docker` + +```` +/etc/systemd/system/docker.service.d/override.conf +[Service] +ExecStart= +ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/etc/docker/certs/ca.pem --tlscert=/etc/docker/certs/server-cert.pem --tlskey=/etc/docker/certs/server-key.pem -H=0.0.0.0:2376 -H unix:///var/run/docker.sock +```` diff --git a/cloudflare/main.tf b/cloudflare/main.tf index dbaec8e..bd6b637 100644 --- a/cloudflare/main.tf +++ b/cloudflare/main.tf @@ -4,18 +4,18 @@ */ resource "cloudflare_record" "home" { - domain = "${var.domain}" - name = "in" - value = "${var.ips["eth0"]}" - type = "A" + zone_id = var.zone_id + name = "in" + value = var.ips["eth0"] + type = "A" } resource "cloudflare_record" "home-wildcard" { - domain = "${var.domain}" - name = "*.in" - value = "${cloudflare_record.home.hostname}" - type = "CNAME" - ttl = 3600 + zone_id = var.zone_id + name = "*.in" + value = cloudflare_record.home.hostname + type = "CNAME" + ttl = 3600 } /** @@ -23,42 +23,42 @@ resource "cloudflare_record" "home-wildcard" { * *.bb8.fun -> bb8.fun */ resource "cloudflare_record" "internet" { - domain = "${var.domain}" - name = "@" - value = "${var.droplet_ip}" - type = "A" + zone_id = var.zone_id + name = "@" + value = var.droplet_ip + type = "A" } resource "cloudflare_record" "internet-wildcard" { - domain = "${var.domain}" - name = "*.${var.domain}" - value = "${cloudflare_record.internet.hostname}" - type = "CNAME" - ttl = 3600 + zone_id = var.zone_id + name = var.domain + value = cloudflare_record.internet.hostname + type = "CNAME" + ttl = 3600 } resource "cloudflare_record" "dns" { - domain = "${var.domain}" - name = "dns" - value = "${var.ips["static"]}" - type = "A" + zone_id = var.zone_id + name = "dns" + value = var.ips["static"] + type = "A" } resource "cloudflare_record" "doh" { - domain = "${var.domain}" - name = "doh" - value = "${var.ips["static"]}" - type = "A" + zone_id = var.zone_id + name = "doh" + value = var.ips["static"] + type = "A" } // This ensures that _acme-challenge is not a CNAME // alongside the above wildcard CNAME entry. resource "cloudflare_record" "acme-no-cname-1" { - domain = "${var.domain}" - name = "_acme-challenge.${var.domain}" - type = "A" - value = "127.0.0.1" - ttl = "300" + zone_id = var.zone_id + name = "_acme-challenge.${var.domain}" + type = "A" + value = "127.0.0.1" + ttl = "300" } /** @@ -66,18 +66,18 @@ resource "cloudflare_record" "acme-no-cname-1" { * *.vpn.bb8.fun */ resource "cloudflare_record" "vpn" { - domain = "${var.domain}" - name = "vpn" - value = "${var.ips["tun0"]}" - type = "A" + zone_id = var.zone_id + name = "vpn" + value = var.ips["tun0"] + type = "A" } resource "cloudflare_record" "vpn_wildcard" { - domain = "${var.domain}" - name = "*.vpn.${var.domain}" - value = "${cloudflare_record.vpn.hostname}" - type = "CNAME" - ttl = 3600 + zone_id = var.zone_id + name = "*.vpn.${var.domain}" + value = cloudflare_record.vpn.hostname + type = "CNAME" + ttl = 3600 } /** @@ -85,25 +85,25 @@ resource "cloudflare_record" "vpn_wildcard" { * *.vpn.bb8.fun */ resource "cloudflare_record" "dovpn" { - domain = "${var.domain}" - name = "dovpn" - value = "${var.ips["dovpn"]}" - type = "A" + zone_id = var.zone_id + name = "dovpn" + value = var.ips["dovpn"] + type = "A" } resource "cloudflare_record" "dovpn_wildcard" { - domain = "${var.domain}" - name = "*.dovpn.${var.domain}" - value = "${cloudflare_record.dovpn.hostname}" - type = "CNAME" - ttl = 3600 + zone_id = var.zone_id + name = "*.dovpn.${var.domain}" + value = cloudflare_record.dovpn.hostname + type = "CNAME" + ttl = 3600 } resource "cloudflare_record" "etcd" { - domain = "${var.domain}" - name = "etcd" - value = "${var.ips["dovpn"]}" - type = "A" + zone_id = var.zone_id + name = "etcd" + value = var.ips["dovpn"] + type = "A" } ######################## @@ -111,21 +111,21 @@ resource "cloudflare_record" "etcd" { ######################## resource "cloudflare_record" "mailgun-spf" { - domain = "${var.domain}" - name = "l" - value = "v=spf1 include:mailgun.org ~all" - type = "TXT" + zone_id = var.zone_id + name = "l" + value = "v=spf1 include:mailgun.org ~all" + type = "TXT" } resource "cloudflare_record" "mailgun-dkim" { - domain = "${var.domain}" - name = "k1._domainkey.l" - value = "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnbP+IQkuPkgmUhpqCKzIdDSZ0HazaMp+cdBH++LBed8oY8/jmV8BhxMp5JwyePzRTxneT8ASsRtcp7CQ3z4nMC7aFX0kH6Bnu2v+u2JWudxs8x0I02OrPbSaQ5QVQdbAaCUCEfCQ06LJsn8aqPNrRIOWEMnxln+ebFJ0wKGscFQIDAQAB" - type = "TXT" + zone_id = var.zone_id + name = "k1._domainkey.l" + value = "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnbP+IQkuPkgmUhpqCKzIdDSZ0HazaMp+cdBH++LBed8oY8/jmV8BhxMp5JwyePzRTxneT8ASsRtcp7CQ3z4nMC7aFX0kH6Bnu2v+u2JWudxs8x0I02OrPbSaQ5QVQdbAaCUCEfCQ06LJsn8aqPNrRIOWEMnxln+ebFJ0wKGscFQIDAQAB" + type = "TXT" } resource "cloudflare_record" "mailgun-mxa" { - domain = "${var.domain}" + zone_id = var.zone_id name = "l" value = "mxa.mailgun.org" type = "MX" @@ -133,7 +133,7 @@ resource "cloudflare_record" "mailgun-mxa" { } resource "cloudflare_record" "mailgun-mxb" { - domain = "${var.domain}" + zone_id = var.zone_id name = "l" value = "mxb.mailgun.org" type = "MX" @@ -141,9 +141,9 @@ resource "cloudflare_record" "mailgun-mxb" { } resource "cloudflare_record" "k8s" { - domain = "${var.domain}" - name = "k8s" - value = "10.8.0.1" - type = "A" - ttl = 3600 + zone_id = var.zone_id + name = "k8s" + value = "10.8.0.1" + type = "A" + ttl = 3600 } diff --git a/cloudflare/providers.tf b/cloudflare/providers.tf new file mode 100644 index 0000000..6d40668 --- /dev/null +++ b/cloudflare/providers.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + cloudflare = { + source = "cloudflare/cloudflare" + } + } +} diff --git a/cloudflare/variables.tf b/cloudflare/variables.tf index 6c1cb5e..c99a7d9 100644 --- a/cloudflare/variables.tf +++ b/cloudflare/variables.tf @@ -1,9 +1,10 @@ variable "domain" { - type = "string" + type = string } variable "ips" { - type = "map" + type = map } variable "droplet_ip" {} +variable "zone_id" {} diff --git a/data.tf b/data.tf index e45042d..952f3ae 100644 --- a/data.tf +++ b/data.tf @@ -1,3 +1,11 @@ data "docker_network" "bridge" { name = "bridge" } + +data "cloudflare_zones" "bb8" { + filter { + name = "bb8" + lookup_type = "exact" + match = "bb8.fun" + } +} diff --git a/db/network.tf b/db/network.tf index 72659f8..6593e41 100644 --- a/db/network.tf +++ b/db/network.tf @@ -8,3 +8,4 @@ resource "docker_network" "postgres" { gateway = "172.20.0.9" } } + diff --git a/db/outputs.tf b/db/outputs.tf index 0db41e2..400bd17 100644 --- a/db/outputs.tf +++ b/db/outputs.tf @@ -1,3 +1,4 @@ output "postgres-network-id" { - value = "${docker_network.postgres.name}" + value = docker_network.postgres.name } + diff --git a/db/postgres.tf b/db/postgres.tf index f56cb20..95ec82b 100644 --- a/db/postgres.tf +++ b/db/postgres.tf @@ -1,18 +1,18 @@ resource "docker_container" "postgres" { name = "postgres" - image = "${docker_image.postgres.latest}" + image = docker_image.postgres.latest volumes { - volume_name = "${docker_volume.postgres_volume.name}" + volume_name = docker_volume.postgres_volume.name container_path = "/var/lib/postgresql/data" - host_path = "${docker_volume.postgres_volume.mountpoint}" + host_path = docker_volume.postgres_volume.mountpoint } // This is so that other host-only services can share this ports { internal = 5432 external = 5432 - ip = "${var.ips["eth0"]}" + ip = var.ips["eth0"] } // This is a not-so-great idea @@ -20,7 +20,7 @@ resource "docker_container" "postgres" { ports { internal = 5432 external = 5432 - ip = "${var.ips["tun0"]}" + ip = var.ips["tun0"] } memory = 256 @@ -32,12 +32,12 @@ resource "docker_container" "postgres" { "POSTGRES_PASSWORD=${var.postgres-root-password}", ] - networks = ["${docker_network.postgres.id}", "${data.docker_network.bridge.id}"] + networks = [docker_network.postgres.id, data.docker_network.bridge.id] } resource "docker_image" "postgres" { - name = "${data.docker_registry_image.postgres.name}" - pull_triggers = ["${data.docker_registry_image.postgres.sha256_digest}"] + name = data.docker_registry_image.postgres.name + pull_triggers = [data.docker_registry_image.postgres.sha256_digest] } data "docker_registry_image" "postgres" { @@ -47,3 +47,4 @@ data "docker_registry_image" "postgres" { data "docker_network" "bridge" { name = "bridge" } + diff --git a/db/providers.tf b/db/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/db/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/db/variables.tf b/db/variables.tf index e57033a..d6424da 100644 --- a/db/variables.tf +++ b/db/variables.tf @@ -4,7 +4,9 @@ variable "postgres-version" { } variable "ips" { - type = "map" + type = map(string) +} + +variable "postgres-root-password" { } -variable "postgres-root-password" {} diff --git a/db/volumes.tf b/db/volumes.tf index 7c6a85c..b27958c 100644 --- a/db/volumes.tf +++ b/db/volumes.tf @@ -1,3 +1,4 @@ resource "docker_volume" "postgres_volume" { name = "postgres_volume" } + diff --git a/digitalocean/droplets.tf b/digitalocean/droplets.tf index 6c79fd8..5aafef1 100644 --- a/digitalocean/droplets.tf +++ b/digitalocean/droplets.tf @@ -1,5 +1,5 @@ resource "digitalocean_droplet" "sydney" { - image = "" + image = "??" name = "sydney.captnemo.in" region = "blr1" size = "s-1vcpu-2gb" @@ -18,5 +18,6 @@ resource "digitalocean_droplet" "sydney" { } output "droplet_ipv4" { - value = "${digitalocean_droplet.sydney.ipv4_address}" + value = digitalocean_droplet.sydney.ipv4_address } + diff --git a/digitalocean/firewall.tf b/digitalocean/firewall.tf index 919e8a9..ce4045b 100644 --- a/digitalocean/firewall.tf +++ b/digitalocean/firewall.tf @@ -1,38 +1,35 @@ resource "digitalocean_firewall" "web" { name = "web-inbound" - inbound_rule = [ - { - protocol = "tcp" - port_range = "80" - source_addresses = ["0.0.0.0/0", "::/0"] - }, - { - protocol = "tcp" - port_range = "443" - source_addresses = ["0.0.0.0/0", "::/0"] - }, - ] + inbound_rule { + protocol = "tcp" + port_range = "80" + source_addresses = ["0.0.0.0/0", "::/0"] + } + inbound_rule { + protocol = "tcp" + port_range = "443" + source_addresses = ["0.0.0.0/0", "::/0"] + } } resource "digitalocean_firewall" "ssh" { name = "ssh-inbound" - inbound_rule = [ - { - protocol = "tcp" - port_range = "22" - source_addresses = ["0.0.0.0/0", "::/0"] - }, - { - protocol = "tcp" - port_range = "222" - source_addresses = ["0.0.0.0/0", "::/0"] - }, - { - protocol = "tcp" - port_range = "24" - source_addresses = ["0.0.0.0/0", "::/0"] - }, - ] + inbound_rule { + protocol = "tcp" + port_range = "22" + source_addresses = ["0.0.0.0/0", "::/0"] + } + inbound_rule { + protocol = "tcp" + port_range = "222" + source_addresses = ["0.0.0.0/0", "::/0"] + } + inbound_rule { + protocol = "tcp" + port_range = "24" + source_addresses = ["0.0.0.0/0", "::/0"] + } } + diff --git a/digitalocean/networking.tf b/digitalocean/networking.tf index fcefd33..94b1672 100644 --- a/digitalocean/networking.tf +++ b/digitalocean/networking.tf @@ -1,4 +1,5 @@ resource "digitalocean_floating_ip" "sydney" { - droplet_id = "${digitalocean_droplet.sydney.id}" - region = "${digitalocean_droplet.sydney.region}" + droplet_id = digitalocean_droplet.sydney.id + region = digitalocean_droplet.sydney.region } + diff --git a/digitalocean/providers.tf b/digitalocean/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/digitalocean/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/docker/conf/traefik.toml b/docker/conf/traefik.toml index eb20faa..e5f2a69 100644 --- a/docker/conf/traefik.toml +++ b/docker/conf/traefik.toml @@ -38,33 +38,6 @@ checkNewVersion = false # Since I can't apply a authentication # on this yet -[backends.elibsrv] -[backends.elibsrv.servers.default] - url = "http://elibsrv.captnemo.in:90" - -[backends.scan] -[backends.scan.servers.default] - url = "http://scan.in.bb8.fun:90" - -[frontends] - -[frontends.scan] - backend = "scan" - [frontends.scan.headers] - SSLRedirect = true - SSLTemporaryRedirect = true - STSSeconds = 2592000 - FrameDeny = true - ContentTypeNosniff = true - BrowserXssFilter = true - ReferrerPolicy = "no-referrer" - [frontends.scan.headers.customresponseheaders] - X-Powered-By = "Allomancy" - Server = "BlackBox" - X-Clacks-Overhead = "GNU Terry Pratchett" -[frontends.scan.routes.domain] - rule = "Host:scan.bb8.fun" - [web] address = ":1111" readOnly = true diff --git a/docker/data.tf b/docker/data.tf index 7305e7b..d10d4a0 100644 --- a/docker/data.tf +++ b/docker/data.tf @@ -9,3 +9,4 @@ data "docker_registry_image" "ubooquity" { data "docker_registry_image" "lychee" { name = "linuxserver/lychee:latest" } + diff --git a/docker/got.tf b/docker/got.tf index aa9a553..f9b0328 100644 --- a/docker/got.tf +++ b/docker/got.tf @@ -6,22 +6,15 @@ data "docker_registry_image" "gotviz" { # name = "${data.docker_registry_image.gotviz.name}" # pull_triggers = ["${data.docker_registry_image.gotviz.sha256_digest}"] # } - - # resource "docker_container" "gotviz" { # name = "gotviz" # image = "${docker_image.gotviz.latest}" - - # labels = "${merge( # local.traefik_common_labels, map( # "traefik.port", 8080, # "traefik.frontend.rule","Host:got-relationships.${var.domain}" # ))}" - - # restart = "unless-stopped" # destroy_grace_seconds = 60 # must_run = true # } - diff --git a/docker/images.tf b/docker/images.tf index 583dc7b..73a2096 100644 --- a/docker/images.tf +++ b/docker/images.tf @@ -1,11 +1,11 @@ resource "docker_image" "traefik17" { - name = "${data.docker_registry_image.traefik.name}" - pull_triggers = ["${data.docker_registry_image.traefik.sha256_digest}"] + name = data.docker_registry_image.traefik.name + pull_triggers = [data.docker_registry_image.traefik.sha256_digest] } resource "docker_image" "ubooquity" { - name = "${data.docker_registry_image.ubooquity.name}" - pull_triggers = ["${data.docker_registry_image.ubooquity.sha256_digest}"] + name = data.docker_registry_image.ubooquity.name + pull_triggers = [data.docker_registry_image.ubooquity.sha256_digest] } # resource "docker_image" "lychee" { diff --git a/docker/locals.tf b/docker/locals.tf index fcdafc3..70ba788 100644 --- a/docker/locals.tf +++ b/docker/locals.tf @@ -1,20 +1,17 @@ locals { - traefik_common_labels { + traefik_common_labels = { "traefik.enable" = "true" - // HSTS "traefik.frontend.headers.SSLTemporaryRedirect" = "true" "traefik.frontend.headers.STSSeconds" = "2592000" "traefik.frontend.headers.STSIncludeSubdomains" = "false" - // X-Powered-By, Server headers - "traefik.frontend.headers.customResponseHeaders" = "${var.xpoweredby}" - + "traefik.frontend.headers.customResponseHeaders" = var.xpoweredby // X-Frame-Options - "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" + "traefik.frontend.headers.customFrameOptionsValue" = var.xfo_allow "traefik.frontend.headers.contentTypeNosniff" = "true" "traefik.frontend.headers.browserXSSFilter" = "true" - - "traefik.docker.network" = "traefik" + "traefik.docker.network" = "traefik" } } + diff --git a/docker/lychee.tf b/docker/lychee.tf index a2f0a9c..dedc70a 100644 --- a/docker/lychee.tf +++ b/docker/lychee.tf @@ -28,4 +28,3 @@ # ] # # links = ["${var.links-mariadb}"] # } - diff --git a/docker/main.tf b/docker/main.tf deleted file mode 100644 index 8b13789..0000000 --- a/docker/main.tf +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docker/network.tf b/docker/network.tf index c2b6e0a..908d003 100644 --- a/docker/network.tf +++ b/docker/network.tf @@ -3,3 +3,4 @@ resource "docker_network" "traefik" { driver = "bridge" internal = true } + diff --git a/docker/outputs.tf b/docker/outputs.tf index 99b17d9..ca08f80 100644 --- a/docker/outputs.tf +++ b/docker/outputs.tf @@ -3,13 +3,14 @@ # } output "names-traefik" { - value = "${docker_container.traefik.name}" + value = docker_container.traefik.name } output "traefik-network-id" { - value = "${docker_network.traefik.id}" + value = docker_network.traefik.id } output "auth-header" { - value = "${var.basic_auth}" + value = var.basic_auth } + diff --git a/docker/providers.tf b/docker/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/docker/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/docker/traefik.tf b/docker/traefik.tf index 4671ea7..a178342 100644 --- a/docker/traefik.tf +++ b/docker/traefik.tf @@ -1,70 +1,78 @@ resource "docker_container" "traefik" { name = "traefik" - image = "${docker_image.traefik17.latest}" + image = docker_image.traefik17.latest # Admin Backend ports { internal = 1111 external = 1111 - ip = "${var.ips["eth0"]}" + ip = var.ips["eth0"] } ports { internal = 1111 external = 1111 - ip = "${var.ips["tun0"]}" + ip = var.ips["tun0"] } # Local Web Server ports { internal = 80 external = 80 - ip = "${var.ips["eth0"]}" + ip = var.ips["eth0"] } # Local Web Server (HTTPS) ports { internal = 443 external = 443 - ip = "${var.ips["eth0"]}" + ip = var.ips["eth0"] } # Proxied via sydney.captnemo.in ports { internal = 443 external = 443 - ip = "${var.ips["tun0"]}" + ip = var.ips["tun0"] } ports { internal = 80 external = 80 - ip = "${var.ips["tun0"]}" + ip = var.ips["tun0"] } upload { - content = "${file("${path.module}/conf/traefik.toml")}" + content = file("${path.module}/conf/traefik.toml") file = "/etc/traefik/traefik.toml" } upload { - content = "${file("/home/nemo/projects/personal/certs/git.captnemo.in/fullchain.pem")}" - file = "/etc/traefik/git.captnemo.in.crt" + content = file( + "/home/nemo/projects/personal/certs/git.captnemo.in/fullchain.pem", + ) + file = "/etc/traefik/git.captnemo.in.crt" } upload { - content = "${file("/home/nemo/projects/personal/certs/git.captnemo.in/privkey.pem")}" - file = "/etc/traefik/git.captnemo.in.key" + content = file( + "/home/nemo/projects/personal/certs/git.captnemo.in/privkey.pem", + ) + file = "/etc/traefik/git.captnemo.in.key" } upload { - content = "${file("/home/nemo/projects/personal/certs/rss.captnemo.in/fullchain.pem")}" - file = "/etc/traefik/rss.captnemo.in.crt" + content = file( + "/home/nemo/projects/personal/certs/rss.captnemo.in/fullchain.pem", + ) + file = "/etc/traefik/rss.captnemo.in.crt" } upload { - content = "${file("/home/nemo/projects/personal/certs/rss.captnemo.in/privkey.pem")}" - file = "/etc/traefik/rss.captnemo.in.key" + content = file( + "/home/nemo/projects/personal/certs/rss.captnemo.in/privkey.pem", + ) + file = "/etc/traefik/rss.captnemo.in.key" } volumes { @@ -85,17 +93,16 @@ resource "docker_container" "traefik" { // `bridge` is auto-connected for now // https://github.com/terraform-providers/terraform-provider-docker/issues/10 - networks = [ - "${docker_network.traefik.id}", - "${data.docker_network.bridge.id}", - ] + networks_advanced { + name = "traefik" + } + + networks_advanced { + name = "bridge" + } env = [ "CLOUDFLARE_EMAIL=${var.cloudflare_email}", "CLOUDFLARE_API_KEY=${var.cloudflare_key}", ] } - -data "docker_network" "bridge" { - name = "bridge" -} diff --git a/docker/ubooquity.tf b/docker/ubooquity.tf index 1486d81..d0bc92d 100644 --- a/docker/ubooquity.tf +++ b/docker/ubooquity.tf @@ -1,6 +1,13 @@ +locals { + l = merge(local.traefik_common_labels, { + "traefik.port" = 3000 + "traefik.frontend.rule" = "Host:${var.domain}" + }) +} + resource "docker_container" "ubooquity" { name = "ubooquity" - image = "${docker_image.ubooquity.latest}" + image = docker_image.ubooquity.latest restart = "unless-stopped" destroy_grace_seconds = 30 @@ -25,32 +32,37 @@ resource "docker_container" "ubooquity" { host_path = "/mnt/xwing/media/EBooks/Comics" container_path = "/comics" } - labels { - "traefik.enable" = "true" - - "traefik.admin.port" = 2203 - "traefik.admin.frontend.rule" = "Host:library.${var.domain}" - - # I do not trust the Ubooquity authentication - # it does some shady JS encryption - "traefik.admin.frontend.auth.basic" = "${var.basic_auth}" - - "traefik.read.port" = 2202 - "traefik.read.frontend.rule" = "Host:read.${var.domain},comics.${var.domain},books.${var.domain}" - - "traefik.read.frontend.headers.SSLTemporaryRedirect" = "true" - "traefik.read.frontend.headers.STSSeconds" = "2592000" - "traefik.read.frontend.headers.STSIncludeSubdomains" = "false" - "traefik.read.frontend.headers.contentTypeNosniff" = "true" - "traefik.read.frontend.headers.browserXSSFilter" = "true" - "traefik.read.frontend.headers.customResponseHeaders" = "${var.xpoweredby}" - "traefik.frontend.headers.customFrameOptionsValue" = "${var.xfo_allow}" - "traefik.docker.network" = "traefik" + label = "traefik.enable" + value = "true" + } + labels { + label = "traefik.admin.port" + value = 2203 + } + labels { + label = "traefik.admin.frontend.rule" + value = "Host:library.${var.domain}" + } + labels { + label = "traefik.admin.frontend.auth.basic" + value = var.basic_auth + } + labels { + label = "traefik.read.port" + value = 2202 + } + labels { + label = "traefik.read.frontend.rule" + value = "Host:read.${var.domain},comics.${var.domain},books.${var.domain}" + } + labels { + label = "traefik.docker.network" + value = "traefik" } upload { - content = "${file("${path.module}/conf/ubooquity.json")}" + content = file("${path.module}/conf/ubooquity.json") file = "/config/preferences.json" } @@ -61,3 +73,4 @@ resource "docker_container" "ubooquity" { "MAXMEM=800", ] } + diff --git a/docker/variables.tf b/docker/variables.tf index bb8a347..9e73360 100644 --- a/docker/variables.tf +++ b/docker/variables.tf @@ -1,18 +1,18 @@ variable "web_username" { - type = "string" + type = string } variable "web_password" { - type = "string" + type = string } variable "cloudflare_key" { - type = "string" + type = string description = "cloudflare API Key" } variable "cloudflare_email" { - type = "string" + type = string description = "cloudflare email address" } @@ -39,15 +39,15 @@ variable "refpolicy" { } variable "wiki_session_secret" { - type = "string" + type = string } variable "domain" { - type = "string" + type = string } variable "ips" { - type = "map" + type = map(string) } # variable "links-mariadb" {} diff --git a/docker/volumes.tf b/docker/volumes.tf deleted file mode 100644 index 8b13789..0000000 --- a/docker/volumes.tf +++ /dev/null @@ -1 +0,0 @@ - diff --git a/echoserver.tf b/echoserver.tf index 23675cd..19bf136 100644 --- a/echoserver.tf +++ b/echoserver.tf @@ -1,11 +1,12 @@ module "echo-server" { - source = "modules/container" + source = "./modules/container" name = "echo-server" image = "jmalloc/echo-server:latest" - web { + web = { expose = "true" port = 8080 host = "debug.${var.root-domain},debug.in.${var.root-domain}" } } + diff --git a/elibsrv.tf b/elibsrv.tf index 3daa65e..ea771a5 100644 --- a/elibsrv.tf +++ b/elibsrv.tf @@ -1,14 +1,14 @@ module "elibsrv" { - name = "elibsrv" + name = "./elibsrv" source = "./modules/container" image = "captn3m0/elibsrv" - resource { + resource = { memory = 512 memory_swap = 512 } - web { + web = { expose = true host = "ebooks.${var.root-domain}" auth = true @@ -40,12 +40,6 @@ module "elibsrv" { "elibsrv_thumbheight=320", "elibsrv_title=Scarif Media Archives", ] - networks_advanced = [ - { - name = "traefik" - }, - { - name = "bridge" - }, - ] + networks = ["bridge"] } + diff --git a/firefox-sync.tf b/firefox-sync.tf index 5eb18e2..f79b6a9 100644 --- a/firefox-sync.tf +++ b/firefox-sync.tf @@ -4,21 +4,23 @@ module "firefox-sync" { image = "mozilla/syncserver:latest" // Default is port 80 - web { + web = { expose = true port = "5000" host = "firesync.${var.root-domain}" } - resource { + resource = { memory = "400" memory_swap = "400" } - volumes = [{ - host_path = "/mnt/xwing/data/firefox-sync" - container_path = "/data" - }] + volumes = [ + { + host_path = "/mnt/xwing/data/firefox-sync" + container_path = "/data" + }, + ] env = [ "SYNCSERVER_PUBLIC_URL=https://firesync.${var.root-domain}", @@ -29,12 +31,6 @@ module "firefox-sync" { "PORT=5000", ] - networks_advanced = [ - { - name = "traefik" - }, - { - name = "bridge" - }, - ] + networks = ["bridge"] } + diff --git a/gitea/conf/conf.ini.tpl b/gitea/conf/conf.ini.tpl index 838e864..fa21d27 100644 --- a/gitea/conf/conf.ini.tpl +++ b/gitea/conf/conf.ini.tpl @@ -137,7 +137,7 @@ ACTIVE_CODE_LIVE_MINUTES = 15 RESET_PASSWD_CODE_LIVE_MINUTES = 30 REGISTER_EMAIL_CONFIRM = true ENABLE_NOTIFY_MAIL = true -DISABLE_REGISTRATION = false +DISABLE_REGISTRATION = true ; ; Enable captcha validation for registration ENABLE_CAPTCHA = true REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA = true @@ -146,7 +146,7 @@ CAPTCHA_TYPE = image REQUIRE_SIGNIN_VIEW = false ; ; Default value for KeepEmailPrivate ; ; New user will get the value of this setting copied into their profile -DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_KEEP_EMAIL_PRIVATE = true ; ; Default value for AllowCreateOrganization ; ; New user will have rights set to create organizations depending on this setting DEFAULT_ALLOW_CREATE_ORGANIZATION = true @@ -249,7 +249,7 @@ SHOW_FOOTER_TEMPLATE_LOAD_TIME = false [openid] ENABLE_OPENID_SIGNIN = true -ENABLE_OPENID_SIGNUP = true +ENABLE_OPENID_SIGNUP = false [metrics] ; Enables metrics endpoint. True or false; default is false. diff --git a/gitea/data.tf b/gitea/data.tf index 8ca4074..61be64b 100644 --- a/gitea/data.tf +++ b/gitea/data.tf @@ -1,6 +1,6 @@ # https://github.com/go-gitea/gitea/releases data "docker_registry_image" "gitea" { - name = "gitea/gitea:1.14" + name = "gitea/gitea:1.15" } data "docker_registry_image" "redis" { @@ -8,14 +8,15 @@ data "docker_registry_image" "redis" { } data "template_file" "gitea-config-file" { - template = "${file("${path.module}/conf/conf.ini.tpl")}" + template = file("${path.module}/conf/conf.ini.tpl") - vars { - secret_key = "${var.secret-key}" - internal_token = "${var.internal-token}" - smtp_password = "${var.smtp-password}" - lfs-jwt-secret = "${var.lfs-jwt-secret}" - mysql-password = "${var.mysql-password}" - oauth2-jwt-secret = "${var.oauth2-jwt-secret}" + vars = { + secret_key = var.secret-key + internal_token = var.internal-token + smtp_password = var.smtp-password + lfs-jwt-secret = var.lfs-jwt-secret + mysql-password = var.mysql-password + oauth2-jwt-secret = var.oauth2-jwt-secret } } + diff --git a/gitea/main.tf b/gitea/main.tf index bc42154..267df3f 100644 --- a/gitea/main.tf +++ b/gitea/main.tf @@ -1,71 +1,74 @@ +locals { + l = merge(var.traefik-labels, { + "traefik.port" = 3000 + "traefik.frontend.rule" = "Host:${var.domain}" + }) +} + resource "docker_container" "gitea" { name = "gitea" - image = "${docker_image.gitea.latest}" + image = docker_image.gitea.latest - labels = "${merge( - var.traefik-labels, map( - "traefik.port", 3000, - "traefik.frontend.rule", "Host:${var.domain}" - ))}" + dynamic "labels" { + for_each = local.l + content { + label = labels.key + value = labels.value + } + } volumes { - volume_name = "${docker_volume.gitea_volume.name}" + volume_name = docker_volume.gitea_volume.name container_path = "/data" - host_path = "${docker_volume.gitea_volume.mountpoint}" + host_path = docker_volume.gitea_volume.mountpoint } # Logos # TODO: Add svg upload { - content = "${file("${path.module}/conf/public/img/gitea-lg.png")}" - file = "/data/gitea/public/img/gitea-lg.png" + content_base64 = filebase64("${path.module}/conf/public/img/gitea-lg.png") + file = "/data/gitea/public/img/gitea-lg.png" } upload { - content = "${file("${path.module}/conf/public/img/gitea-sm.png")}" - file = "/data/gitea/public/img/gitea-sm.png" + content_base64 = filebase64("${path.module}/conf/public/img/gitea-sm.png") + file = "/data/gitea/public/img/gitea-sm.png" } upload { - content = "${file("${path.module}/conf/public/img/gitea-sm.png")}" - file = "/data/gitea/public/img/favicon.png" - executable = false + content_base64 = filebase64("${path.module}/conf/public/img/gitea-sm.png") + file = "/data/gitea/public/img/favicon.png" + executable = false } upload { - content = "${file("${path.module}/../docker/conf/humans.txt")}" + content = file("${path.module}/../docker/conf/humans.txt") file = "/data/gitea/public/humans.txt" } upload { - content = "${file("${path.module}/conf/public/robots.txt")}" + content = file("${path.module}/conf/public/robots.txt") file = "/data/gitea/public/robots.txt" } + # Extra Links in header upload { - content = "${file("${path.module}/conf/extra_links.tmpl")}" + content = file("${path.module}/conf/extra_links.tmpl") file = "/data/gitea/templates/custom/extra_links.tmpl" } + # This is the main configuration file upload { - content = "${data.template_file.gitea-config-file.rendered}" + content = data.template_file.gitea-config-file.rendered file = "/data/gitea/conf/app.ini" } + memory = 800 restart = "always" destroy_grace_seconds = 10 must_run = true - networks = ["${docker_network.gitea.id}", "${var.traefik-network-id}"] - - # This doesn't work. - # See https://github.com/terraform-providers/terraform-provider-docker/issues/48 - # lifecycle { - # ignore_changes = [ - # "upload.2151376053.content", - # "upload.2151376053.executable", - # "upload.2151376053.file", - # ] - # } + networks = ["gitea", "traefik"] } resource "docker_image" "gitea" { - name = "${data.docker_registry_image.gitea.name}" - pull_triggers = ["${data.docker_registry_image.gitea.sha256_digest}"] + name = data.docker_registry_image.gitea.name + pull_triggers = [data.docker_registry_image.gitea.sha256_digest] } + diff --git a/gitea/mysql.tf b/gitea/mysql.tf deleted file mode 100644 index 8b13789..0000000 --- a/gitea/mysql.tf +++ /dev/null @@ -1 +0,0 @@ - diff --git a/gitea/network.tf b/gitea/network.tf index 9613ebe..142547d 100644 --- a/gitea/network.tf +++ b/gitea/network.tf @@ -2,3 +2,4 @@ resource "docker_network" "gitea" { name = "gitea" driver = "bridge" } + diff --git a/gitea/providers.tf b/gitea/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/gitea/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/gitea/redis.tf b/gitea/redis.tf index 6d3b06c..1d2751d 100644 --- a/gitea/redis.tf +++ b/gitea/redis.tf @@ -1,6 +1,6 @@ resource "docker_container" "redis" { name = "gitea-redis" - image = "${docker_image.redis.latest}" + image = docker_image.redis.latest volumes { host_path = "/mnt/xwing/cache/gitea" @@ -12,11 +12,12 @@ resource "docker_container" "redis" { destroy_grace_seconds = 10 must_run = true - networks = ["${docker_network.gitea.id}"] + networks = [docker_network.gitea.id] } resource "docker_image" "redis" { - name = "${data.docker_registry_image.redis.name}" - pull_triggers = ["${data.docker_registry_image.redis.sha256_digest}"] + name = data.docker_registry_image.redis.name + pull_triggers = [data.docker_registry_image.redis.sha256_digest] keep_locally = true } + diff --git a/gitea/variables.tf b/gitea/variables.tf index 5457f6f..b52b8f9 100644 --- a/gitea/variables.tf +++ b/gitea/variables.tf @@ -1,18 +1,32 @@ variable "traefik-labels" { - type = "map" + type = map(string) } -variable "domain" {} +variable "domain" { +} variable "ips" { - type = "map" + type = map(string) } -variable "secret-key" {} -variable "internal-token" {} -variable "smtp-password" {} -variable "lfs-jwt-secret" {} -variable "oauth2-jwt-secret" {} -variable "mysql-password" {} +variable "secret-key" { +} + +variable "internal-token" { +} + +variable "smtp-password" { +} + +variable "lfs-jwt-secret" { +} + +variable "oauth2-jwt-secret" { +} + +variable "mysql-password" { +} + +variable "traefik-network-id" { +} -variable "traefik-network-id" {} diff --git a/gitea/volume.tf b/gitea/volume.tf index 9cdc53e..7b83622 100644 --- a/gitea/volume.tf +++ b/gitea/volume.tf @@ -1,3 +1,4 @@ resource "docker_volume" "gitea_volume" { name = "gitea_volume" } + diff --git a/jupyter.tf b/jupyter.tf index 43cc05a..3deceed 100644 --- a/jupyter.tf +++ b/jupyter.tf @@ -10,4 +10,3 @@ # }, # ] # } - diff --git a/kaarana.tf b/kaarana.tf index e0fe45d..86f1615 100644 --- a/kaarana.tf +++ b/kaarana.tf @@ -1,15 +1,15 @@ # kaarana related stuff -module "kaarana" { - source = "./kaarana" +# module "kaarana" { +# source = "./kaarana" - root_db_password = "${data.pass_password.kaarana-root-db-password.password}" - db_password = "${data.pass_password.kaarana-db-password.password}" +# root_db_password = data.pass_password.kaarana-root-db-password.password +# db_password = data.pass_password.kaarana-db-password.password - providers = { - docker = "docker.sydney" - } -} +# providers = { +# docker = docker.sydney +# } +# } data "pass_password" "kaarana-root-db-password" { path = "KAARANA_DB_ROOT_PASSWORD" @@ -18,3 +18,4 @@ data "pass_password" "kaarana-root-db-password" { data "pass_password" "kaarana-db-password" { path = "KAARANA_DB_PASSWORD" } + diff --git a/kaarana/database.tf b/kaarana/database.tf index 17756db..d29ef83 100644 --- a/kaarana/database.tf +++ b/kaarana/database.tf @@ -18,7 +18,7 @@ resource "docker_network" "kaarana-db" { // Run a small mySQL container in this subnet resource "docker_container" "mysql" { - image = "${docker_image.db.latest}" + image = docker_image.db.latest name = "kaarana-mariadb" restart = "always" must_run = true @@ -35,8 +35,6 @@ resource "docker_container" "mysql" { container_path = "/var/lib/mysql" } - networks_advanced { - name = "kaarana-db" - aliases = ["${local.db_hostname}"] - } + networks = ["kaarana-db"] } + diff --git a/kaarana/images.tf b/kaarana/images.tf index f1e3e77..fd0df71 100644 --- a/kaarana/images.tf +++ b/kaarana/images.tf @@ -4,7 +4,7 @@ data "docker_registry_image" "wp" { resource "docker_image" "wp" { name = "wordpress" - pull_triggers = ["${data.docker_registry_image.wp.sha256_digest}"] + pull_triggers = [data.docker_registry_image.wp.sha256_digest] } data "docker_registry_image" "db" { @@ -13,7 +13,7 @@ data "docker_registry_image" "db" { resource "docker_image" "db" { name = "mariadb" - pull_triggers = ["${data.docker_registry_image.db.sha256_digest}"] + pull_triggers = [data.docker_registry_image.db.sha256_digest] } data "docker_registry_image" "traefik" { @@ -22,5 +22,6 @@ data "docker_registry_image" "traefik" { resource "docker_image" "traefik" { name = "traefik" - pull_triggers = ["${data.docker_registry_image.db.sha256_digest}"] + pull_triggers = [data.docker_registry_image.db.sha256_digest] } + diff --git a/kaarana/traefik.tf b/kaarana/traefik.tf index adf5ab0..2788b94 100644 --- a/kaarana/traefik.tf +++ b/kaarana/traefik.tf @@ -12,7 +12,7 @@ resource "docker_network" "traefik" { resource "docker_container" "traefik" { name = "traefik" - image = "${docker_image.traefik.latest}" + image = docker_image.traefik.latest # Do not offer HTTP2 # https://community.containo.us/t/traefikv2-http-2-0/1199 @@ -21,7 +21,7 @@ resource "docker_container" "traefik" { ] upload { - content = "${file("${path.module}/traefik.toml")}" + content = file("${path.module}/traefik.toml") file = "/etc/traefik/traefik.toml" } @@ -53,12 +53,12 @@ resource "docker_container" "traefik" { destroy_grace_seconds = 10 must_run = true - networks_advanced = [ - { - name = "bridge" - }, - { - name = "traefik" - }, - ] + networks_advanced { + name = "bridge" + } + + networks_advanced { + name = "traefik" + } } + diff --git a/kaarana/vars.tf b/kaarana/vars.tf index a826515..f3ec232 100644 --- a/kaarana/vars.tf +++ b/kaarana/vars.tf @@ -1,8 +1,12 @@ -variable "root_db_password" {} -variable "db_password" {} +variable "root_db_password" { +} + +variable "db_password" { +} locals { username = "wordpress" database = "wordpress" db_hostname = "kaarana.db" } + diff --git a/kaarana/wordpress.tf b/kaarana/wordpress.tf index d5483f3..e6b2843 100644 --- a/kaarana/wordpress.tf +++ b/kaarana/wordpress.tf @@ -1,18 +1,16 @@ resource "docker_container" "wp" { - image = "${docker_image.wp.latest}" + image = docker_image.wp.latest name = "kaarana-wordpress" restart = "always" must_run = true - labels { + labels = { "traefik.enable" = "true" "traefik.tcp.routers.kaarana.rule" = "HostSNI(`kaarana.captnemo.in`)" "traefik.tcp.routers.kaarana.tls" = "true" - # "traefik.tcp.routers.kaarana.tls.options" = "foo" "traefik.tcp.services.wordpress.loadbalancer.server.port" = "80" - # "traefik.tcp.routers.kaarana.entrypoints" = "web-secure" "traefik.tcp.routers.kaarana.tls.certResolver" = "default" "traefik.tcp.routers.kaarana.tls.domains[0].main" = "kaarana.captnemo.in" @@ -37,17 +35,6 @@ resource "docker_container" "wp" { ip = "10.8.0.1" } - networks_advanced = [ - { - name = "kaarana-db" - }, - { - // TODO: Once configuration/plugins have stabilized - // remove internet access from wordpress - name = "bridge" - }, - { - name = "traefik" - }, - ] + networks = ["bridge", "kaarana-db"] } + diff --git a/kayak.tf b/kayak.tf index 3b131b8..53e14da 100644 --- a/kayak.tf +++ b/kayak.tf @@ -39,4 +39,3 @@ # type = "A" # ttl = 120 # } - diff --git a/klaxon.tf b/klaxon.tf index d34deeb..47401ae 100644 --- a/klaxon.tf +++ b/klaxon.tf @@ -1,20 +1,20 @@ module "klaxon-db" { - source = "modules/postgres" + source = "./modules/postgres" name = "klaxon" - password = "${data.pass_password.klaxon-db-password.password}" + password = data.pass_password.klaxon-db-password.password } module "klaxon" { name = "klaxon" - source = "modules/container" + source = "./modules/container" - web { + web = { expose = true port = "3000" host = "klaxon.${var.root-domain}" } - resource { + resource = { memory = 1024 memory_swap = 1024 } @@ -29,18 +29,12 @@ module "klaxon" { "KLAXON_FORCE_SSL=false", "KLAXON_COMPILE_ASSETS=true", "ADMIN_EMAILS=klaxon@captnemo.in", - "MAILER_FROM_ADDRESS=klaxon@sendgrid.captnemo.in" + "MAILER_FROM_ADDRESS=klaxon@sendgrid.captnemo.in", ] restart = "always" image = "themarshallproject/klaxon" - networks_advanced = [ - { - name = "traefik" - }, { - name = "postgres" - }, { - name = "external" - }] + networks = ["postgres", "external"] } + diff --git a/kube-test.tf b/kube-test.tf index 89bb3a9..66bfa62 100644 --- a/kube-test.tf +++ b/kube-test.tf @@ -17,4 +17,3 @@ # } # } # } - diff --git a/main.tf b/main.tf index 29ea359..5a45435 100644 --- a/main.tf +++ b/main.tf @@ -1,96 +1,97 @@ module "cloudflare" { - source = "cloudflare" - domain = "bb8.fun" - ips = "${var.ips}" + source = "./cloudflare" + domain = "bb8.fun" + zone_id = lookup(data.cloudflare_zones.bb8.zones[0], "id") + ips = var.ips - droplet_ip = "${module.digitalocean.droplet_ipv4}" + droplet_ip = module.digitalocean.droplet_ipv4 } module "docker" { - source = "docker" - web_username = "${data.pass_password.web_username.password}" - web_password = "${data.pass_password.web_password.password}" - cloudflare_key = "${data.pass_password.cloudflare_key.password}" + source = "./docker" + web_username = data.pass_password.web_username.password + web_password = data.pass_password.web_password.password + cloudflare_key = data.pass_password.cloudflare_key.password cloudflare_email = "bb8@captnemo.in" - wiki_session_secret = "${data.pass_password.wiki_session_secret.password}" - ips = "${var.ips}" + wiki_session_secret = data.pass_password.wiki_session_secret.password + ips = var.ips domain = "bb8.fun" } module "db" { - source = "db" - postgres-root-password = "${data.pass_password.postgres-root-password.password}" - ips = "${var.ips}" + source = "./db" + postgres-root-password = data.pass_password.postgres-root-password.password + ips = var.ips } module "timemachine" { - source = "timemachine" - ips = "${var.ips}" + source = "./timemachine" + ips = var.ips username-1 = "vikalp" username-2 = "rishav" - password-1 = "${data.pass_password.timemachine-password-1.password}" - password-2 = "${data.pass_password.timemachine-password-2.password}" + password-1 = data.pass_password.timemachine-password-1.password + password-2 = data.pass_password.timemachine-password-2.password } module "gitea" { - source = "gitea" + source = "./gitea" domain = "git.captnemo.in" - traefik-labels = "${var.traefik-common-labels}" - ips = "${var.ips}" - secret-key = "${data.pass_password.gitea-secret-key.password}" - internal-token = "${data.pass_password.gitea-internal-token.password}" - smtp-password = "${data.pass_password.gitea-smtp-password.password}" - lfs-jwt-secret = "${data.pass_password.gitea-lfs-jwt-secret.password}" - oauth2-jwt-secret = "${data.pass_password.gitea-oauth2-jwt-secret.password}" + traefik-labels = var.traefik-common-labels + ips = var.ips + secret-key = data.pass_password.gitea-secret-key.password + internal-token = data.pass_password.gitea-internal-token.password + smtp-password = data.pass_password.gitea-smtp-password.password + lfs-jwt-secret = data.pass_password.gitea-lfs-jwt-secret.password + oauth2-jwt-secret = data.pass_password.gitea-oauth2-jwt-secret.password //passed, but not used mysql-password = "" - traefik-network-id = "${module.docker.traefik-network-id}" + traefik-network-id = module.docker.traefik-network-id } module "opml" { - source = "opml" + source = "./opml" domain = "opml.bb8.fun" - client-id = "${data.pass_password.opml-github-client-id.password}" - client-secret = "${data.pass_password.opml-github-client-secret.password}" - traefik-network-id = "${module.docker.traefik-network-id}" + client-id = data.pass_password.opml-github-client-id.password + client-secret = data.pass_password.opml-github-client-secret.password + traefik-network-id = module.docker.traefik-network-id } module "radicale" { - source = "radicale" + source = "./radicale" domain = "radicale.bb8.fun" } module "media" { - source = "media" + source = "./media" domain = "bb8.fun" - traefik-labels = "${var.traefik-common-labels}" - ips = "${var.ips}" - traefik-network-id = "${module.docker.traefik-network-id}" - lastfm_api_key = "${data.pass_password.navidrome-lastfm-api-key.password}" - lastfm_secret = "${data.pass_password.navidrome-lastfm-secret.password}" - spotify_id = "${data.pass_password.navidrome-spotify-id.password}" - spotify_secret = "${data.pass_password.navidrome-spotify-secret.password}" + traefik-labels = var.traefik-common-labels + ips = var.ips + traefik-network-id = module.docker.traefik-network-id + lastfm_api_key = data.pass_password.navidrome-lastfm-api-key.password + lastfm_secret = data.pass_password.navidrome-lastfm-secret.password + spotify_id = data.pass_password.navidrome-spotify-id.password + spotify_secret = data.pass_password.navidrome-spotify-secret.password } module "monitoring" { - source = "monitoring" - gf-security-admin-password = "${data.pass_password.gf-security-admin-password.password}" + source = "./monitoring" + gf-security-admin-password = data.pass_password.gf-security-admin-password.password domain = "bb8.fun" - transmission = "${module.media.names-transmission}" - traefik-labels = "${var.traefik-common-labels}" - ips = "${var.ips}" - links-traefik = "${module.docker.names-traefik}" - traefik-network-id = "${module.docker.traefik-network-id}" + transmission = module.media.names-transmission + traefik-labels = var.traefik-common-labels + ips = var.ips + links-traefik = module.docker.names-traefik + traefik-network-id = module.docker.traefik-network-id } module "digitalocean" { - source = "digitalocean" + source = "./digitalocean" } // Used to force access to ISP related resources # module "tinyproxy" { -# source = "tinyproxy" +# source = "./tinyproxy" # ips = "${var.ips}" # } diff --git a/media/airsonic.tf b/media/airsonic.tf index 90a36be..b0911c5 100644 --- a/media/airsonic.tf +++ b/media/airsonic.tf @@ -2,43 +2,34 @@ # source = "../modules/container" # image = "linuxserver/airsonic:latest" # name = "airsonic" - # resource { # memory = "1024" # memory_swap = "1024" # } - # web { # port = 4040 # host = "airsonic.bb8.fun" # expose = true # } - # networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" - # env = [ # "PUID=1004", # "PGID=1003", # "TZ=Asia/Kolkata", # "JAVA_OPTS=-Xmx512m -Dserver.use-forward-headers=true -Dserver.context-path=/", # ] - # devices = [{ # host_path = "/dev/snd" # container_path = "/dev/snd" # }] - # # files = [ # # "/usr/lib/jvm/java-1.8-openjdk/jre/lib/airsonic.properties", # # "/usr/lib/jvm/java-1.8-openjdk/jre/lib/sound.properties", # # ] - - # # contents = [ # # "${data.template_file.airsonic-properties-file.rendered}", # # "${file("${path.module}/conf/airsonic.sound.properties")}", # # ] - # volumes = [ # { # host_path = "/mnt/xwing/config/airsonic2" @@ -62,16 +53,10 @@ # }, # ] # } - # data "template_file" "airsonic-properties-file" { # template = "${file("${path.module}/conf/airsonic.properties.tpl")}" - - # vars { # smtp-password = "${var.airsonic-smtp-password}" - - # # db-password = "${var.airsonic-db-password}" # } # } - diff --git a/media/conf/transmission.json b/media/conf/transmission.json index 029c854..197afb7 100644 --- a/media/conf/transmission.json +++ b/media/conf/transmission.json @@ -11,7 +11,7 @@ "blocklist-enabled": true, "blocklist-url": "http://john.bitsurge.net/public/biglist.p2p.gz", "cache-size-mb": 16, - "dht-enabled": true, + "dht-enabled": false, "download-dir": "/downloads", "download-queue-enabled": true, "download-queue-size": 5, @@ -31,14 +31,14 @@ "peer-port-random-low": 49152, "peer-port-random-on-start": false, "peer-socket-tos": "default", - "pex-enabled": true, + "pex-enabled": false, "port-forwarding-enabled": true, "preallocation": 1, "prefetch-enabled": true, "queue-stalled-enabled": true, "queue-stalled-minutes": 30, "ratio-limit": 0.2, - "ratio-limit-enabled": true, + "ratio-limit-enabled": false, "rename-partial-files": true, "rpc-host-whitelist": "transmission.bb8.fun,transmission", "rpc-host-whitelist-enabled": true, diff --git a/media/data.tf b/media/data.tf index e45042d..247e9cc 100644 --- a/media/data.tf +++ b/media/data.tf @@ -1,3 +1,4 @@ data "docker_network" "bridge" { name = "bridge" } + diff --git a/media/emby.tf b/media/emby.tf index a27ceb4..9c673cd 100644 --- a/media/emby.tf +++ b/media/emby.tf @@ -1,6 +1,15 @@ + +locals { + emby_labels = merge(var.traefik-labels, { + "traefik.frontend.rule" = "Host:emby.in.${var.domain},emby.${var.domain}" + "traefik.frontend.passHostHeader" = "true" + "traefik.port" = 8096 + }) +} + resource "docker_container" "emby" { name = "emby" - image = "${docker_image.emby.latest}" + image = docker_image.emby.latest volumes { host_path = "/mnt/xwing/config/emby" @@ -12,36 +21,40 @@ resource "docker_container" "emby" { container_path = "/media" } - labels = "${merge( - var.traefik-labels, - map( - "traefik.frontend.rule", "Host:emby.in.${var.domain},emby.${var.domain}", - "traefik.frontend.passHostHeader", "true", - "traefik.port", 8096, - ))}" + dynamic "labels" { + for_each = local.emby_labels + content { + label = labels.key + value = labels.value + } + } - networks = ["${docker_network.media.id}", "${var.traefik-network-id}"] + networks = [docker_network.media.id, var.traefik-network-id] memory = 2048 restart = "unless-stopped" destroy_grace_seconds = 10 must_run = true + devices { + host_path = "/dev/dri" + container_path = "/dev/dri" + } + # Running as lounge:tatooine env = [ - "APP_USER=lounge", - "APP_UID=1004", - "APP_GID=1003", - "APP_CONFIG=/mnt/xwing/config", - "TZ=Asia/Kolkata", + "UID=1004", + "GID=1003", + "GIDLIST=1003" ] } resource "docker_image" "emby" { - name = "${data.docker_registry_image.emby.name}" - pull_triggers = ["${data.docker_registry_image.emby.sha256_digest}"] + name = data.docker_registry_image.emby.name + pull_triggers = [data.docker_registry_image.emby.sha256_digest] } data "docker_registry_image" "emby" { name = "emby/embyserver:latest" } + diff --git a/media/jackett.tf b/media/jackett.tf index 5ed6256..2c0916c 100644 --- a/media/jackett.tf +++ b/media/jackett.tf @@ -2,21 +2,23 @@ module "jackett" { name = "jackett" source = "../modules/container" image = "linuxserver/jackett:latest" + # TODO FIXME + # networks = [data.docker_network.bridge.id] - networks = "${list(data.docker_network.bridge.id)}" - - web { + web = { expose = true port = 9117 host = "jackett.${var.domain}" } - volumes = [{ - host_path = "/mnt/xwing/config/jackett" - container_path = "/config" - }] + volumes = [ + { + host_path = "/mnt/xwing/config/jackett" + container_path = "/config" + }, + ] - resource { + resource = { memory = "256" memory_swap = "512" } @@ -27,3 +29,4 @@ module "jackett" { "TZ=Asia/Kolkata", ] } + diff --git a/media/lidarr.tf b/media/lidarr.tf index c0e02fb..62e4ea6 100644 --- a/media/lidarr.tf +++ b/media/lidarr.tf @@ -3,19 +3,29 @@ data "docker_registry_image" "lidarr" { } resource "docker_image" "lidarr" { - name = "${data.docker_registry_image.lidarr.name}" - pull_triggers = ["${data.docker_registry_image.lidarr.sha256_digest}"] + name = data.docker_registry_image.lidarr.name + pull_triggers = [data.docker_registry_image.lidarr.sha256_digest] +} + +locals { + lidarr_labels = merge(var.traefik-labels, { + "traefik.port" = 8686 + "traefik.frontend.rule" = "Host:lidarr.${var.domain}" + }) } resource "docker_container" "lidarr" { name = "lidarr" - image = "${docker_image.lidarr.latest}" + image = docker_image.lidarr.latest + + dynamic "labels" { + for_each = local.lidarr_labels + content { + label = labels.key + value = labels.value + } + } - labels = "${merge( - var.traefik-labels, map( - "traefik.port", 8686, - "traefik.frontend.rule","Host:lidarr.${var.domain}" - ))}" memory = 512 restart = "unless-stopped" @@ -43,5 +53,6 @@ resource "docker_container" "lidarr" { "TZ=Asia/Kolkata", ] - networks = ["${docker_network.media.id}", "${var.traefik-network-id}"] + networks = [docker_network.media.id, var.traefik-network-id] } + diff --git a/media/navidrome.tf b/media/navidrome.tf index c2191b9..b1ff663 100644 --- a/media/navidrome.tf +++ b/media/navidrome.tf @@ -5,12 +5,12 @@ module "navidrome" { user = 1004 - resource { + resource = { memory = "1024" memory_swap = "1024" } - web { + web = { port = 4533 host = "music.bb8.fun" expose = true @@ -22,14 +22,14 @@ module "navidrome" { "ND_SESSIONTIMEOUT=300h", "ND_BASEURL=", "ND_AUTOIMPORTPLAYLISTS=false", - # "ND_UIWELCOMEMESSAGE=Welcome to Scarif Music Archives", "ND_LASTFM_APIKEY=${var.lastfm_api_key}", "ND_LASTFM_SECRET=${var.lastfm_secret}", "ND_SPOTIFY_ID=${var.spotify_id}", - "ND_SPOTIFY_SECRET=${var.spotify_secret}" + "ND_SPOTIFY_SECRET=${var.spotify_secret}", ] - networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" + # TODO FIXME + # networks = [docker_network.media.id, data.docker_network.bridge.id] volumes = [ { @@ -40,6 +40,7 @@ module "navidrome" { host_path = "/mnt/xwing/media/Music" container_path = "/music" read_only = true - } + }, ] } + diff --git a/media/network.tf b/media/network.tf index 4b3e8ff..8e09d28 100644 --- a/media/network.tf +++ b/media/network.tf @@ -7,3 +7,4 @@ resource "docker_network" "media" { gateway = "172.18.0.1" } } + diff --git a/media/outputs.tf b/media/outputs.tf index c9ec38f..b32f8dc 100644 --- a/media/outputs.tf +++ b/media/outputs.tf @@ -1,7 +1,8 @@ output "names-transmission" { - value = "${docker_container.transmission.name}" + value = docker_container.transmission.name } output "names-emby" { - value = "${docker_container.emby.name}" + value = docker_container.emby.name } + diff --git a/media/providers.tf b/media/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/media/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/media/radarr.tf b/media/radarr.tf index d7b7095..9ebffab 100644 --- a/media/radarr.tf +++ b/media/radarr.tf @@ -3,15 +3,16 @@ module "radarr" { source = "../modules/container" image = "linuxserver/radarr:latest" - networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" + # TODO FIXME + # networks = [docker_network.media.id, data.docker_network.bridge.id] - web { + web = { expose = true port = 7878 host = "radarr.${var.domain}" } - resource { + resource = { memory = 512 memory_swap = 1024 } @@ -37,3 +38,4 @@ module "radarr" { "TZ=Asia/Kolkata", ] } + diff --git a/media/requestrr.tf b/media/requestrr.tf index 560b821..0a3baf1 100644 --- a/media/requestrr.tf +++ b/media/requestrr.tf @@ -3,13 +3,13 @@ module "requestrr" { source = "../modules/container" image = "darkalfx/requestrr:latest" - web { + web = { expose = true port = 4545 host = "requestrr.${var.domain}" } - resource { + resource = { memory = 256 memory_swap = 256 } @@ -18,8 +18,10 @@ module "requestrr" { { host_path = "/mnt/xwing/config/requestrr" container_path = "/root/config" - } + }, ] - networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" + # TODO FIXME + # networks = [docker_network.media.id, data.docker_network.bridge.id] } + diff --git a/media/sonarr.tf b/media/sonarr.tf index 375b811..fb0e823 100644 --- a/media/sonarr.tf +++ b/media/sonarr.tf @@ -3,13 +3,13 @@ module "sonarr-container" { source = "../modules/container" image = "linuxserver/sonarr:latest" - web { + web = { expose = true port = 8989 host = "sonarr.${var.domain}" } - resource { + resource = { memory = 512 memory_swap = 1024 } @@ -35,5 +35,6 @@ module "sonarr-container" { "TZ=Asia/Kolkata", ] - networks = "${list(docker_network.media.id, data.docker_network.bridge.id)}" + networks = [docker_network.media.id, data.docker_network.bridge.id] } + diff --git a/media/transmission.tf b/media/transmission.tf index 197e92a..b030816 100644 --- a/media/transmission.tf +++ b/media/transmission.tf @@ -1,18 +1,26 @@ +locals { + transmission_labels = merge(var.traefik-labels, { + "traefik.frontend.auth.basic" = var.basic_auth + "traefik.port" = 9091 + }) +} + resource "docker_container" "transmission" { name = "transmission" - image = "${docker_image.transmission.latest}" + image = docker_image.transmission.latest - labels = "${merge( - var.traefik-labels, - map( - "traefik.frontend.auth.basic", "${var.basic_auth}", - "traefik.port", 9091, - ))}" + dynamic "labels" { + for_each = local.transmission_labels + content { + label = labels.key + value = labels.value + } + } ports { internal = 51413 external = 51413 - ip = "${var.ips["eth0"]}" + ip = var.ips["eth0"] protocol = "udp" } @@ -26,13 +34,18 @@ resource "docker_container" "transmission" { container_path = "/downloads" } + volumes { + host_path = "/mnt/xwing/media/Music/Audiobooks" + container_path = "/audiobooks" + } + volumes { host_path = "/mnt/xwing/data/watch/transmission" container_path = "/watch" } upload { - content = "${file("${path.module}/conf/transmission.json")}" + content = file("${path.module}/conf/transmission.json") file = "/config/settings.json" } @@ -42,7 +55,7 @@ resource "docker_container" "transmission" { "TZ=Asia/Kolkata", ] - networks = ["${docker_network.media.id}", "${var.traefik-network-id}"] + networks = [docker_network.media.id, var.traefik-network-id] memory = 1024 restart = "unless-stopped" @@ -51,10 +64,11 @@ resource "docker_container" "transmission" { } resource "docker_image" "transmission" { - name = "${data.docker_registry_image.transmission.name}" - pull_triggers = ["${data.docker_registry_image.transmission.sha256_digest}"] + name = data.docker_registry_image.transmission.name + pull_triggers = [data.docker_registry_image.transmission.sha256_digest] } data "docker_registry_image" "transmission" { name = "linuxserver/transmission:latest" } + diff --git a/media/variables.tf b/media/variables.tf index 06eb255..0ea39b0 100644 --- a/media/variables.tf +++ b/media/variables.tf @@ -1,11 +1,11 @@ variable "domain" { - type = "string" + type = string } # variable "airsonic-smtp-password" {} variable "traefik-labels" { - type = "map" + type = map(string) } // TODO: Remove duplication @@ -14,23 +14,29 @@ variable "basic_auth" { } variable "ips" { - type = "map" + type = map(string) +} + +variable "traefik-network-id" { } -variable "traefik-network-id" {} variable "lastfm_api_key" { description = "Navidrome Configuration for lastfm_api_key" - type = "string" + type = string } + variable "lastfm_secret" { description = "Navidrome Configuration for lastfm_secret" - type = "string" + type = string } + variable "spotify_id" { description = "Navidrome Configuration for spotify_id" - type = "string" + type = string } + variable "spotify_secret" { description = "Navidrome Configuration for spotify_secret" - type = "string" + type = string } + diff --git a/miniflux.tf b/miniflux.tf index b72ae8b..a4f74f1 100644 --- a/miniflux.tf +++ b/miniflux.tf @@ -1,19 +1,15 @@ module "miniflux-container" { name = "miniflux" - source = "modules/container" - image = "miniflux/miniflux:2.0.28" + source = "./modules/container" + image = "miniflux/miniflux:2.0.33" - web { + web = { expose = true port = 8080 host = "rss.captnemo.in" } - networks = "${list( - data.docker_network.bridge.id, - module.docker.traefik-network-id, - module.db.postgres-network-id - )}" + networks = ["bridge", "postgres"] env = [ "DATABASE_URL=postgres://miniflux:${data.pass_password.miniflux-db-password.password}@postgres/miniflux?sslmode=disable", @@ -22,7 +18,8 @@ module "miniflux-container" { } module "miniflux-db" { - source = "modules/postgres" + source = "./modules/postgres" name = "miniflux" - password = "${data.pass_password.miniflux-db-password.password}" + password = data.pass_password.miniflux-db-password.password } + diff --git a/modules/container/image.tf b/modules/container/image.tf new file mode 100644 index 0000000..9395802 --- /dev/null +++ b/modules/container/image.tf @@ -0,0 +1,9 @@ +data "docker_registry_image" "image" { + name = var.image +} + +resource "docker_image" "image" { + name = var.image + pull_triggers = [data.docker_registry_image.image.sha256_digest] + keep_locally = var.keep_image +} diff --git a/modules/container/locals.tf b/modules/container/locals.tf index 8d96c2e..4a107b4 100644 --- a/modules/container/locals.tf +++ b/modules/container/locals.tf @@ -1,36 +1,47 @@ locals { - default_labels { + default_labels = { "managed.by" = "nebula" } - web { - "traefik.port" = "${lookup(var.web, "port", "80")}" - "traefik.frontend.rule" = "Host:${lookup(var.web, "host", "example.invalid")}" - "traefik.protocol" = "${lookup(var.web, "protocol", "http")}" + web = { + "traefik.port" = var.web.port != null ? var.web.port : 80 + "traefik.frontend.rule" = var.web.host != null ? "Host:${var.web.host}" : "Host:example.invalid" + "traefik.protocol" = var.web.protocol != null ? var.web.protocol : "http" } - resource { - memory = "${lookup(var.resource, "memory", 64)}" - memory_swap = "${lookup(var.resource, "memory_swap", 128)}" - } - - traefik_common_labels { + traefik_common_labels = { "traefik.enable" = "true" - // HSTS "traefik.frontend.headers.SSLTemporaryRedirect" = "true" "traefik.frontend.headers.STSSeconds" = "2592000" "traefik.frontend.headers.STSIncludeSubdomains" = "false" - // X-Powered-By, Server headers - "traefik.frontend.headers.customResponseHeaders" = "${var.xpoweredby}" + "traefik.frontend.headers.customResponseHeaders" = var.xpoweredby "traefik.frontend.headers.contentTypeNosniff" = "true" "traefik.frontend.headers.browserXSSFilter" = "true" - - "traefik.docker.network" = "traefik" + "traefik.docker.network" = "traefik" } - traefik_auth_labels { - "traefik.frontend.auth.basic" = "${var.auth_header}" + # if var.web.auth == true + traefik_auth_labels = { + "traefik.frontend.auth.basic" = var.auth_header } + + resource = { + memory = lookup(var.resource, "memory", 64) + memory_swap = lookup(var.resource, "memory_swap", 128) + } + + labels = merge( + # Default labels are applied to every container + local.default_labels, + # Add the common traefik labels + var.web.expose ? local.traefik_common_labels : null, + # Apply the overwritten web labels only if the container is exposed + var.web.expose ? local.web : null, + # And finally a label for Basic Authentication if the service wants it + var.web.auth != null ? (var.web.auth ? local.traefik_auth_labels : null) : null, + ) + + networks = concat(var.networks, var.web.expose ? ["traefik"] : []) } diff --git a/modules/container/main.tf b/modules/container/main.tf index 4019398..ffa8e04 100644 --- a/modules/container/main.tf +++ b/modules/container/main.tf @@ -1,125 +1,82 @@ -data "docker_registry_image" "image" { - name = "${var.image}" -} - -resource "docker_image" "image" { - name = "${var.image}" - pull_triggers = ["${data.docker_registry_image.image.sha256_digest}"] - keep_locally = "${var.keep_image}" -} - -data "docker_network" "traefik" { - name = "traefik" -} - resource "docker_container" "container" { - name = "${var.name}" - image = "${docker_image.image.latest}" - ports = "${var.ports}" - restart = "${var.restart}" - env = ["${var.env}"] - command = "${var.command}" - entrypoint = "${var.entrypoint}" - user = "${var.user}" + name = var.name + image = docker_image.image.latest - network_mode = "${var.network_mode}" + dynamic "ports" { + for_each = var.ports + content { + external = ports.value.external + internal = ports.value.internal + ip = ports.value.ip + protocol = lookup(ports.value, "protocol", "tcp") + } + } + restart = var.restart + env = var.env + command = var.command + entrypoint = var.entrypoint + user = var.user - capabilities = ["${var.capabilities}"] + network_mode = var.network_mode - // Only attach the traefik network if - // service is exposed to the web - networks = ["${concat(var.networks,compact(split(",",lookup(var.web, "expose", "false") == "false" ? "" :"${data.docker_network.traefik.id}")))}"] + dynamic "capabilities" { + for_each = [var.capabilities] + content { + add = lookup(capabilities.value, "add", []) + drop = lookup(capabilities.value, "drop", []) + } + } - networks_advanced = ["${var.networks_advanced}"] + dynamic "networks_advanced" { + for_each = local.networks + content { + name = networks_advanced.value + } + } - memory = "${local.resource["memory"]}" - memory_swap = "${local.resource["memory_swap"]}" + memory = local.resource["memory"] + memory_swap = local.resource["memory_swap"] - volumes = ["${var.volumes}"] - devices = ["${var.devices}"] + dynamic "volumes" { + for_each = var.volumes + content { + container_path = lookup(volumes.value, "container_path", null) + from_container = lookup(volumes.value, "from_container", null) + host_path = lookup(volumes.value, "host_path", null) + read_only = lookup(volumes.value, "read_only", null) + volume_name = lookup(volumes.value, "volume_name", null) + } + } - upload = ["${var.uploads}"] + dynamic "devices" { + for_each = var.devices + content { + host_path = devices.value["host_path"] + container_path = devices.value["container_path"] + permissions = devices.value["permissions"] + } + } - # Look at this monstrosity - # And then https://github.com/hashicorp/terraform/issues/12453#issuecomment-365569618 - # for why this is needed + dynamic "upload" { + for_each = var.uploads + content { + file = lookup(upload.value, "file", null) + content = lookup(upload.value, "content", null) + content_base64 = lookup(upload.value, "content_base64", null) + executable = lookup(upload.value, "executable", null) + source = lookup(upload.value, "source", null) + source_hash = lookup(upload.value, "source_hash", null) + } + } - labels = "${merge(local.default_labels, - zipmap( - concat( - keys(local.default_labels), - split("~", - lookup(var.web, "expose", "false") == "false" ? - "" : - join("~", keys(local.traefik_common_labels)) - ) - ), - concat( - values(local.default_labels), - split("~", - lookup(var.web, "expose", "false") == "false" ? - "" : - join("~", values(local.traefik_common_labels)) - ) - ) - ), - zipmap( - concat( - keys(local.default_labels), - split("~", - lookup(var.web, "expose", "false") == "false" ? - "" : - join("~", keys(local.web)) - ) - ), - concat( - values(local.default_labels), - split("~", - lookup(var.web, "expose", "false") == "false" ? - "" : - join("~", values(local.web)) - ) - ) - ), + dynamic "labels" { + for_each = local.labels + content { + label = labels.key + value = labels.value + } + } - - zipmap( - concat( - keys(local.default_labels), - split("~", - lookup(var.web, "expose", "false") == "false" ? - "" : - join("~", keys(local.traefik_common_labels)) - ) - ), - concat( - values(local.default_labels), - split("~", - lookup(var.web, "expose", "false") == "false" ? - "" : - join("~", values(local.traefik_common_labels)) - ) - ) - ), - zipmap( - concat( - keys(local.default_labels), - split("~", - lookup(var.web, "auth", "false") == "false" ? - "" : - join("~", keys(local.traefik_auth_labels)) - ) - ), - concat( - values(local.default_labels), - split("~", - lookup(var.web, "auth", "false") == "false" ? - "" : - join("~", values(local.traefik_auth_labels)) - ) - ) - ) - )}" - destroy_grace_seconds = "${var.destroy_grace_seconds}" - must_run = "${var.must_run}" + destroy_grace_seconds = var.destroy_grace_seconds + must_run = var.must_run } diff --git a/modules/container/providers.tf b/modules/container/providers.tf new file mode 100644 index 0000000..c8e3cc2 --- /dev/null +++ b/modules/container/providers.tf @@ -0,0 +1,9 @@ +terraform { + experiments = [module_variable_optional_attrs] + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "2.15.0" + } + } +} diff --git a/modules/container/vars.tf b/modules/container/vars.tf index c64d63c..82c0239 100644 --- a/modules/container/vars.tf +++ b/modules/container/vars.tf @@ -8,19 +8,13 @@ variable "name" { variable "ports" { description = "list of port mappings" - type = "list" - default = [] -} - -variable "networks_advanced" { - description = "list of networks_advanced" - type = "list" + type = list(map(string)) default = [] } variable "networks" { - description = "list of networks" - type = "list" + description = "list of names of networks to attach to" + type = list(string) default = [] } @@ -32,7 +26,7 @@ variable "restart" { variable "must_run" { description = "If true, then the Docker container will be kept running. " default = "true" - type = "string" + type = string } variable "user" { @@ -43,7 +37,7 @@ variable "user" { variable "destroy_grace_seconds" { description = "Container will be destroyed after n seconds or on successful stop." default = 10 - type = "string" + type = string } variable "command" { @@ -61,10 +55,9 @@ variable "env" { default = [] } -variable "labels" { - description = "labels" - default = {} -} +# variable "labels" { +# description = "labels" +# } variable "xpoweredby" { default = "X-Powered-By:Allomancy||X-Server:Blackbox" @@ -72,10 +65,20 @@ variable "xpoweredby" { variable "web" { description = "Web Configuration" + type = object({ + expose = bool + auth = optional(bool) + port = optional(number) + host = optional(string) + protocol = optional(string) + }) default = { - expose = "false" - auth = "false" + expose = false + auth = false + port = 80 + host = "" + protocol = "http" } } @@ -95,20 +98,23 @@ variable "resource" { variable "volumes" { description = "volumes" - type = "list" - default = [] + default = {} } variable "capabilities" { description = "capabilities" - type = "list" - default = [] + + default = { + add = [] + drop = [] + } } variable "devices" { - description = "devices" - type = "list" - default = [] + description = "list of devices" + type = list(map(string)) + + default = [] } variable "keep_image" { @@ -117,5 +123,15 @@ variable "keep_image" { } variable "uploads" { + description = "Files to Upload" + type = list(object({ + file = string + content = optional(string) + content_base64 = optional(string) + executable = optional(bool) + source = optional(string) + source_hash = optional(string) + })) + default = [] } diff --git a/modules/image/main.tf b/modules/image/main.tf index 68eb353..cb6d11a 100644 --- a/modules/image/main.tf +++ b/modules/image/main.tf @@ -3,14 +3,15 @@ variable "image" { } data "docker_registry_image" "image" { - name = "${var.image}" + name = var.image } resource "docker_image" "image" { - name = "${data.docker_registry_image.image.name}" - pull_triggers = ["${data.docker_registry_image.image.sha256_digest}"] + name = data.docker_registry_image.image.name + pull_triggers = [data.docker_registry_image.image.sha256_digest] } output "image" { - value = "${docker_image.image.latest}" + value = docker_image.image.latest } + diff --git a/modules/postgres/main.tf b/modules/postgres/main.tf index a35ed91..ee31a8d 100644 --- a/modules/postgres/main.tf +++ b/modules/postgres/main.tf @@ -1,10 +1,11 @@ resource "postgresql_database" "db" { - name = "${var.name}" - owner = "${var.name}" + name = var.name + owner = var.name } resource "postgresql_role" "role" { - name = "${var.name}" + name = var.name login = true - password = "${var.password}" + password = var.password } + diff --git a/modules/postgres/providers.tf b/modules/postgres/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/modules/postgres/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/modules/postgres/vars.tf b/modules/postgres/vars.tf index 52cfbc8..9e7446e 100644 --- a/modules/postgres/vars.tf +++ b/modules/postgres/vars.tf @@ -1,9 +1,10 @@ variable "name" { description = "database/role name" - type = "string" + type = string } variable "password" { description = "role password" - type = "string" + type = string } + diff --git a/monitoring/act.tf b/monitoring/act.tf index b5c2e52..c27d865 100644 --- a/monitoring/act.tf +++ b/monitoring/act.tf @@ -4,7 +4,7 @@ data "docker_registry_image" "act-exporter" { resource "docker_container" "act-exporter" { name = "act-exporter" - image = "${docker_image.act-exporter.latest}" + image = docker_image.act-exporter.latest entrypoint = ["/usr/local/bin/node", "server.js"] @@ -14,11 +14,10 @@ resource "docker_container" "act-exporter" { } // So it can talk to ACT - networks_advanced { - name = "bridge" - } + networks = ["bridge"] restart = "unless-stopped" destroy_grace_seconds = 10 must_run = true } + diff --git a/monitoring/cadvisor.tf b/monitoring/cadvisor.tf index c7c1db2..ee326c0 100644 --- a/monitoring/cadvisor.tf +++ b/monitoring/cadvisor.tf @@ -3,7 +3,7 @@ module "cadvisor" { name = "cadvisor" image = "google/cadvisor:latest" - resource { + resource = { memory = 512 memory_swap = 512 } @@ -39,18 +39,12 @@ module "cadvisor" { }, ] - networks_advanced = [ - { - name = "traefik" - }, - { - name = "monitoring" - }, - ] + networks = ["monitoring"] - web { + web = { expose = true port = 8080 auth = true } } + diff --git a/monitoring/data.tf b/monitoring/data.tf index 1a5ae92..f26fcbc 100644 --- a/monitoring/data.tf +++ b/monitoring/data.tf @@ -1,3 +1,4 @@ data "docker_registry_image" "prometheus" { name = "prom/prometheus:latest" } + diff --git a/monitoring/grafana.tf b/monitoring/grafana.tf index c6519ef..03f6f10 100644 --- a/monitoring/grafana.tf +++ b/monitoring/grafana.tf @@ -7,32 +7,25 @@ module "grafana" { // grafana:grafana user = "984:982" - web { + web = { port = 3000 host = "grafana.${var.domain}" expose = true } - volumes = [{ - host_path = "/mnt/xwing/data/grafana" - container_path = "/var/lib/grafana" - }] - - networks_advanced = [ + volumes = [ { - name = "traefik" - }, - { - name = "monitoring" + host_path = "/mnt/xwing/data/grafana" + container_path = "/var/lib/grafana" }, ] + networks = ["monitoring"] + env = [ "GF_SERVER_ROOT_URL=https://grafana.${var.domain}", "GF_AUTH_ANONYMOUS_ENABLED=true", "GF_AUTH_ANONYMOUS_ORG_NAME=Tatooine", - - # Keep this disabled unless bringing up a new grafana instance "GF_SECURITY_ADMIN_PASSWORD=${var.gf-security-admin-password}", ] @@ -40,3 +33,4 @@ module "grafana" { destroy_grace_seconds = 10 must_run = true } + diff --git a/monitoring/images.tf b/monitoring/images.tf index 12fcfdc..1acfc35 100644 --- a/monitoring/images.tf +++ b/monitoring/images.tf @@ -1,10 +1,11 @@ resource "docker_image" "prometheus" { - name = "${data.docker_registry_image.prometheus.name}" - pull_triggers = ["${data.docker_registry_image.prometheus.sha256_digest}"] + name = data.docker_registry_image.prometheus.name + pull_triggers = [data.docker_registry_image.prometheus.sha256_digest] } resource "docker_image" "act-exporter" { - name = "${data.docker_registry_image.act-exporter.name}" - pull_triggers = ["${data.docker_registry_image.act-exporter.sha256_digest}"] + name = data.docker_registry_image.act-exporter.name + pull_triggers = [data.docker_registry_image.act-exporter.sha256_digest] keep_locally = true } + diff --git a/monitoring/network.tf b/monitoring/network.tf index aa53012..9c2cf51 100644 --- a/monitoring/network.tf +++ b/monitoring/network.tf @@ -3,3 +3,4 @@ resource "docker_network" "monitoring" { driver = "bridge" internal = true } + diff --git a/monitoring/nodeexporter.tf b/monitoring/nodeexporter.tf index c665f75..0739a8f 100644 --- a/monitoring/nodeexporter.tf +++ b/monitoring/nodeexporter.tf @@ -27,14 +27,17 @@ module "nodeexporter" { command = [ "--path.procfs=/host/proc", "--path.sysfs=/host/sys", - "--collector.filesystem.ignored-mount-points=\"^/(sys|proc|dev|host|etc)($$|/)\"", + "--collector.filesystem.ignored-mount-points=\"^/(sys|proc|dev|host|etc)($|/)\"", ] - networks = [ - "${docker_network.monitoring.id}", - ] + # TODO FIXME + + # networks = [ + # docker_network.monitoring.id, + # ] restart = "unless-stopped" destroy_grace_seconds = 10 must_run = true } + diff --git a/monitoring/prometheus.tf b/monitoring/prometheus.tf index 7875f63..1831270 100644 --- a/monitoring/prometheus.tf +++ b/monitoring/prometheus.tf @@ -1,6 +1,6 @@ resource "docker_container" "prometheus" { name = "prometheus" - image = "${docker_image.prometheus.latest}" + image = docker_image.prometheus.latest # prometheus:prometheus user = "985:983" @@ -8,13 +8,13 @@ resource "docker_container" "prometheus" { ports { internal = 9090 external = 8811 - ip = "${var.ips["eth0"]}" + ip = var.ips["eth0"] } ports { internal = 9090 external = 8811 - ip = "${var.ips["tun0"]}" + ip = var.ips["tun0"] } command = ["--config.file=/etc/prometheus/prometheus.yml"] @@ -25,22 +25,11 @@ resource "docker_container" "prometheus" { } upload { - content = "${file("${path.module}/config/prometheus.yml")}" + content = file("${path.module}/config/prometheus.yml") file = "/etc/prometheus/prometheus.yml" } - networks_advanced { - name = "monitoring" - } - - networks_advanced { - name = "bridge" - } - - networks = [ - "${data.docker_network.bridge.id}", - "${docker_network.monitoring.id}", - ] + networks = ["monitoring", "bridge"] restart = "unless-stopped" destroy_grace_seconds = 10 @@ -50,3 +39,4 @@ resource "docker_container" "prometheus" { data "docker_network" "bridge" { name = "bridge" } + diff --git a/monitoring/providers.tf b/monitoring/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/monitoring/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/monitoring/speedtest.tf b/monitoring/speedtest.tf index 0a0c11c..8b00a58 100644 --- a/monitoring/speedtest.tf +++ b/monitoring/speedtest.tf @@ -7,17 +7,9 @@ module "speedtest" { image = "captn3m0/speedtest-exporter:alpine" source = "../modules/container" - networks_advanced = [ - { - name = "monitoring" - aliases = ["speedtest", "speedtest.docker"] - }, - { - name = "bridge" - }, - ] + networks = ["monitoring"] - resource { + resource = { memory = 256 memory_swap = 256 } @@ -26,3 +18,4 @@ module "speedtest" { destroy_grace_seconds = 10 must_run = true } + diff --git a/monitoring/variables.tf b/monitoring/variables.tf index 57b0281..05deb6b 100644 --- a/monitoring/variables.tf +++ b/monitoring/variables.tf @@ -1,17 +1,17 @@ variable "gf-security-admin-password" { - type = "string" + type = string } variable "domain" { - type = "string" + type = string } variable "transmission" { - type = "string" + type = string } variable "links-traefik" { - type = "string" + type = string } variable "alert-slack-username" { @@ -31,11 +31,13 @@ variable "basic_auth" { } variable "traefik-labels" { - type = "map" + type = map(string) } variable "ips" { - type = "map" + type = map(string) +} + +variable "traefik-network-id" { } -variable "traefik-network-id" {} diff --git a/nextcloud.tf b/nextcloud.tf index 3ff3a20..7ad9f87 100644 --- a/nextcloud.tf +++ b/nextcloud.tf @@ -1,18 +1,20 @@ module "nextcloud-db" { - source = "modules/postgres" + source = "./modules/postgres" name = "nextcloud" - password = "${data.pass_password.nextcloud-db-password.password}" + password = data.pass_password.nextcloud-db-password.password } module "nextcloud-container" { - source = "modules/container" + source = "./modules/container" name = "nextcloud" image = "nextcloud:stable-apache" - volumes = [{ - container_path = "/var/www/html" - host_path = "/mnt/xwing/data/nextcloud" - }] + volumes = [ + { + container_path = "/var/www/html" + host_path = "/mnt/xwing/data/nextcloud" + }, + ] env = [ "POSTGRES_DB=nextcloud", @@ -24,28 +26,18 @@ module "nextcloud-container" { "REDIS_HOST=nextcloud-redis", ] - resource { + resource = { memory = 1024 memory_swap = 1024 } - web { + web = { expose = true port = 80 host = "c.${var.root-domain}" } - networks_advanced = [ - { - name = "traefik" - }, - { - name = "nextcloud" - }, - { - name = "postgres" - }, - ] + networks = ["nextcloud", "postgres"] } resource "docker_network" "nextcloud" { @@ -55,23 +47,15 @@ resource "docker_network" "nextcloud" { module "nextcloud-redis" { name = "nextcloud-redis" - source = "modules/container" + source = "./modules/container" image = "redis:alpine" keep_image = true - networks_advanced = [ - { - name = "nextcloud" - }, - ] + networks = ["nextcloud"] - # ThisSucks - web { - expose = "false" - } - - resource { + resource = { memory = 256 memory_swap = 256 } } + diff --git a/opml/main.tf b/opml/main.tf index dcf1b0f..437ce83 100644 --- a/opml/main.tf +++ b/opml/main.tf @@ -1,12 +1,13 @@ module "opml" { - name = "opml" - source = "../modules/container" - image = "captn3m0/opml-gen:latest" - networks = ["${docker_network.opml.id}", "${var.traefik-network-id}"] + name = "opml" + source = "../modules/container" + image = "captn3m0/opml-gen:latest" + # TODO FIXME + # networks = [docker_network.opml.id, var.traefik-network-id] - web { + web = { expose = true - host = "${var.domain}" + host = var.domain } env = [ @@ -15,8 +16,9 @@ module "opml" { "REDIS_URL=redis://opml-redis:6379/1", ] - resource { + resource = { memory = 256 memory_swap = 256 } } + diff --git a/opml/network.tf b/opml/network.tf index dc17e53..6d59776 100644 --- a/opml/network.tf +++ b/opml/network.tf @@ -2,3 +2,4 @@ resource "docker_network" "opml" { name = "opml" driver = "bridge" } + diff --git a/opml/providers.tf b/opml/providers.tf new file mode 100644 index 0000000..c8dd4a4 --- /dev/null +++ b/opml/providers.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } +} diff --git a/opml/redis.tf b/opml/redis.tf index f9c506c..74b77cb 100644 --- a/opml/redis.tf +++ b/opml/redis.tf @@ -1,17 +1,19 @@ module "redis" { - name = "opml-redis" - source = "../modules/container" - image = "redis:alpine" - networks = ["${docker_network.opml.id}"] + name = "opml-redis" + source = "../modules/container" + image = "redis:alpine" + # TODO FIXME + # networks = [docker_network.opml.id] keep_image = true # ThisSucks - web { + web = { expose = "false" } - resource { + resource = { memory = 256 memory_swap = 256 } } + diff --git a/opml/variables.tf b/opml/variables.tf index 98f8d60..23ea989 100644 --- a/opml/variables.tf +++ b/opml/variables.tf @@ -1,5 +1,12 @@ -variable "domain" {} -variable "client-id" {} -variable "client-secret" {} +variable "domain" { +} + +variable "client-id" { +} + +variable "client-secret" { +} + +variable "traefik-network-id" { +} -variable "traefik-network-id" {} diff --git a/providers.tf b/providers.tf index 5b660f3..160466a 100644 --- a/providers.tf +++ b/providers.tf @@ -1,41 +1,53 @@ provider "docker" { host = "tcp://docker.vpn.bb8.fun:2376" cert_path = "./secrets/tatooine" - version = "~> 2.2.0" + + } provider "docker" { host = "tcp://docker.dovpn.bb8.fun:2376" cert_path = "./secrets/sydney" - version = "~> 2.2.0" alias = "sydney" } -provider "kubernetes" { - # version = "1.3.0-custom" - host = "https://k8s.bb8.fun:6443" - - config_path = "${path.root}/k8s/auth/kubeconfig" -} - provider "cloudflare" { - email = "bb8@captnemo.in" - token = "${data.pass_password.cloudflare_key.password}" + email = "bb8@captnemo.in" + api_key = data.pass_password.cloudflare_key.password } provider "postgresql" { host = "postgres.vpn.bb8.fun" port = 5432 username = "postgres" - password = "${data.pass_password.postgres-root-password.password}" + password = data.pass_password.postgres-root-password.password sslmode = "disable" } provider "digitalocean" { - token = "${data.pass_password.digitalocean-token.password}" + token = data.pass_password.digitalocean-token.password } provider "pass" { - store_dir = "/home/nemo/.password-store/Nebula/" - refresh_store = false +} + + +terraform { + required_providers { + pass = { + source = "camptocamp/pass" + } + digitalocean = { + source = "digitalocean/digitalocean" + } + postgresql = { + source = "cyrilgdn/postgresql" + } + cloudflare = { + source = "cloudflare/cloudflare" + } + docker = { + source = "kreuzwerker/docker" + } + } } diff --git a/pulse.tf b/pulse.tf index 98c17bf..e022acc 100644 --- a/pulse.tf +++ b/pulse.tf @@ -21,4 +21,3 @@ # memory = 2048 # } # } - diff --git a/radicale/config b/radicale/config index 86d2d10..3a13e70 100644 --- a/radicale/config +++ b/radicale/config @@ -11,6 +11,10 @@ max_connections = 10 # Value: none | htpasswd | remote_user | http_x_remote_user type = htpasswd htpasswd_filename = /config/users +htpasswd_encryption = bcrypt + +# Message displayed in the client when a password is needed +realm = Authentication required [storage] filesystem_folder = /data/collections diff --git a/radicale/main.tf b/radicale/main.tf index 35c05d9..216c5f3 100644 --- a/radicale/main.tf +++ b/radicale/main.tf @@ -3,15 +3,18 @@ module "container" { source = "../modules/container" image = "tomsquest/docker-radicale:amd64" - resource { + resource = { memory = 2000 memory_swap = 2000 } - web { + # TODO Drop Capabilities + # https://github.com/tomsquest/docker-radicale#option-2-recommended-production-grade-instruction-secured-safe-rocket + + web = { expose = true port = 5232 - host = "${var.domain}" + host = var.domain } volumes = [ @@ -27,39 +30,15 @@ module "container" { uploads = [ { - content = <