feat(teal): Add tailscale

We set up a headscale server, but we did not yet add a client so it
isn't possible to use it on the tailnet. Let's do that!

Change-Id: I686a6f6d8df2b4a8dd9d47389aacb0bff3abff82
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/742
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/flake.nix b/flake.nix
index 55ec830..a2b1e78 100644
--- a/flake.nix
+++ b/flake.nix
@@ -55,7 +55,7 @@
       deploy = lib.deploy.mkDeploy {
         inherit (inputs) self;
         overrides = {
-          a1d1.hostname = "d1.a1.clicks.domains";
+          teal.hostname = "teal.alpha.clicks.domains";
         };
       };
 
diff --git a/modules/nixos/clicks/networking/tailscale/default.nix b/modules/nixos/clicks/networking/tailscale/default.nix
new file mode 100644
index 0000000..29e413a
--- /dev/null
+++ b/modules/nixos/clicks/networking/tailscale/default.nix
@@ -0,0 +1,51 @@
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+let
+  cfg = config.clicks.networking.tailscale;
+in
+{
+  options.clicks.networking.tailscale = {
+    enable = lib.mkEnableOption "Enable tailscale for this system";
+    runExitNode.enable = lib.mkOption {
+      description = "Enable this system as an exit node on the tailnet";
+      default = true;
+      type = lib.types.bool;
+    };
+    server = lib.mkOption {
+      description = "Set where your control plane server is";
+      default = "https://clicks.domains";
+      example = "https://controlplane.tailscale.com";
+    };
+    authKeyFile = lib.mkOption {
+      type = lib.types.str;
+      description = "Path to key file for tailscale";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.tailscale = {
+      enable = true;
+      useRoutingFeatures = if cfg.runExitNode.enable then "both" else "client";
+      extraUpFlags = [
+        "--login-server=${cfg.server}"
+        "--accept-routes"
+        "--ssh"
+      ] ++ (if cfg.runExitNode.enable then [ "--advertise-exit-node" ] else [ ]);
+      authKeyFile = cfg.authKeyFile;
+    };
+
+    clicks.storage.impermanence.persist.directories = [ "/var/lib/tailscale" ];
+
+    systemd.services.tailscaled.environment.TS_NO_LOGS_NO_SUPPORT = lib.mkIf (
+      cfg.server != "https://controlplane.tailscale.com"
+    ) "true";
+  };
+}
diff --git a/systems/x86_64-linux/teal/default.nix b/systems/x86_64-linux/teal/default.nix
index 11e6f04..a0595cc 100644
--- a/systems/x86_64-linux/teal/default.nix
+++ b/systems/x86_64-linux/teal/default.nix
@@ -51,6 +51,12 @@
       };
     };
 
+    networking.tailscale = {
+      enable = true;
+      authKeyFile =
+        config.clicks.secrets."${lib.clicks.secrets.name ./tailscale.sops.json}".paths.authKey;
+    };
+
     storage = {
       raid.enable = true;
       impermanence = {
@@ -108,4 +114,9 @@
     ];
     neededForUsers = false;
   };
+
+  clicks.secrets."${lib.clicks.secrets.name ./tailscale.sops.json}" = {
+    file = ./tailscale.sops.json;
+    keys = [ "authKey" ];
+  };
 }
