diff --git a/cmd/tsidp/tsidp.go b/cmd/tsidp/tsidp.go index 8df68cd74..c0f821342 100644 --- a/cmd/tsidp/tsidp.go +++ b/cmd/tsidp/tsidp.go @@ -29,6 +29,7 @@ import ( "net/url" "os" "os/signal" + "path/filepath" "strconv" "strings" "sync" @@ -818,9 +819,10 @@ func (s *idpServer) oidcSigner() (jose.Signer, error) { } func (s *idpServer) oidcPrivateKey() (*signingKey, error) { + keyPath := filepath.Join(*flagDir, "oidc-key.json") return s.lazySigningKey.GetErr(func() (*signingKey, error) { var sk signingKey - b, err := os.ReadFile("oidc-key.json") + b, err := os.ReadFile(keyPath) if err == nil { if err := sk.UnmarshalJSON(b); err == nil { return &sk, nil @@ -835,7 +837,7 @@ func (s *idpServer) oidcPrivateKey() (*signingKey, error) { if err != nil { log.Fatalf("Error marshaling key: %v", err) } - if err := os.WriteFile("oidc-key.json", b, 0600); err != nil { + if err := os.WriteFile(keyPath, b, 0600); err != nil { log.Fatalf("Error writing key: %v", err) } return &sk, nil diff --git a/flake.nix b/flake.nix index 82af7b776..b6dc9b7de 100644 --- a/flake.nix +++ b/flake.nix @@ -52,6 +52,7 @@ # or the empty string when building from a local checkout of the # tailscale repo. tailscaleRev = self.rev or ""; + lib = nixpkgs.lib; in { # tailscale takes a nixpkgs package set, and builds Tailscale from # the same commit as this flake. IOW, it provides "tailscale built @@ -74,6 +75,7 @@ default = pkgs.buildGo124Module { name = "tailscale"; pname = "tailscale"; + meta.mainProgram = "tailscaled"; src = ./.; vendorHash = pkgs.lib.fileContents ./go.mod.sri; @@ -116,6 +118,16 @@ tailscale = default; }); + overlays.default = final: prev: { + tailscale = self.packages.${prev.stdenv.hostPlatform.system}.default; + }; + + nixosModules = { + # tailscale = import ./nixos/tailscaled-module.nix; + tsidp = import ./nixos/tsidp-module.nix self; + # default = self.nixosModules.tailscale; + }; + devShells = eachSystem (pkgs: { devShell = pkgs.mkShell { packages = with pkgs; [ diff --git a/nixos/tailscaled-module.nix b/nixos/tailscaled-module.nix new file mode 100644 index 000000000..6a9e1395a --- /dev/null +++ b/nixos/tailscaled-module.nix @@ -0,0 +1,25 @@ +{ + config, + lib, + ... +}: let + cfg = config.services.tailscale; + inherit + (lib) + mkEnableOption + mkIf + mkOption + types + ; +in { + # Tailscale config options + options.services.tailscale = { + enable = mkEnabledOption "Enable Tailscale service"; + + port = mkOption { + type = types.port; + default = 41641; + description = "The port Tailscale listens on."; + }; + }; +} diff --git a/nixos/tsidp-module.nix b/nixos/tsidp-module.nix new file mode 100644 index 000000000..6b23ce74f --- /dev/null +++ b/nixos/tsidp-module.nix @@ -0,0 +1,120 @@ +self: { + config, + lib, + pkgs, + ... +}: let + cfg = config.services.tsidp; + inherit + (lib) + mkEnableOption + mkIf + mkOption + types + ; +in { + # tsidp config options + options.services.tsidp = { + enable = mkEnableOption "Enable tsidp service"; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/tsidp"; + description = "Directory where tsidp stores its data."; + }; + + hostname = mkOption { + type = types.str; + default = "tsidp"; + description = "The hostname for the tsidp service appears as on the tailnet."; + }; + + funnel = mkOption { + type = types.bool; + default = false; + description = "Use Tailscale Funnel to make tsidp available on the public internet."; + }; + + useLocalTailscale = mkOption { + type = types.bool; + default = false; + description = "Use local tailscaled instead of tsnet."; + }; + + port = mkOption { + type = types.nullOr types.port; + default = null; + description = "The port on which tsidp listens for incoming connections."; + }; + + localPort = mkOption { + type = types.nullOr types.ints.s16; + default = null; + description = "The local port on which tsidp listens for incoming connections on localhost."; + }; + + verbose = mkOption { + type = types.bool; + default = false; + description = "Enable verbose logging for tsidp."; + }; + + serviceRestartMode = mkOption { + type = types.enum [ + "always" + "on-failure" + ]; + default = "always"; + description = "The systemd service restart mode for tsidp."; + }; + + serviceRestartInterval = mkOption { + type = types.int; + default = 5; + description = "Systemd RestartSec for tsidp service."; + }; + + user = mkOption { + type = types.str; + default = "tsidp"; + description = "The user under which the tsidp service runs."; + }; + + group = mkOption { + type = types.str; + default = "tsidp"; + description = "The group under which the tsidp service runs."; + }; + }; + + config = mkIf cfg.enable { + # tsidp service configuration + users.users = mkIf (config.services.tsidp.user == "tsidp") { + tsidp = { + name = "tsidp"; + group = cfg.group; + isSystemUser = true; + description = "Tailscale Identity Provider (tsidp) User."; + }; + }; + users.groups = mkIf (cfg.group == "tsidp") {tsidp = {};}; + + systemd.services.tsidp = { + description = "Tailscale Identity Provider (tsidp)"; + wantedBy = ["multi-user.target"]; + wants = ["network-online.target"]; + after = ["network-online.target"]; + environment = { + TAILSCALE_USE_WIP_CODE = "1"; + }; + serviceConfig = { + Type = "simple"; + Restart = "${cfg.serviceRestartMode}"; + RestartSec = cfg.serviceRestartInterval; + StateDirectory = "tsidp"; + User = "${cfg.user}"; + ExecStart = "${self.packages.${pkgs.system}.tailscale}/bin/tsidp --dir ${cfg.dataDir} --hostname ${cfg.hostname}${lib.optionalString cfg.verbose " --verbose"}${lib.optionalString cfg.funnel " --funnel"}${lib.optionalString cfg.useLocalTailscale " --use-local-tailscaled"}${lib.optionalString (cfg.port != null) " --port ${builtins.toString cfg.port}"}${lib.optionalString (cfg.localPort != null) " --local-port ${builtins.toString cfg.localPort}"}"; + }; + }; + }; +}