From cb6b883f6e48d90b80d5c75a37db1aca41261e62 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 21 Jul 2024 19:47:22 +0200 Subject: [PATCH] feat(tailscale): Install k8s operator --- flake-parts/kubenix.nix | 5 ++ kubenix-modules/bootstrap-default.nix | 2 +- kubenix-modules/custom/tailscale.nix | 109 ++++++++------------------ kubenix-modules/inbucket.nix | 11 +-- kubenix-modules/syncthing.nix | 7 +- kubenix-modules/tailscale.nix | 14 ++++ secrets/kubernetes.yaml | 7 +- 7 files changed, 66 insertions(+), 89 deletions(-) create mode 100644 kubenix-modules/tailscale.nix diff --git a/flake-parts/kubenix.nix b/flake-parts/kubenix.nix index 81223c5..76cfa53 100644 --- a/flake-parts/kubenix.nix +++ b/flake-parts/kubenix.nix @@ -176,6 +176,11 @@ module = "${self}/kubenix-modules/minecraft.nix"; namespace = "minecraft"; }; + + tailscale = { + module = "${self}/kubenix-modules/tailscale.nix"; + namespace = "tailscale"; + }; }; in { diff --git a/kubenix-modules/bootstrap-default.nix b/kubenix-modules/bootstrap-default.nix index f1828b2..4f5d9ba 100644 --- a/kubenix-modules/bootstrap-default.nix +++ b/kubenix-modules/bootstrap-default.nix @@ -1,6 +1,5 @@ { lib, nixhelm, system, machines, ... }: { kubernetes = { - helm.releases = { metallb = { chart = nixhelm.chartsDerivations.${system}.metallb.metallb; @@ -48,6 +47,7 @@ dns = { }; media = { }; minecraft = { }; + tailscale = { }; }; nodes = diff --git a/kubenix-modules/custom/tailscale.nix b/kubenix-modules/custom/tailscale.nix index e5b1142..0789c6c 100644 --- a/kubenix-modules/custom/tailscale.nix +++ b/kubenix-modules/custom/tailscale.nix @@ -1,91 +1,50 @@ -{ lib, config, ... }: -let - cfg = config.lab.tailscale; - secretName = "tailscale-auth"; - roleName = "tailscale"; - sidecarContainername = "tailscale-sidecar"; -in -{ +{ lib, config, ... }: { options = with lib.types; { - lab.tailscale = { - enable = lib.mkEnableOption "tailscale"; + lab.tailscaleIngresses = lib.mkOption { + type = attrsOf (submodule { + options = { + host = lib.mkOption { type = str; }; - allowedServiceAccounts = lib.mkOption { - type = listOf str; + service = { + name = lib.mkOption { type = str; }; - description = '' - Allow specified service accounts to manage Tailscale authentication. - ''; - }; - - deploymentsWithSidecarContainers = lib.mkOption { - type = attrsOf (submodule ({ name, ... }: { - options.hostName = lib.mkOption { type = str; }; - })); - }; + portName = lib.mkOption { + type = str; + default = "web"; + }; + }; + }; + }); }; }; config = let - mkRoleBinding = name: { - name = "${name}-${roleName}"; - value = { - subjects = [{ - inherit name; - kind = "ServiceAccount"; + cfg = config.lab.tailscaleIngresses; + + mkTailscaleIngress = name: { host, service }: { + spec = { + ingressClassName = "tailscale"; + + rules = [{ + http.paths = [{ + path = "/"; + pathType = "Prefix"; + + backend.service = { + name = service.name; + port.name = service.portName; + }; + }]; }]; - roleRef = { - kind = "Role"; - name = roleName; - apiGroup = "rbac.authorization.k8s.io"; - }; - }; - }; - - mkSidecarContainer = name: { hostName, ... }: { - spec.template.spec.containers.${sidecarContainername} = { - imagePullPolicy = "Always"; - image = "ghcr.io/tailscale/tailscale:latest"; - - env = { - TS_HOSTNAME.value = hostName; - TS_KUBE_SECRET.value = secretName; - TS_USERSPACE.value = "false"; - TS_DEBUG_FIREWALL_MODE.value = "auto"; - TS_AUTHKEY.valueFrom.secretKeyRef = { - name = secretName; - key = "TS_AUTHKEY"; - optional = true; - }; - }; - - securityContext.capabilities.add = [ "NET_ADMIN" ]; + tls = [{ + hosts = [ host ]; + }]; }; }; in { - kubernetes.resources = lib.mkIf cfg.enable { - secrets.${secretName}.stringData.TS_AUTHKEY = "ref+sops://secrets/kubernetes.yaml#/tailscale/authKey"; - - roles.${roleName}.rules = [ - { - apiGroups = [ "" ]; - resources = [ "secrets" ]; - verbs = [ "create" ]; - } - { - apiGroups = [ "" ]; - resourceNames = [ secretName ]; - resources = [ "secrets" ]; - verbs = [ "get" "update" "patch" ]; - } - ]; - - roleBindings = builtins.listToAttrs (map mkRoleBinding cfg.allowedServiceAccounts); - - deployments = builtins.mapAttrs mkSidecarContainer cfg.deploymentsWithSidecarContainers; - }; + kubernetes.resources.ingresses = builtins.mapAttrs mkTailscaleIngress cfg; }; } diff --git a/kubenix-modules/inbucket.nix b/kubenix-modules/inbucket.nix index 26676ea..aed9bac 100644 --- a/kubenix-modules/inbucket.nix +++ b/kubenix-modules/inbucket.nix @@ -15,10 +15,8 @@ inbucket = { image = "inbucket/inbucket:edge"; - env.INBUCKET_WEB_ADDR.value = "0.0.0.0:80"; - ports = { - web.containerPort = 80; + web.containerPort = 9000; smtp.containerPort = 2500; }; }; @@ -52,9 +50,8 @@ }; }; - lab.tailscale = { - enable = true; - allowedServiceAccounts = [ "inbucket" ]; - deploymentsWithSidecarContainers.inbucket.hostName = "inbucket"; + lab.tailscaleIngresses.tailscale = { + host = "inbucket"; + service.name = "web"; }; } diff --git a/kubenix-modules/syncthing.nix b/kubenix-modules/syncthing.nix index 472cfdf..de132c0 100644 --- a/kubenix-modules/syncthing.nix +++ b/kubenix-modules/syncthing.nix @@ -79,10 +79,9 @@ storage = "400Mi"; }; - tailscale = { - enable = true; - allowedServiceAccounts = [ "syncthing" ]; - deploymentsWithSidecarContainers.syncthing.hostName = "syncthing"; + tailscaleIngresses.tailscale = { + host = "sync"; + service.name = "syncthing"; }; }; } diff --git a/kubenix-modules/tailscale.nix b/kubenix-modules/tailscale.nix new file mode 100644 index 0000000..58a61fe --- /dev/null +++ b/kubenix-modules/tailscale.nix @@ -0,0 +1,14 @@ +{ nixhelm, system, ... }: { + kubernetes = { + helm.releases.tailscale = { + chart = nixhelm.chartsDerivations.${system}.tailscale.tailscale-operator; + includeCRDs = true; + namespace = "tailscale"; + }; + + resources.secrets.operator-oauth.stringData = { + client_id = "ref+sops://secrets/kubernetes.yaml#/tailscale/oauth/clientID"; + client_secret = "ref+sops://secrets/kubernetes.yaml#/tailscale/oauth/clientSecret"; + }; + }; +} diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index a3847d3..41de328 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -28,6 +28,9 @@ immich: databasePassword: ENC[AES256_GCM,data:fZtGYiHOhYjdzBxaSdnstjlOAJE=,iv:YV+o4upajDHtwWSU6Z9h3Ncl9fXbo65KT6YMqlh2evY=,tag:BWLRc3bdnS9M70jC3SZXlA==,type:str] tailscale: authKey: ENC[AES256_GCM,data:pBbrL6/HVxDgvEeVHdnH6O3YsUB4tpRCO7SacYxSunDcMg8xcIXWWx1Zt65z9hcMcW/2AZbXC8mh+UPBRw==,iv:tTXdEAgCAHL46nN6yO0QNwJ0DUltAmQ/359TzuqXrpI=,tag:F7DtCigCRhdPBgMK3ZzV7g==,type:str] + oauth: + clientID: ENC[AES256_GCM,data:HLkgZ2q79LSBDCrwgzErNVE=,iv:/877rL2F/r4yxhGXaZW/TsbaU0arBKJiH9arTqfStrk=,tag:lVLJJ/D19FoSJXLu7S3ByQ==,type:str] + clientSecret: ENC[AES256_GCM,data:AsgE6KYXP8Z/2c4WdxWOou62txjz/TNarlQn6osebPB3czVVlGky4d4KcDE2cMgXqIEY3E/LNxbjMnfxIC9s,iv:EQDN/ECzIkKXtfj2DE0JtgXEpRMMEbYbfYDMxwXkx5E=,tag:NXwbzQv38njh+a5O8kQOag==,type:str] sops: kms: [] gcp_kms: [] @@ -52,8 +55,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-07-18T09:03:54Z" - mac: ENC[AES256_GCM,data:BEgztutw7barzGcbx5hkfAnauPv2H4nvwZM5iUfPJcjOkPsKTVwYAcdDdJE8wL2Nc9b4iIGSRwf9fwizyaerPR6SFt1zNHgbQz0DbUz+j/bUIXwKBSQNgK0KjiX8ONyFK62OxAhEa600OUV0cqWURUwRl+F8fRQSqQCvKuREVyE=,iv:ZMj4NAVI94bM/HwYSkZIN9hRPXWR1miIld57EeC+ckk=,tag:wy2ENtExu2mtpFPc/jy+nw==,type:str] + lastmodified: "2024-07-21T16:43:44Z" + mac: ENC[AES256_GCM,data:Gx9Zpdt/HzeYRj2ksmCGLaIJTcsfzxJklGdVNbtMIU888A32B72lAHfv0MbU5OBX0ZRt+VYDRncARSeTKPI3CGZu0qLtJwkDcVFGv+y+sea63DN8mmvNpYLQeif0daqE1GGMPVWukzV/2aBmfWbYBtHhm3C2v4f7KXobE83v3K0=,iv:bd+U7zyGOeH2Wq+y4RRv7kGfDkUGq1Kkfj4LOFdMJkY=,tag:5JkuFvY8kFfguBJoZfOnvg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1