From bc661b67431ebfb167e3078ef5d5d719df37865e Mon Sep 17 00:00:00 2001 From: Fabian Kammel Date: Mon, 4 Aug 2025 19:25:31 +0200 Subject: [PATCH 1/2] maintainers: add datosh Signed-off-by: Fabian Kammel --- maintainers/maintainer-list.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index a07d0e41b379..c07676f4b3ff 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -5859,6 +5859,12 @@ { fingerprint = "E8F9 0B80 908E 723D 0EDF 0916 5803 CDA5 9C26 A96A"; } ]; }; + datosh = { + email = "fabian@kammel.dev"; + github = "datosh"; + githubId = 6423339; + name = "Fabian Kammel"; + }; dav-wolff = { email = "nixpkgs@dav.dev"; github = "dav-wolff"; From 5d653c251fcdd6c804ac189d49e26bfba6a57431 Mon Sep 17 00:00:00 2001 From: Fabian Kammel Date: Mon, 4 Aug 2025 20:42:24 +0200 Subject: [PATCH 2/2] nixos/opkssh: init opkssh service Signed-off-by: Fabian Kammel --- nixos/modules/module-list.nix | 1 + .../services/networking/opkssh/opkssh.nix | 170 ++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 nixos/modules/services/networking/opkssh/opkssh.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 01e55d267bf2..6d3f39efe67e 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1296,6 +1296,7 @@ ./services/networking/openconnect.nix ./services/networking/opengfw.nix ./services/networking/openvpn.nix + ./services/networking/opkssh/opkssh.nix ./services/networking/ostinato.nix ./services/networking/owamp.nix ./services/networking/pangolin.nix diff --git a/nixos/modules/services/networking/opkssh/opkssh.nix b/nixos/modules/services/networking/opkssh/opkssh.nix new file mode 100644 index 000000000000..035b8f9f7ff4 --- /dev/null +++ b/nixos/modules/services/networking/opkssh/opkssh.nix @@ -0,0 +1,170 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.opkssh; + + providerFile = pkgs.writeText "opkssh-providers" ( + lib.concatStringsSep "\n" ( + lib.mapAttrsToList ( + name: provider: "${provider.issuer} ${provider.clientId} ${provider.lifetime}" + ) cfg.providers + ) + ); + + authIdFile = pkgs.writeText "opkssh-auth-id" ( + lib.concatStringsSep "\n" ( + lib.map (auth: "${auth.user} ${auth.principal} ${auth.issuer}") cfg.authorizations + ) + ); +in +{ + options.services.opkssh = { + enable = lib.mkEnableOption "OpenID Connect SSH authentication"; + + package = lib.mkPackageOption pkgs "opkssh" { }; + + user = lib.mkOption { + type = lib.types.str; + default = "opksshuser"; + description = "System user for running opkssh"; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "opksshuser"; + description = "System group for opkssh"; + }; + + providers = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule { + options = { + issuer = lib.mkOption { + type = lib.types.str; + description = "Issuer URI"; + example = "https://accounts.google.com"; + }; + + clientId = lib.mkOption { + type = lib.types.str; + description = "OAuth client ID"; + }; + + lifetime = lib.mkOption { + type = lib.types.enum [ + "12h" + "24h" + "48h" + "1week" + "oidc" + "oidc-refreshed" + ]; + default = "24h"; + description = "Token lifetime"; + }; + }; + } + ); + default = { + google = { + issuer = "https://accounts.google.com"; + clientId = "206584157355-7cbe4s640tvm7naoludob4ut1emii7sf.apps.googleusercontent.com"; + lifetime = "24h"; + }; + microsoft = { + issuer = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0"; + clientId = "096ce0a3-5e72-4da8-9c86-12924b294a01"; + lifetime = "24h"; + }; + github = { + issuer = "https://token.actions.githubusercontent.com"; + clientId = "github"; + lifetime = "oidc"; + }; + }; + description = "OpenID Connect providers configuration"; + }; + + authorizations = lib.mkOption { + type = lib.types.listOf ( + lib.types.submodule { + options = { + user = lib.mkOption { + type = lib.types.str; + description = "Linux user to authorize"; + }; + + principal = lib.mkOption { + type = lib.types.str; + description = "Principal identifier (email, repo, etc.)"; + }; + + issuer = lib.mkOption { + type = lib.types.str; + description = "Issuer URI"; + }; + }; + } + ); + default = [ ]; + description = "User authorization mappings"; + example = lib.literalExpression '' + # This example refers to values in the providers example + # adjust your expressions as necessary + [ + { + user = "alice"; + principal = "alice@gmail.com"; + inherit (config.services.opkssh.providers.google) issuer; + } + { + user = "bob"; + principal = "repo:NixOs/nixpkgs:environment:production"; + inherit (config.services.opkssh.providers.github) issuer; + } + ]; + ''; + }; + }; + + config = lib.mkIf cfg.enable { + users.groups.${cfg.group} = { }; + users.users.${cfg.user} = { + isSystemUser = true; + description = "OpenPubkey OpenID Connect SSH User"; + group = cfg.group; + }; + + services.openssh = { + authorizedKeysCommand = "/run/wrappers/bin/opkssh verify %u %k %t"; + authorizedKeysCommandUser = cfg.user; + }; + + security.wrappers."opkssh" = { + source = "${cfg.package}/bin/opkssh"; + owner = "root"; + group = "root"; + }; + + environment.etc."opk/providers" = { + mode = "0640"; + user = cfg.user; + group = cfg.group; + source = providerFile; + }; + + environment.etc."opk/auth_id" = { + mode = "0640"; + user = cfg.user; + group = cfg.group; + source = authIdFile; + }; + }; + + meta.maintainers = with lib.maintainers; [ datosh ]; +}