diff --git a/systems/x86_64-linux/teal/tailscale.sops.json b/systems/x86_64-linux/teal/tailscale.sops.json
new file mode 100644
index 0000000..ff1483e
--- /dev/null
+++ b/systems/x86_64-linux/teal/tailscale.sops.json
@@ -0,0 +1,36 @@
+{
+	"authKey": "ENC[AES256_GCM,data:Fpnxd58MoKDjpFWAUl9hK38p8yS6YPd0ZgdCZuIRKnEtmHXqpRcIUbcCrAuq+ja+,iv:ZOTBAJmdIdZ9WkhIoyg3Li/jSMZV8yxhrMy5TQnSCng=,tag:ZaFhr+MApSkCmPzGZWwBhw==,type:str]",
+	"sops": {
+		"kms": null,
+		"gcp_kms": null,
+		"azure_kv": null,
+		"hc_vault": null,
+		"age": null,
+		"lastmodified": "2024-06-09T22:48:26Z",
+		"mac": "ENC[AES256_GCM,data:/1hnKjEBozmYEAiISda91jsALJXo0bSC/YiMhj9GDCD8BAD74VEczSj9iTqk7pA39FLNg0+Sw8Um28azOrIe6TGFmemhnk1EkYH4k+aVGezRND/yhozvzml/UWE90sPx2xecHWUp33gfVgvbO4D8Kis0MmsSPnsopr4CAgydZkM=,iv:3OLsBKfcMJaTp4WisPczGqpVeGGxx1cr0zfFKW9XlMo=,tag:wUQDgFtJL6eCstx6dzO/mA==,type:str]",
+		"pgp": [
+			{
+				"created_at": "2024-06-09T19:37:39Z",
+				"enc": "-----BEGIN PGP MESSAGE-----\n\nhF4D6MHlIv4I/7ASAQdA/2WUVwimMMk8s37AfsuMrhBHxdeWptDHzbEB4LQ6cGEw\nU2YTgbtQF6CeCaAAgxE7+OKPFfNPH4UgziBIvxhk1RXXLoV5rnKY9WPj95a56cxH\n0l4BDJ8dgh/ufGB2ai/3hu5z1F4vPbouKv347itkaHnhnU8ljR89cx5BgAPjVeQr\nwZi6H+H6KWS0VJtR7Ygbjzdo56Q+/F3X/xEC1GjbT7ZUBYlHAXIaQNepAE7SrnIi\n=y8Hs\n-----END PGP MESSAGE-----",
+				"fp": "BC82DF237610AE9113EB075900E944BFBE99ADB5"
+			},
+			{
+				"created_at": "2024-06-09T19:37:39Z",
+				"enc": "-----BEGIN PGP MESSAGE-----\n\nhF4DxpBiwsu2o5wSAQdAtpXcG/TCbQeoriZPp42t1YXOYE8usTsz3bifoGfwOUEw\nDIpm35PU+onEelcNndZ2UaJh2Z6M4OWuul68KxgZwF+WrXW/pIIX+3bHNBQ9mM2i\n0l4B6o2FwoUBn9P4+G7t+rKBnGadvDWNaA1Lf+qfkS6H9ohzikwE3UxDsnLdZ0RU\nJexicnSDCa/Uoao5593wiKl4rt2QE+vma7LdwoY/oqgzg6gqZWK6kMHF49u5bA6E\n=dpw2\n-----END PGP MESSAGE-----",
+				"fp": "76E0B09A741C4089522111E5F27E3E5922772E7A"
+			},
+			{
+				"created_at": "2024-06-09T19:37:39Z",
+				"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMA9bzf+GUl7kkARAAxci3NfjtURRnLV7bw6xJLGxfmGzynoETHRCsEk6Wqhyo\nFRGEVJzpaadqTzvLHODI7LF6gpL3jsU50LfLqUnHHoOtBSi8qLEebow/ah2dvPaX\nX7adcwx3B05YinYZXKfIP+VZXgnKxW6r0OODhKTeWQSwxzc3aLXJBpEZPBG6ndTi\ns8TyPesMZMKi60mGr8goQZqzsEjzKfUeAZgzl55Y3+/gu252ayfYD2DHNSHMD6cs\ny6lNfQ8ECLF9+p/tauBRFiYckgqRWFZakjMlqcKX8s5zucJIPPuvwjqRTOcj3R18\nupKNCuC05yAN3GormNvwGENZ7n8p+aBBbjfc5Qqq3mgPU8+oo6Uw8inTUiL1Z1CN\nPGgSL3t4I4CIL7Znh5Ib0wA/UhOYS6G0ExiLg2LAWjBhF/oRgGafUb+O9jbibfrk\nD0PVedWY6HMV29Td45+7CgMCo7DkpHgsL4T55BjUO1bX9hmyJ3ryTRJMSmovM9db\nIGiLb57f8t2VzZcvXvn9OMCcBC1BF3BHD5y70H4ROLYqE+hl5qOqvyTF2M0XOaZ7\n8PXZgZFBrIsq6dMNHQrI0DXXzROFqBw4on2nlj3iV2j/6HTrpaUY8IZ9iXQfIwfm\n83cAtbwAnpWDrty/cchX5ZJ5mvJ4FzbHaJdxkfyriK3UQHcymveGQR1D6YgXH1/S\nXgFbNKSqFuIDPJG66U9nDbOF9zhnwvF1Ztc2pH+FmIFyk9lP7SlYflx/civfWI15\n3JD9E7iDhOFKuhlJ8mFFreRaVRBELII6qE/cFm5VTic+RXsZ8CdOLABH7oOCfm4=\n=D+Ck\n-----END PGP MESSAGE-----",
+				"fp": "8F50789F12AC6E6206EA870CE5E1C2D43B0E4AB3"
+			},
+			{
+				"created_at": "2024-06-09T19:37:39Z",
+				"enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAw8Caq2TdS1qAQ//fFgBgGmOXPYWdw7U1o8Alof3ZLtErIJDCgIc4WmY6git\nTdHcnHvDsIrI8kWEOrmr+Zz+ev0Px27BlFnsCj+p/8IUqTxxpqCdOu8rh4YPeHoD\n1ktfBxpxP1kBJKvsdmP6dwttYfm2bEEKCiIOnsJI2u+cNVszSz3UbTyuoI9CKfCL\nTgqVD3tF6P/5euFzbUHEBz+rSMDmV0OJBZ2nDupeiCwveYdGYS6qKRONcG9CZ2E6\nSayfZqvYq5ec3ETzLTTzio+fpN7aJsBMfy1DHo903Wk3MlPYyGlxrYaUdSfpjXDf\ngoEcVXN2abqjipnfJHWRhU3BDzH1f4TNHvOHuRemTqo6eickjuCp20KqBoWOYqY8\nULRH/5vfGjrEj8U2jKRbDV+FSwTDktY1lsU9u8MUPwiAANhdB691lK/pjpVfVg6C\nB800DFx7z5P84IQhsDJN4PrUmktnpMqbZ4hMhQJTzTrFpVtXDwFz15TckWK+JuyY\naqHgyvpfYFylc1Orn1uSUwqOXRl8zO335aP79Ss2hgNjfZZiFEOnRvjYipT4NvC6\n/mAWGRRrzOUzLjxT3/xcPSKFLiJ9Qx7R7VmxcoEU4Vs25DkZcpLt0y38WEH25qZZ\nO9LcarohWOb5SmSQ221TlvDFy7lm0yuoQu6mGjBMedw0y+mPQ4crASOx/C/KksLS\nWAGgSGR2jGpR1vhpmYUgX2IdPKrbk6bOAQFy1Hg2I1NzXYJBncIjKqklRrXUXDZI\n272hkAs02o7NFlS0u6qWcjiMMuhfgJn1jAqLbGnaS//CKK1fUGnjhXY=\n=c6ad\n-----END PGP MESSAGE-----",
+				"fp": "67c66d58ac73fd744c2b49720f026aad93752d6a"
+			}
+		],
+		"unencrypted_suffix": "_unencrypted",
+		"version": "3.8.1"
+	}
+}
\ No newline at end of file
diff --git a/systems/x86_64-linux/teal/tailscale.sops.json.license b/systems/x86_64-linux/teal/tailscale.sops.json.license
new file mode 100644
index 0000000..bda0f14
--- /dev/null
+++ b/systems/x86_64-linux/teal/tailscale.sops.json.license
@@ -0,0 +1,3 @@
+SPDX-FileCopyrightText: 2024 Clicks Codes
+
+SPDX-License-Identifier: GPL-3.0-only