From 37fdae42d289909e3d96fd0231ef7da333411fbf Mon Sep 17 00:00:00 2001 From: Lucy Hochkamp Date: Tue, 2 Apr 2024 15:30:58 +0200 Subject: [PATCH] this will explode --- hosts/daedalus/default.nix | 3 + hosts/picard/default.nix | 21 ++++- nixos-modules/services/tailscale-openvpn.nix | 93 +++++++++++++++++++ secrets/ovpnCrt1.age | Bin 0 -> 2949 bytes secrets/ovpnDe.age | Bin 0 -> 1587 bytes secrets/ovpnNl.age | Bin 0 -> 1316 bytes secrets/ovpnPw1.age | 15 +++ secrets/ovpnPw2.age | Bin 0 -> 793 bytes secrets/ovpnTu.age | Bin 0 -> 2632 bytes secrets/secrets.nix | 9 ++ 10 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 nixos-modules/services/tailscale-openvpn.nix create mode 100644 secrets/ovpnCrt1.age create mode 100644 secrets/ovpnDe.age create mode 100644 secrets/ovpnNl.age create mode 100644 secrets/ovpnPw1.age create mode 100644 secrets/ovpnPw2.age create mode 100644 secrets/ovpnTu.age 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 0000000000000000000000000000000000000000..14ec8abba9b62c70304ebc7235af01674d2c5185 GIT binary patch literal 2949 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 literal 0 HcmV?d00001 diff --git a/secrets/ovpnDe.age b/secrets/ovpnDe.age new file mode 100644 index 0000000000000000000000000000000000000000..a415d33fcc4e1bac959b8502c033500b2dfe8512 GIT binary patch literal 1587 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCR+Pfqpr4^$`!a5OW} z4-3vnEi4O+NDIzPsWM1(4fpo9sM0peaJS6VHV(^lN()POj^uKw^vriE$V$w0j&RM+ z%t|-0@Ql=UcQeoPvGme5OUudgG|UW0EH{oaG(oqmG~FXSyj&qSDWI&>H7qA2+uX_1 zzu2|hD9H6Z+^5pG zD9|lCH@C7XILoZEI4HfcytE+C)fL^g&``^uU`K`0G{3ww7i~}N{PX~m$l}Nd?GV4@ z$P|krv+%qWi^@{}()5rppQ2pnJWsB|@QN(Ah*A?5V;_&;98c}w5`CwrBBK(^tU#Zj z0;BAd025E&uy9ACD?KgBEV9BA(~T@GOe}o;0(`YSl2Y9~ zy(*oZJrm8d%yZpb+>^NqiZY$O{7an*_0ux7%iK*foju&Lvdbef-Kt7FocvQNEzBH! z!%I9OvmMcGi^wbU@-9~hbImc-56N}+^fPpiN+~uDD$a;0g1F$wkYbI%Bj zGA&3k4bJ9raSZe+G%ZarDJ?Uqa4mPt%E|Q0FU=}1N(?a0bxSKUGs()2@=Z%J*ET@6 z&D_t&)GuAZCE3}?$JaYqzp|<#)w3|q!!X0irPRONwbU!P)WgdotkASP(9Fl#*D0SX zDc>@s$T-ujDBC?TEIB0E+oi%H(m3Bg$~i#4B)25rq_W5}#L_*|F({u)S65dd#XQj@ zFRCotFsLxx*~h>yI4Z~0A~VI@(97M>DN(!1(E)|&T9QYdSXuouyf8pzc<}K-;(+_ln zrWz|P+qPx;%DVb$IjOISXB=aNR!pBQBN1TY6C>NP`b-r6f^BXKCrO7y-aRiU^r}zx zWQ0p(<9n~H(hM!9S=qBRS{=>j&(ibb*m~J|J!kdvU*bLY78*=C{rL2eYD2Y9lb1Ut zv3edaSm~Rxsk+Sn%-rv<>cZG`_FUd`==h>v;e69X1t;da?q$Ed_s$-Bo*R=4A3kon zwyfak>Bo7dU)gOeYV2z+2Sn*rybn0G_f6ZS(@TDRob@FrF(LizZWRF&rf$cd4+ZCh zzf-%ee|A@JL^I>6?duXnjhnAN>wN3K@u+Rv2Yf1)R*&)aLw>`%x_JN^DkY3J&W9TLJTo?nwYHpN%{?Gh8Oqj}Ftg9`O7yfry+Z(jYOy0?Xw z?=T#?IB)Ls*1DwP*(VwEFQ$d4&pY@(_d~aKp3&!RaI7hq8`E7rJv z!$a3i&3y)6Lras)SEx4x9q^lS^uK$P>U*X0vFla~E1q1PeA=Y{^i|KtVVCSX_Gn9L z%=$JhZBJo=_&uE!vwO?7)iG8SaxB)KxZ~^oiHG05?%uw$(;^iw0^B?btzOTG@liQyC=M^TjU*P>! zx&Eoxx8C;or}G1}qgOHT+{~KvV#zVN4SSBtRF{8TTABQ$^4jYQ&swX$+v%0w67p2I z5^gzft<&2xh5_r}?%!7x_S{=kAj%VQZ&8@%?@>ZP)h~vUBx}#HJTr$cd|;^l#3(b5YTL#riKrjU{Io Ps@^p=Q=DpBweb@G_c@_@ literal 0 HcmV?d00001 diff --git a/secrets/ovpnNl.age b/secrets/ovpnNl.age new file mode 100644 index 0000000000000000000000000000000000000000..60d6bd5aaa40cd056015491a42a83155c81cf940 GIT binary patch literal 1316 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCR+Pfqpr4^(hBj|>hE z3n_FoHIB-0F|0ICDGrY`_RNh8HFIcNOm&Iu`F^iF6Oe#iUl4=Twk2`|shbn!{7a!%F{4hyNM$Va!WG~FXSyj-EUpdivX)GReT*eN45 zFihW1-@CxWFTX_FvpmQ+(I?L%yf7lPpsc{eD4)wY*gqx5JjBV#tK20#+%v=6*+0rd zzaTW&+$`BM(89>ED5oODBPt->!WZ4P&``^uU`K@_{fdytLW{D3@<`*PFt;@AY?EZa zFpG-3aAzZD3m49H#0%E z&D_t&)Gu8jCsDt^!@|r$-!dvaFv79WF~2aqEWjY#qcT6tDLd8Q#ns2hBR??RKR1%A z+$be5KP}D4F(;$k$KT7#F*)C)G{VEo)4({g#JfB+CDpJfDl^?Y%_EshS65fTB&*yh zG&m(ZEGyE}Fx0R-x2)38tRTQ7q{_v`C@i8fD<#S^r#!gS-7%8uP4souJzi6v?sGNm zI?d%{xvTV6uZ7v`Ub($ooBg-Rov7R|t*y6dk^kpOM>9A7p1arL!;dQK%-Eh)8@n5( z=ImY_x>U`o<+X0@%O_d)dGdd`KL2rCU4OxTjtGTh8Rd`j9v%D=^+LDm zCcX`v8ggq=O>Jd3-;~V1f_jU?xR*ZKzr@Hn?CHY!wofN;mUnF|Pd)nZZR{k59}nMc zXE^VFYr6EsvgHb2nqto~lvN-2o0fB-;~-;yv+l}?w`ae8vMxyDOHf9egjK??bJ10| z8E5D|-q)91Iq#p`28%W!=2YW4_gfbS|vUR%~7HlHbL!`Ehn>kx!%GvtMWT&9=Uz;rV0z8RfOXbLTXl z(}+4eAz+Cmk1w;!Q^Cl+>eaylSERfbeREQ%S3JM?nVR9d`sp|3h_k)Bug1Dn=7Vj* zfxe)>bAQMi>t%g(&Ru)G@L%y)dGYV7eqqu-S9Vxwc>KScrt&Yi(09x4 zb#YUEw!fOP_1A_#r6uQ>GQ~q 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 0000000000000000000000000000000000000000..2ebfebbb9a014f77b162cbde23da7aa0ffa65770 GIT binary patch literal 793 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