diff --git a/hosts/daedalus/default.nix b/hosts/daedalus/default.nix index 8d2513f4..cae795c8 100644 --- a/hosts/daedalus/default.nix +++ b/hosts/daedalus/default.nix @@ -31,6 +31,8 @@ with lib.my; "ukelele" # "homebrew/cask-drivers/zsa-wally" "thunderbird" + "balenaetcher" + "audacity" "openlens" "ferdium" "discord" @@ -169,6 +171,7 @@ with lib.my; bitwarden-cli rustup + ffmpeg ]; }; diff --git a/hosts/picard/default.nix b/hosts/picard/default.nix index 57f6385d..7a2417b3 100644 --- a/hosts/picard/default.nix +++ b/hosts/picard/default.nix @@ -24,6 +24,7 @@ ../../nixos-modules/services/authelia.nix ../../nixos-modules/services/hedgedoc.nix ../../nixos-modules/services/ts3.nix + ../../nixos-modules/services/tailscale-openvpn.nix ../../nixos-modules/user ]; @@ -263,9 +264,17 @@ }; ragon = { + + agenix.secrets."ovpnNl" = { }; + agenix.secrets."ovpnDe" = { }; + agenix.secrets."ovpnTu" = { }; + agenix.secrets."ovpnCrt1" = { }; + agenix.secrets."ovpnPw1" = { }; + agenix.secrets."ovpnPw2" = { }; + agenix.secrets."tailscaleKey" = { }; user.enable = true; persist.enable = true; - persist.extraDirectories = [ "/srv/www" config.services.caddy.dataDir "/var/lib/syncthing" "/var/lib/${config.services.xynoblog.stateDirectory}" "/var/lib/postgresql" config.services.forgejo.stateDir ]; + persist.extraDirectories = [ "/var/lib/nixos-containers" "/srv/www" config.services.caddy.dataDir "/var/lib/syncthing" "/var/lib/${config.services.xynoblog.stateDirectory}" "/var/lib/postgresql" config.services.forgejo.stateDir ]; services = { caddy.enable = true; @@ -276,6 +285,16 @@ hedgedoc.enable = true; authelia.enable = true; ts3.enable = true; + tailscale-openvpn = { + enable = true; + tsAuthKey = config.age.secrets.tailscaleKey.path; + config = { + nl = config.age.secrets.ovpnNl.path; + de = config.age.secrets.ovpnDe.path; + tu = config.age.secrets.ovpnTu.path; + }; + }; + }; }; diff --git a/nixos-modules/services/tailscale-openvpn.nix b/nixos-modules/services/tailscale-openvpn.nix new file mode 100644 index 00000000..4509c743 --- /dev/null +++ b/nixos-modules/services/tailscale-openvpn.nix @@ -0,0 +1,93 @@ +{ options, config, lib, pkgs, ... }: +with lib; +{ + options.ragon.services.tailscale-openvpn = { + enable = mkEnableOption "Tailscale OpenVPN Bridge"; + config = mkOption { + type = types.attrsOf types.str; + }; + tsAuthKey = mkOption { type = types.str; }; + }; + config = + let + cfg = config.ragon.services.tailscale-openvpn; + bridgeExt = "br-ovpn-ext"; + container = server: "ovpn-${server}"; + bridge = server: "br-ovpn-${server}"; + in + mkIf cfg.enable + { + networking.bridges = { + ${bridgeExt}.interfaces = { }; + } // (mapAttrs + (server: _: { + name = bridge server; + value = { ipv4.addresses = [ ]; }; + }) + cfg.config); + networking.interfaces = { + ${bridgeExt}.ipv4.addresses = [{ address = "192.168.129.1"; prefixLength = 24; }]; + } // (optionalAttrs cfg.bridges + (mapAttrs + (server: _: { + name = bridge server; + value = { ipv4.addresses = [ ]; }; + }) + cfg.config + ) + ); + + networking.nat = { + enable = true; + internalInterfaces = [ bridgeExt ]; + }; + + + systemd.services = { + "container@".after = [ "network.target" ]; + } // (mapListToAttrs + (server: _: { + name = "container@${container server}"; + value = { requires = [ "network-addresses-${bridgeExt}.service" ]; }; + }) + cfg.config + ); + containers = imap0 + (i: v: { + name = v.name; + value = { + autoStart = true; + ephemeral = true; + enableTun = true; + privateNetwork = true; + hostBridge = bridgeExt; + localAddress = "192.168.129.${toString (i + 2)}/24"; + bindMounts = { + "/host/run" = { hostPath = "/run"; isReadOnly = true; }; + "/run/agenix.d" = { hostPath = "/run/agenix.d"; isReadOnly = true; }; + }; + config = { + services.openvpn.servers.${v.name} = { + config = '' + config ${v.value} + ''; + up = "echo nameserver $nameserver | ${pkgs.openresolv}/sbin/resolvconf -m 0 -a $dev"; + down = "${pkgs.openresolv}/sbin/resolvconf -d $dev"; + }; + services.tailscale = { + enable = true; + useRoutingFeatures = "server"; + extraUpFlags = [ "--advertise-exit-node" ]; + authKeyFile = cfg.tsAuthKey; + openFirewall = true; + }; + }; + + }; + }) + (nameValuePair cfg.config); + + + + }; +} diff --git a/secrets/ovpnCrt1.age b/secrets/ovpnCrt1.age new file mode 100644 index 00000000..14ec8abb Binary files /dev/null and b/secrets/ovpnCrt1.age differ diff --git a/secrets/ovpnDe.age b/secrets/ovpnDe.age new file mode 100644 index 00000000..a415d33f Binary files /dev/null and b/secrets/ovpnDe.age differ diff --git a/secrets/ovpnNl.age b/secrets/ovpnNl.age new file mode 100644 index 00000000..60d6bd5a Binary files /dev/null and b/secrets/ovpnNl.age differ diff --git a/secrets/ovpnPw1.age b/secrets/ovpnPw1.age new file mode 100644 index 00000000..75eda5ec --- /dev/null +++ b/secrets/ovpnPw1.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> ssh-ed25519 WceKOQ CVFVF1xOo2IQVAPHRG3ZQRZL7sFUD47WmBZbehCplBc +BOE58fJvBffvGIhpwowLbmjNGW7FExlUgPflBu9j0Io +-> ssh-ed25519 ugHWWw ZGWHrptykQ8hd/WGLAhRWDB5ApXpCZve1o7ybL1uSmM +PNWpNgHTSUBDFuCOtTf3B9ggWPekVCkz5pLtPB6YRzQ +-> ssh-ed25519 UU9RSA AVSSyjLC8iYIdJZzM93UkH4M4nTKJedN8f3AJzydMjM +A3uu+wM08CPueva8V0KrhxWznYQHqQ//xFjUanaZxwE +-> ssh-ed25519 RJI3BA kXVH/oYuxkZWL6Yu6NB/7nyTs6ZqLW8VUtsPVqp0GWU +VMsaYDUcGdwMvIaW1gBysLbpx5SHzPYpy18vt2h20KA +-> ssh-ed25519 XnvJKw GlO03p3pf3WV36WKNUSCbMSAHgvc2Y+2wo2soaCD/g4 +y+KikjwtlNJBXrqcVWrxVEGxj0RQJWXgmgDsnqdvQ64 +-> ssh-ed25519 7NL5Ng s9Um5T4QaOfxORcQ2bcipqC2evWlgYmmcDOost8ZcQc +Qfpel8aWbNDp352Re2FIcYsCYbEclhQnpWabA45Mr+g +--- LK7+9jw7wsPzO3vzf/4aG0TybkUQit+Z0/x5AipXt18 +o-FJsXA iT$pL*Udu \ No newline at end of file diff --git a/secrets/ovpnPw2.age b/secrets/ovpnPw2.age new file mode 100644 index 00000000..2ebfebbb Binary files /dev/null and b/secrets/ovpnPw2.age differ diff --git a/secrets/ovpnTu.age b/secrets/ovpnTu.age new file mode 100644 index 00000000..c91b67e8 Binary files /dev/null and b/secrets/ovpnTu.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 816a02ac..3190f8d4 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -47,4 +47,13 @@ in "autheliaJwtSecret.age".publicKeys = pubkeys.ragon.host "picard"; "autheliaEmail.age".publicKeys = pubkeys.ragon.host "picard"; "autheliaHedgedoc.age".publicKeys = pubkeys.ragon.host "picard"; + + # ovpn + "ovpnDe.age".publicKeys = pubkeys.ragon.host "picard"; + "ovpnNl.age".publicKeys = pubkeys.ragon.host "picard"; + "ovpnTu.age".publicKeys = pubkeys.ragon.host "picard"; + "ovpnCrt1.age".publicKeys = pubkeys.ragon.host "picard"; + "ovpnPw1.age".publicKeys = pubkeys.ragon.host "picard"; + "ovpnPw2.age".publicKeys = pubkeys.ragon.host "picard"; + }