From 2a2b98f3fef0777bf92b19d5d990c9f26458d3c1 Mon Sep 17 00:00:00 2001 From: Tine Date: Fri, 23 Aug 2024 22:03:47 +0200 Subject: [PATCH] feat: tailscale + dns --- configuration.nix | 26 +++++++++++++++++++-- justfile | 4 +++- terraform/dns.tf | 53 ++++++++++++++++++++++++++++++++++++++++++ terraform/node.tf | 31 +++++++++++++++++------- terraform/nodes.tf | 28 ---------------------- terraform/records.tf | 35 ---------------------------- terraform/terraform.tf | 3 +++ terraform/variables.tf | 4 ++++ 8 files changed, 110 insertions(+), 74 deletions(-) create mode 100644 terraform/dns.tf delete mode 100644 terraform/nodes.tf delete mode 100644 terraform/records.tf diff --git a/configuration.nix b/configuration.nix index 08c42f9..1bb4a51 100644 --- a/configuration.nix +++ b/configuration.nix @@ -6,7 +6,7 @@ ... }: let - ngx_http_geoip2_module = pkgs.stdenv.mkDerivation rec { + ngx_http_geoip2_module = pkgs.stdenv.mkDerivation { name = "ngx_http_geoip2_module-a28ceff"; src = pkgs.fetchgit { url = "https://github.com/leev/ngx_http_geoip2_module"; @@ -28,23 +28,45 @@ in # PROXMOX services.qemuGuest.enable = true; + services.cloud-init = { + enable = true; + }; # USER MANAGEMENT + # TODO: Should this be in cloud-init? nix.settings.trusted-users = [ "nixos" ]; users.users.nixos = { isNormalUser = true; + password = "nixos"; extraGroups = [ "wheel" ]; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICXAlzwziqfUUb2qmFwNF/nrBYc5MNT1MMOx81ohBmB+ tine@little.sys.tjo.space" ]; }; + security.sudo.wheelNeedsPassword = false; + + # SSH services.openssh = { enable = true; settings.PasswordAuthentication = false; settings.KbdInteractiveAuthentication = false; settings.PermitRootLogin = "no"; }; - security.sudo.wheelNeedsPassword = false; + + # TAILSCALE + services.tailscale = { + enable = true; + }; + + # FIREWALL + networking.firewall = { + enable = true; + + trustedInterfaces = [ "tailscale0" ]; + + allowedUDPPorts = [ config.services.tailscale.port ]; + allowedTCPPorts = [ 22 ]; + }; # NGINX services.nginx = { diff --git a/justfile b/justfile index 4cd66ab..43abb89 100644 --- a/justfile +++ b/justfile @@ -28,11 +28,13 @@ push: --upload-file $NIXOS_IMAGE \ https://code.tjo.space/api/packages/tjo-cloud/generic/ingress/${VERSION}/nixos.qcow2 -deploy: +deploy: build #!/usr/bin/env sh export NIXOS_IMAGE=$(nix path-info --quiet .#vm)/nixos.qcow2 export TF_VAR_image_path=$NIXOS_IMAGE + echo "Deploying $NIXOS_IMAGE" + cd {{justfile_directory()}}/terraform tofu init tofu apply diff --git a/terraform/dns.tf b/terraform/dns.tf new file mode 100644 index 0000000..72d7742 --- /dev/null +++ b/terraform/dns.tf @@ -0,0 +1,53 @@ +data "digitalocean_domain" "ingress" { + name = "ingress.tjo.cloud" +} + +resource "digitalocean_record" "public" { + for_each = merge( + { + for key, node in local.nodes_with_address : key => { + node = node.name, + ip = node.public_ipv4, + type = "A", + } + }, + { + for key, node in local.nodes_with_address : key => { + node = node.name, + ip = node.public_ipv6, + type = "AAAA", + } + } + ) + + domain = data.digitalocean_domain.ingress.id + type = each.value.type + name = lower(each.value.node) + value = each.value.ip + ttl = 60 +} + +resource "digitalocean_record" "internal" { + for_each = merge( + { + for key, node in local.nodes_with_address : key => { + node = node.name, + ip = node.internal_ipv4, + type = "A", + } + }, + { + for key, node in local.nodes_with_address : key => { + node = node.name, + ip = node.internal_ipv6, + type = "AAAA", + } + } + ) + + domain = data.digitalocean_domain.ingress.id + type = each.value.type + name = lower(each.value.node) + value = each.value.ip + ttl = 60 +} diff --git a/terraform/node.tf b/terraform/node.tf index 1ddc2af..d96e299 100644 --- a/terraform/node.tf +++ b/terraform/node.tf @@ -1,9 +1,9 @@ locals { nodes_with_names = { for k, v in var.nodes : k => merge(v, { - id = 700 + index(keys(var.nodes), k) - name = "${v.name}.ingress.tjo.cloud" - hash = sha1(v.name) + id = 700 + index(keys(var.nodes), k) + hostname = "${v.name}.ingress.tjo.cloud" + hash = sha1(v.name) }) } nodes = { @@ -28,12 +28,22 @@ locals { nodes_with_address = { for k, v in local.nodes : k => merge(v, { - ipv4 = local.ipv4_addresses[k]["eth0"][0] - ipv6 = local.ipv6_addresses[k]["eth0"][0] + public_ipv4 = local.ipv4_addresses[k]["eth0"][0] + public_ipv6 = local.ipv6_addresses[k]["eth0"][0] + internal_ipv4 = local.ipv4_addresses[k]["tailscale0"][0] + internal_ipv6 = local.ipv6_addresses[k]["tailscale0"][0] }) } } +resource "tailscale_tailnet_key" "ingress" { + reusable = true + ephemeral = true + preauthorized = true + tags = ["tag:ingress-tjo-cloud"] + description = "tailscale key for ingress-tjo-cloud nodes" +} + resource "proxmox_virtual_environment_file" "ingress" { content_type = "iso" datastore_id = var.common_storage @@ -54,9 +64,14 @@ resource "proxmox_virtual_environment_file" "cloudinit" { source_raw { data = <<-EOF - + #cloud-config + bootcmd: + - [ 'tailscale', 'up', '--authkey', '${tailscale_tailnet_key.ingress.key}', + '--hostname', '${each.value.name}', + '--accept-routes', 'true', + '--ssh' ] EOF - file_name = "${each.value.name}.cloudinit.yaml" + file_name = "${each.value.hostname}.cloudinit.yaml" } } @@ -64,7 +79,7 @@ resource "proxmox_virtual_environment_vm" "nodes" { for_each = local.nodes vm_id = each.value.id - name = each.value.name + name = each.value.hostname node_name = each.value.host description = "Node ${each.value.name} for ingress.tjo.cloud." diff --git a/terraform/nodes.tf b/terraform/nodes.tf deleted file mode 100644 index 40e7713..0000000 --- a/terraform/nodes.tf +++ /dev/null @@ -1,28 +0,0 @@ - -locals { - locations = { - DE = ["46.4.88.62", "2a01:4f8:202:2395::"] - SI = ["93.103.125.118", "2a01:261:455:6c00:21e:6ff:fe45:c34"] - } -} - -data "digitalocean_domain" "ingress" { - name = "ingress.tjo.cloud" -} - -resource "digitalocean_record" "locations" { - for_each = merge([ - for location, ips in local.locations : { - for ip in ips : "${location} at ${ip}" => { - location = location, - ip = ip, - } - } - ]...) - - domain = data.digitalocean_domain.ingress.id - type = strcontains(each.value.ip, ":") ? "AAAA" : "A" - name = lower(each.value.location) - value = each.value.ip - ttl = 60 -} diff --git a/terraform/records.tf b/terraform/records.tf deleted file mode 100644 index 5221de4..0000000 --- a/terraform/records.tf +++ /dev/null @@ -1,35 +0,0 @@ -locals { - listeners = [ - { - domain = "k8s.tjo.cloud" - name = "api" - locations = ["SI", "DE"] - }, - { - domain = "k8s.tjo.cloud" - name = "dashboard" - locations = ["SI", "DE"] - } - ] -} - -resource "digitalocean_record" "listeners" { - for_each = merge(flatten([ - for listener in local.listeners : - [ - for location in listener.locations : { - for ip in local.locations[location] : "${ip} for ${listener.name}.${listener.domain} at ${location}" => { - ip = ip - domain = listener.domain - name = listener.name - } - } - ] - ])...) - - domain = each.value.domain - type = strcontains(each.value.ip, ":") ? "AAAA" : "A" - name = each.value.name - value = each.value.ip - ttl = 60 -} diff --git a/terraform/terraform.tf b/terraform/terraform.tf index 88a9394..1295d39 100644 --- a/terraform/terraform.tf +++ b/terraform/terraform.tf @@ -25,6 +25,9 @@ provider "digitalocean" { token = var.digitalocean_token } +provider "tailscale" { + api_key = var.tailscale_apikey +} provider "proxmox" { # FIXME: Traefik/NGINX breaks this! 500 ERROR diff --git a/terraform/variables.tf b/terraform/variables.tf index fae3d30..2423ff1 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -27,6 +27,10 @@ variable "proxmox_token" { type = string } +variable "tailscale_apikey" { + type = string +} + variable "image_path" { type = string }