diff --git a/checks/flake-module.nix b/checks/flake-module.nix index 3c61aae4e..55a18e751 100644 --- a/checks/flake-module.nix +++ b/checks/flake-module.nix @@ -53,6 +53,7 @@ in dummy-inventory-test = import ./dummy-inventory-test nixosTestArgs; borgbackup = import ./borgbackup nixosTestArgs; data-mesher = import ./data-mesher nixosTestArgs; + syncthing = import ./syncthing nixosTestArgs; } // lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "aarch64-linux") { # for some reason this hangs in an odd place in CI, but it works on my machine ... diff --git a/clanModules/sshd/README.md b/clanModules/sshd/README.md index 883050605..3373af308 100644 --- a/clanModules/sshd/README.md +++ b/clanModules/sshd/README.md @@ -1,7 +1,7 @@ --- description = "Enables secure remote access to the machine over ssh." categories = ["System", "Network"] -features = [ "inventory" ] +features = [ "inventory", "deprecated" ] --- This module will setup the opensshd service. diff --git a/clanServices/sshd/default.nix b/clanServices/sshd/default.nix new file mode 100644 index 000000000..9cb878db2 --- /dev/null +++ b/clanServices/sshd/default.nix @@ -0,0 +1,209 @@ +{ ... }: +{ + _class = "clan.service"; + manifest.name = "clan-core/sshd"; + manifest.description = "Enables secure remote access to the machine over ssh."; + manifest.categories = [ + "System" + "Network" + ]; + + roles.client = { + interface = + { lib, ... }: + { + options.certificate = { + searchDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ "mydomain.com" ]; + description = '' + List of domains to include in the certificate. + This option will prepend the machine name in front of each domain + before adding it to the certificate. + ''; + }; + }; + }; + + perInstance = + { settings, ... }: + { + nixosModule = + { + config, + lib, + pkgs, + ... + }: + { + + clan.core.vars.generators.openssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { + share = true; + files.id_ed25519.deploy = false; + files."id_ed25519.pub" = { + deploy = false; + secret = false; + }; + runtimeInputs = [ + pkgs.openssh + ]; + script = '' + ssh-keygen -t ed25519 -N "" -f "$out"/id_ed25519 + ''; + }; + + programs.ssh.knownHosts.ssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { + certAuthority = true; + extraHostNames = builtins.map (domain: "*.${domain}") settings.certificate.searchDomains; + publicKey = config.clan.core.vars.generators.openssh-ca.files."id_ed25519.pub".value; + }; + }; + }; + }; + + roles.server = { + interface = + { lib, ... }: + { + options = { + hostKeys.rsa.enable = lib.mkEnableOption "Generate RSA host key"; + + certificate = { + searchDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ "mydomain.com" ]; + description = '' + List of domains to include in the certificate. This option will + prepend the machine name in front of each domain before adding + it to the certificate. + ''; + }; + }; + }; + }; + + perInstance = + { settings, ... }: + { + nixosModule = + { + config, + lib, + pkgs, + ... + }: + { + + clan.core.vars.generators = { + + openssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { + share = true; + files.id_ed25519.deploy = false; + files."id_ed25519.pub" = { + deploy = false; + secret = false; + }; + runtimeInputs = [ + pkgs.openssh + ]; + script = '' + ssh-keygen -t ed25519 -N "" -f "$out"/id_ed25519 + ''; + }; + + openssh-cert = lib.mkIf (settings.certificate.searchDomains != [ ]) { + files."ssh.id_ed25519-cert.pub".secret = false; + dependencies = [ + "openssh" + "openssh-ca" + ]; + validation = { + name = config.clan.core.settings.machine.name; + domains = lib.genAttrs settings.certificate.searchDomains lib.id; + }; + runtimeInputs = [ + pkgs.openssh + pkgs.jq + ]; + script = + let + stringSet = list: builtins.attrNames (builtins.groupBy lib.id list); + domains = stringSet settings.certificate.searchDomains; + in + '' + ssh-keygen \ + -s $in/openssh-ca/id_ed25519 \ + -I ${config.clan.core.settings.machine.name} \ + -h \ + -n ${lib.concatMapStringsSep "," (d: "${config.clan.core.settings.machine.name}.${d}") domains} \ + $in/openssh/ssh.id_ed25519.pub + mv $in/openssh/ssh.id_ed25519-cert.pub "$out"/ssh.id_ed25519-cert.pub + ''; + }; + + openssh-rsa = lib.mkIf settings.hostKeys.rsa.enable { + files."ssh.id_rsa" = { }; + files."ssh.id_rsa.pub".secret = false; + runtimeInputs = [ + pkgs.coreutils + pkgs.openssh + ]; + script = '' + ssh-keygen -t rsa -b 4096 -N "" -f "$out"/ssh.id_rsa + ''; + }; + + openssh = { + files."ssh.id_ed25519" = { }; + files."ssh.id_ed25519.pub".secret = false; + migrateFact = "openssh"; + runtimeInputs = [ + pkgs.coreutils + pkgs.openssh + ]; + script = '' + ssh-keygen -t ed25519 -N "" -f "$out"/ssh.id_ed25519 + ''; + }; + }; + + programs.ssh.knownHosts.ssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { + certAuthority = true; + extraHostNames = builtins.map (domain: "*.${domain}") settings.certificate.searchDomains; + publicKey = config.clan.core.vars.generators.openssh-ca.files."id_ed25519.pub".value; + }; + + services.openssh = { + enable = true; + settings.PasswordAuthentication = false; + + settings.HostCertificate = lib.mkIf ( + settings.certificate.searchDomains != [ ] + ) config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".path; + + hostKeys = + [ + { + path = config.clan.core.vars.generators.openssh.files."ssh.id_ed25519".path; + type = "ed25519"; + } + ] + ++ lib.optional settings.hostKeys.rsa.enable { + path = config.clan.core.vars.generators.openssh-rsa.files."ssh.id_rsa".path; + type = "rsa"; + }; + }; + + programs.ssh.knownHosts.clan-sshd-self-ed25519 = { + hostNames = [ + "localhost" + config.networking.hostName + ] ++ (lib.optional (config.networking.domain != null) config.networking.fqdn); + publicKey = config.clan.core.vars.generators.openssh.files."ssh.id_ed25519.pub".value; + }; + }; + }; + }; +} diff --git a/clanServices/sshd/flake-module.nix b/clanServices/sshd/flake-module.nix new file mode 100644 index 000000000..0c44a0fbc --- /dev/null +++ b/clanServices/sshd/flake-module.nix @@ -0,0 +1,19 @@ +{ lib, self, ... }: +{ + clan.modules = { + sshd = lib.modules.importApply ./default.nix { }; + }; + + perSystem = + { pkgs, ... }: + { + checks = lib.optionalAttrs (pkgs.stdenv.isLinux) { + sshd = import ./tests/vm/default.nix { + inherit pkgs; + clan-core = self; + nixosLib = import (self.inputs.nixpkgs + "/nixos/lib") { }; + }; + }; + }; + +} diff --git a/clanServices/sshd/tests/vm/default.nix b/clanServices/sshd/tests/vm/default.nix new file mode 100644 index 000000000..ec097780e --- /dev/null +++ b/clanServices/sshd/tests/vm/default.nix @@ -0,0 +1,62 @@ +{ + pkgs, + nixosLib, + clan-core, + ... +}: + +nixosLib.runTest ( + { ... }: + { + imports = [ + clan-core.modules.nixosVmTest.clanTest + ]; + + hostPkgs = pkgs; + + name = "sshd"; + + clan = { + directory = ./.; + modules."@clan/sshd" = ../../default.nix; + inventory = { + machines.server = { }; + machines.client = { }; + + instances = { + sshd-test = { + module.name = "@clan/sshd"; + roles.server.machines."server".settings = { + certificate.searchDomains = [ "example.com" ]; + hostKeys.rsa.enable = true; + }; + roles.client.machines."client".settings = { + certificate.searchDomains = [ "example.com" ]; + }; + }; + }; + }; + }; + + nodes = { + server = { }; + client = { }; + }; + + testScript = '' + start_all() + + # Check that sshd port is open on the server + server.succeed("${pkgs.netcat}/bin/nc -z -v 127.0.0.1 22") + + # Check that /etc/ssh/ssh_known_hosts contains the required CA string on the server + server.succeed("grep '^@cert-authority ssh-ca,\*.example.com ssh-ed25519 ' /etc/ssh/ssh_known_hosts") + + # Check that server contains a line starting with 'localhost,server ssh-ed25519' + server.succeed("grep '^localhost,server ssh-ed25519 ' /etc/ssh/ssh_known_hosts") + + # Check that /etc/ssh/ssh_known_hosts contains the required CA string on the client + client.succeed("grep '^.cert-authority ssh-ca.*example.com ssh-ed25519 ' /etc/ssh/ssh_known_hosts") + ''; + } +) diff --git a/clanServices/sshd/tests/vm/sops/machines/client/key.json b/clanServices/sshd/tests/vm/sops/machines/client/key.json new file mode 100755 index 000000000..75b3e200f --- /dev/null +++ b/clanServices/sshd/tests/vm/sops/machines/client/key.json @@ -0,0 +1,6 @@ +[ + { + "publickey": "age124l8cfswl97ck0e0qw8l47usf375srn69e4mhxr3gr40erxw7pesftxshx", + "type": "age" + } +] diff --git a/clanServices/sshd/tests/vm/sops/machines/server/key.json b/clanServices/sshd/tests/vm/sops/machines/server/key.json new file mode 100755 index 000000000..564f53809 --- /dev/null +++ b/clanServices/sshd/tests/vm/sops/machines/server/key.json @@ -0,0 +1,6 @@ +[ + { + "publickey": "age1f39qxz84yv272wk636el0kdyagzudcs99ucpkjarsj2rey6yvccse9lwet", + "type": "age" + } +] diff --git a/clanServices/sshd/tests/vm/sops/secrets/client-age.key/secret b/clanServices/sshd/tests/vm/sops/secrets/client-age.key/secret new file mode 100644 index 000000000..7b5867fb5 --- /dev/null +++ b/clanServices/sshd/tests/vm/sops/secrets/client-age.key/secret @@ -0,0 +1,15 @@ +{ + "data": "ENC[AES256_GCM,data:anP0O+JjJDg3vcm9BzNSZ7pun/wkgDQtBFlAZiVdNTzLQJuRmQLnzh3M6HVZpaIm4vtKKXwvoW+6OxagZtAujuO0vfCVal/xNH4=,iv:D5jY2mXxPhXeX7cHuFKqhm5gAnErW/NZSGqgXGRgyLY=,tag:Xgt2/IcXxbx8uo1ne765Gg==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKQmsyTWloZWRCN216elBD\nS1NMVDlrcHpBT05YOUJ3SmpTN3MzMWlrSXo0CmVjNGdETVpuaGhWWE1KVmYyS04x\nQ2hLdWxmNmNFQzdNckRtQXVSajRZK1EKLS0tIG9OYmR5RUhYRmM1R3V6QTZDa2Yz\nSCtpTkZNaGRVRTNJK2N0QUR6aXdGMjgKXWGMFKeqY12wAhLheA44ZZmXdHWhYFF0\nzYAASccNOxf+AjnbYd8l4wOMGRhE0nqIW60kudQM/pPVprYR9p0eHQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-06-09T19:51:26Z", + "mac": "ENC[AES256_GCM,data:IwXjc6aOs+hsAEnUN44SzIr8otAq1g18IleZtmSxYJvs/XGiEBeOy9BPiKutlf2uTgiUJgz2f/799ifvBCjgmUZzbsdMw6OFOKB+BDuZHO4FCPg4nUC8AJ4DkA+tYVqZEPbMsOhWmwqPnLg3tvyIvGBgBtEu1zqe6UnYcs/UVAk=,iv:Ks4L5+aBHrDRaspdqRJTWg3a0zufqwTIvUEx6JFvhhc=,tag:2MU7JlamUQy8FFHLbvqVhQ==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/sshd/tests/vm/sops/secrets/client-age.key/users/admin b/clanServices/sshd/tests/vm/sops/secrets/client-age.key/users/admin new file mode 120000 index 000000000..9e21a9938 --- /dev/null +++ b/clanServices/sshd/tests/vm/sops/secrets/client-age.key/users/admin @@ -0,0 +1 @@ +../../../users/admin \ No newline at end of file diff --git a/clanServices/sshd/tests/vm/sops/secrets/server-age.key/secret b/clanServices/sshd/tests/vm/sops/secrets/server-age.key/secret new file mode 100644 index 000000000..23611d085 --- /dev/null +++ b/clanServices/sshd/tests/vm/sops/secrets/server-age.key/secret @@ -0,0 +1,15 @@ +{ + "data": "ENC[AES256_GCM,data:I/owfPMFtZtI23/2G8h67cZ+j3ZvU2CJ0PiR6gY4mH6IelDoKN/oFF9VmxDDcSNQPGY+aI8squqnOAbGZxjnxx+uU75j0IfcPvk=,iv:l++juCs2uVExfoAlg/Ho9sXDJeWspWwWfE5zWGr7iNw=,tag:4UkvlSq1WONy03NBDAP/4g==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlZ2ZHcHhzSUFlYU5vbjEy\nVVlhQ2hDL0lmK2FHeEFXQzBndnJoQ3VoeTFBCk9Jc2h4S1Yzb0Exam40RWpiSkhW\neVFibkw2RHB5VXdRQlBnc2VxOHdtU1kKLS0tIHV4RGRsdzE1amQyRFdwY1FCdnZ6\nM0pOdlBtYUtOUVNuV01lbTFoSFVlUEUKDuT0iyCQaUcfa+9mC1yGtC8XUm2ihfOu\neNM5lQ5vGOdFjumhUgWwBVHSMvqWd/Y2dNfIsJOQ95nvm48LSCOWVQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-06-09T19:51:28Z", + "mac": "ENC[AES256_GCM,data:Qw3p5S9xTdfCIH4sGdDp/5uFe17+8St6HAWTAmtsrkN1IApWiFgO65Io/5kjjzvsPlb5tYa73irfzvHjKZeacDkUzrCGr+U92nECiAtoawD7VZMp4f3d81erFQ8Vh92+Y8oByPFwLXIUC1FCe7LrtdhYWsgYRBdeDtcNMW+Yums=,iv:DQ/2E71p+SJceQYZ/1zsrI9CYO0PHktCn59lli6ZLQk=,tag:BGfLj9Detkri/ivaK2R/PQ==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/sshd/tests/vm/sops/secrets/server-age.key/users/admin b/clanServices/sshd/tests/vm/sops/secrets/server-age.key/users/admin new file mode 120000 index 000000000..9e21a9938 --- /dev/null +++ b/clanServices/sshd/tests/vm/sops/secrets/server-age.key/users/admin @@ -0,0 +1 @@ +../../../users/admin \ No newline at end of file diff --git a/clanServices/sshd/tests/vm/sops/users/admin/key.json b/clanServices/sshd/tests/vm/sops/users/admin/key.json new file mode 100644 index 000000000..e408aa96b --- /dev/null +++ b/clanServices/sshd/tests/vm/sops/users/admin/key.json @@ -0,0 +1,4 @@ +{ + "publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "type": "age" +} diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-cert/.validation-hash b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-cert/.validation-hash new file mode 100644 index 000000000..43921f474 --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-cert/.validation-hash @@ -0,0 +1 @@ +6e0863a6ca671e08b2f8ecbf9bb410953f5c6625cf61e04744393acb18db1c91 \ No newline at end of file diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-cert/ssh.id_ed25519-cert.pub/value b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-cert/ssh.id_ed25519-cert.pub/value new file mode 100644 index 000000000..fe49e7daa --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-cert/ssh.id_ed25519-cert.pub/value @@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIIVAZzuQVwfTqUCbcj3xlsW+/4to2v/r7cU7+FvU5F0MAAAAIOrepoK2S7VKrauHjf9SmMedDj1MxCMpJkehTrZC/XUTAAAAAAAAAAAAAAACAAAABnNlcnZlcgAAABYAAAASc2VydmVyLmV4YW1wbGUuY29tAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAge/ie7wQVq53Qpx/igaCsBiQrGLAnqV/Mmj7uS2A4q70AAABTAAAAC3NzaC1lZDI1NTE5AAAAQIW5ykVePfn24zFYoVnVwO4c+pqpkwxN00E+Vj8vKCcbUU5dAH3AH7X2Sl1WPFSBaIMX6tx8doC0tPohoLXZOA4= nixbld@kiwi diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa.pub/value b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa.pub/value new file mode 100644 index 000000000..5012c5acd --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa.pub/value @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCrCdAtYO93aa1m2kTyXz67IE6nO0w5qHwZbPPiMQH7EmAvdF3ROvvCooC2lKtuAtjJT71T9MalljRpv1yFVzALW+uOrqUjIZMNYJSoRF2KbGVbofF/2pi8ZVTFCvXfSLhy7Qhh5DppAET8Sp/vHk5tK+NMIxT5aiYHz9G3yxkjnvlUAiBpQjiWjxSQRXItgB/VqmUPv8dkTwobhQXjs7Q71nMCvPUB6CL5GHFZcN10wZovTFilOA1cge2II3QZ6Fw07hDga02sdTyUphBreZNtivyGgKcS2g0RFjpsV4udk3s6oBHNe463ngrPs/iqBe/r7AAVB4PC8VbKM5du+DKGybUf2JRi85Y7evicElLo0/Cu/0fSg/KAGOW2+GwcmD+A/zGpX/5dTHq1cYS4Zg24+1mpO/Hk9xqGQditnSUc6FTk1E/XaxWQOAv4m+a4811puvWUyllyvu1ETq0PujoayalIjQCYR2z7BBUghn2hcigv2jaIN9Q5LvWc2h4BRbgWf/ovWPG/wUN8B3nC/cmLBRTFjVxnJUVcgWPIV89jjARUZmyG2HEHxlxKKEQ+TSlTXfMpAwXssCMJ+bYs0+cXewnW8T+KsckABLyjBrqsFmEbA+auRVE31XLsA4jm1yybNtkraIHprTiT1RLCrn0wDfBXwd8DEqGFfMuoQ4J3gw== nixbld@kiwi diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/machines/server b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/machines/server new file mode 120000 index 000000000..2bd819ecb --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/machines/server @@ -0,0 +1 @@ +../../../../../../sops/machines/server \ No newline at end of file diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/secret b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/secret new file mode 100644 index 000000000..d6267f4b7 --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/secret @@ -0,0 +1,19 @@ +{ + "data": "ENC[AES256_GCM,data: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,iv:HyFkKHy8Jk/NcsCsUhwZI24X/9ZhOwMmyNmvYrgMBSw=,tag:Vu7UvIwr4pd1i9wdK7CRGQ==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1f39qxz84yv272wk636el0kdyagzudcs99ucpkjarsj2rey6yvccse9lwet", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArSkZEUzljMW04NERjMlZ6\nUkdQVy9RT1ZNbnZWN0hLdzhQT2VjWDlBZG5nCkJZbGZmNFp0aXZ5d3BrVWw2dVd0\nQ1c5SjRhL3dXQzFqcjBLZDhkOHVFdGMKLS0tIDZVSVpQUlJITzd4M3VWZUtnNjlJ\nNEtXNzVFS1FDN1dJTUZxeHg1Mm9uNEEKNHkM7rAPY97nH77w6sWEWGayPwNVkS+d\nMcQJKMknkGuhD5jS0XZF4m+J1yv8VisVECNDD6jo9bIKw2f62l2cYA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0M252OE0rV2dGT1c1b2FG\nMjBHYXpHWGFRRitXTEVLcVc2K0FMUkpjbUhVCldMelhUZmhza1VaMzBLekZTamlK\nU1FKMmt1dUdRN1oyWmtNZnlScHJsRTQKLS0tIGxtZGxvelZwS0VYNWZ6Y1RtU0Ev\naTVHZVhpZ0luWVBpTGdDYk1FRkpQdFEKL7Rw1hwIs8qLHi899xS9CTiysGnrSvmS\nDBvD8cFyxKbOzKxE6s1KkBjp/9jI2t4fcHfAAJwH18h6O+OiT+6GyA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-06-09T19:51:32Z", + "mac": "ENC[AES256_GCM,data:TaeTF0M5zqmiI0ANLIABskA6YHfSB41PMkL1j3WHoff8tO73YVM/l+yg4fs0HgsFZ/eDMG1gyHEzM8nGHeZ+oexla+ByAT9kgCZ1LaHCqANhMOlYCM9CLWqJg4OUUhi88f8147Gz6D9viMbOtRXvcOF+PdifCD70Ji02BGKApUU=,iv:pm+pYCWHRyKHavc3ZBgkiV+86RqcL3zJ0Li85SVw+6Q=,tag:D/hRrQaTxEr1cG3r7KloPg==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/users/admin b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/users/admin new file mode 120000 index 000000000..ca714e122 --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh-rsa/ssh.id_rsa/users/admin @@ -0,0 +1 @@ +../../../../../../sops/users/admin \ No newline at end of file diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519.pub/value b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519.pub/value new file mode 100644 index 000000000..e6a1dab2f --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519.pub/value @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOrepoK2S7VKrauHjf9SmMedDj1MxCMpJkehTrZC/XUT nixbld@kiwi diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/machines/server b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/machines/server new file mode 120000 index 000000000..2bd819ecb --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/machines/server @@ -0,0 +1 @@ +../../../../../../sops/machines/server \ No newline at end of file diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/secret b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/secret new file mode 100644 index 000000000..055c8325d --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/secret @@ -0,0 +1,19 @@ +{ + "data": "ENC[AES256_GCM,data:2eY77OJxJceog1MK0tLlu6FWyQLAz12w9GkwIq251ajbns1tiotUfPi5VecrTSU00aejA3GRg2Mp37kVHPCGLlwTVrqWJqJ2SG3FpqvdAhAwVNV4i3VlqIt8kT6P3WqhkOGCwIgcKEPwJ7EmYtBwihZosUw1xL3NflYAdzvH4wtqB9WrenHXsnK5zn4+F+CFOD8YtjY4QUrkPleeZE202fAlu6ItTwITZA0I9MqVRFUZC7XLoPltKkF9nNucfP3zz4oMko2wwyNeaj9ZQJYzzCuFQrTvq5AbN/Fq5weFO57QbysKsYEX1FcOI9njVTrffF70MEr7peJOB/kk0FKrG5ihy+stZ8WSYH9cE76ezA25FyB8eSv2Em0KjUxgc3v/9CWA8qvUeTRNSnv7hbe7J/ozGSRWkNCzFe9tQLdxJmfT+8RB9WKE50shSLvm9O2YoCWN6CDH5n+ifuyuF4eGJxVOEWXfBUebRjXrvczqE6+XHtMg0ZIfN+xIF6Ge0cFep+AtOHUgcY/CZf4yGshu,iv:/I4X6ljLySVXlmMHtHBTt/s3jdwYEOoQIb2yv6Tg/QA=,tag:XOn9ichWhpI7By9Hwe3g7Q==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1f39qxz84yv272wk636el0kdyagzudcs99ucpkjarsj2rey6yvccse9lwet", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlcDZCUmQ0UXVJMTczVVhJ\nT1c1V1U5QUdCdW94Q0c4VFp1empUWWhWcmo0CllUdlZhWnhZK1dta0NDNStjZDJD\nRTBOUmFaT1owY1J3TWZxMm9Pd2FNZWcKLS0tIGxCTWRKa3RKdlhsNmZveTV2TDF5\nMktOazU0SWZoYWNhSmxvTTZ3Wnd6eXcK6dIuJ3vR4f7qSRC2i8gQPx1wVDNnRcZu\nbz5f3aw0HhvnDRtgGfra9DVAyrJt7FVlEqMTMV6Cb5yr59fZAdvReQ==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIOWFjejdVaUdLUEY2T3pn\nR2RieWVTNTRHa2R6UWZZQ0FPcjNaQ0c0WlNVCnp2bkJvUXVPS2NXSGRGT3MrUzlz\nYnlyY2pjYXlGaVY0L3M2eURPWlFWZjQKLS0tIDFXaVNnRHREVUFHMDVQY05MZUFm\neVN5Vlc4S0FWRm5QQW9PQUNnZ1FjY1UKVmrCJ1x5B3uoA1YlFCTVaggVUZMtXoQN\nFA+hclCt/3Rt6EOajxjgF+nv8QNLnusj+IQgsgDh5H+YldLbu5XfUg==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-06-09T19:51:30Z", + "mac": "ENC[AES256_GCM,data:PG7jsFaXYmqFc7+z8/HgeMjGa5UwJi2XigYDQJ6zYNuMt4xsrK2G/Zss4uUAK5oSNN/TG3QJzR21OVGTsuZee+oCwho9P/px9as52sr1tzSJOwhboHb1S+CftWcqN3METYPwdowVvgrCJFAhWdKKTNy4DNzli7HJ+SDR6xE2da8=,iv:5/tzaObkRhSPdd6V/VLNlPzlKIReZMWTObqZZIbn5b8=,tag:Wje1JKGOQj7elnCWKN+IrA==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/users/admin b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/users/admin new file mode 120000 index 000000000..ca714e122 --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/per-machine/server/openssh/ssh.id_ed25519/users/admin @@ -0,0 +1 @@ +../../../../../../sops/users/admin \ No newline at end of file diff --git a/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519.pub/value b/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519.pub/value new file mode 100644 index 000000000..4cf3f4172 --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519.pub/value @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHv4nu8EFaud0Kcf4oGgrAYkKxiwJ6lfzJo+7ktgOKu9 nixbld@kiwi diff --git a/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519/secret b/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519/secret new file mode 100644 index 000000000..0634f39ef --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519/secret @@ -0,0 +1,15 @@ +{ + "data": "ENC[AES256_GCM,data:Qje3bXRHcAiFCslFfAeUTcOn2woc06e1sLAoH16x1sZ7N0i07rHqwsBjn7nKvMee6tktIjLMGTPOQL9TLgYI+wDgU5MHqlZlVBnYLk+VXYEKhymDlS3RAg5pbrmJzkucl/Vw5VBlDK+n8qnrgFG2pgpiC6Lzb5f4I7pxUl4zcz9jCf0Stj10lVQgkbvnr8UMUvcb1vUF/EAhF6WhhhgrhpbYrK+PkNW6EXmxIXdUdXvSqVWvJby2NgBaGOM1lwnWv4LOOiJ1BNXnOnLE0a8+8SjqahzqroeFvUCtoFxJ45/LqFTtgS9cQ44FaqrMRSWlOgsNR2BkeT449fKUCwYfEW1g/R47I9hAm/bcKrOBpHdAji/hpcDy73Qb9ZKrY6/0kRXl/ECI3YVX8nrHIjEJpoZ7a/dxJu7z8OOdb7gP2mVPTiWcbpD/KwpefDWLKnYhBrXUNaqSajf95Ahln2Vn6sALbbjcUzs/x5OqchYe1/kYy7MaGbEFNPeINnGid73c7xfUoyI90Ho4azLW8Q/n,iv:9heXX8g1P8/4gGT3+RYYmz6rJ5EnIDr5w1OAbGybL+I=,tag:p6mHZ8+EaJ+Nyn59n2TQ4g==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkNlpCNGR0SHVtVzJ2K0hM\ncng1ZWlTSGQzWndXVWhlbEZMN25TUklXV1I4Cm9PZkJ3Zi81YXoxdzVPTFI3dE1a\nUnJnUmJPbi9CYmdFL2ltaTRSQ1MreFUKLS0tIDE4Y05IamJjL0huY2l2YU4zbDJs\ndTl1b0wzaTM4MndlcFZYVThqbWtVeFUKuSZLJpUrccuusJPU2xWHw19wTN8mKZW3\n1GJJjlb79rZp/RbSMxFxkyVHgu+F9kbpRgViICJSWkeR495786oArA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-06-09T19:51:28Z", + "mac": "ENC[AES256_GCM,data:fgs9ftvz3wFsCsTJ94vnriYaG6JxZ4xbZan1J6TL/P3WoLR3KgacKuOxUfOCq5fRmz5wezyjoyRaYpm9AnDKLWDS0Tlu8Ja763FBYtPJHRsPc4giHr3QyQrIr8gG9DhmKNpBO7dzI02mkQmNU6ar3rGytGI9l5jYTHpnRqQCtQQ=,iv:GHV71/RE5R6TWwWvjjsEweruUQPvVLljmCK8qgTQga4=,tag:eJfy+ohGeBiZQaT5jRuWfQ==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519/users/admin b/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519/users/admin new file mode 120000 index 000000000..f14859ae0 --- /dev/null +++ b/clanServices/sshd/tests/vm/vars/shared/openssh-ca/id_ed25519/users/admin @@ -0,0 +1 @@ +../../../../../sops/users/admin \ No newline at end of file diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 32348d28f..14e667b0f 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -92,6 +92,7 @@ nav: - reference/clanServices/importer.md - reference/clanServices/localsend.md - reference/clanServices/mycelium.md + - reference/clanServices/sshd.md - reference/clanServices/hello-world.md - reference/clanServices/wifi.md - reference/clanServices/zerotier.md