diff --git a/modules/programs/ssh.nix b/modules/programs/ssh.nix
index abbde3f4..b51ecedf 100644
--- a/modules/programs/ssh.nix
+++ b/modules/programs/ssh.nix
@@ -414,6 +414,22 @@ in
'';
};
+ includes = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ File globs of ssh config files that should be included via the
+ Include directive.
+
+ See
+
+ ssh_config
+ 5
+
+ for more information.
+ '';
+ };
+
matchBlocks = mkOption {
type = hm.types.listOrDagOf matchBlockModule;
default = {};
@@ -474,9 +490,12 @@ in
else abort "Dependency cycle in SSH match blocks: ${sortedMatchBlocksStr}";
in ''
${concatStringsSep "\n" (
- mapAttrsToList (n: v: "${n} ${v}") cfg.extraOptionOverrides)}
-
- ${concatStringsSep "\n\n" (map (block: matchBlockStr block.data) matchBlocks)}
+ (mapAttrsToList (n: v: "${n} ${v}") cfg.extraOptionOverrides)
+ ++ (optional (cfg.includes != [ ]) ''
+ Include ${concatStringsSep " " cfg.includes}
+ '')
+ ++ (map (block: matchBlockStr block.data) matchBlocks)
+ )}
Host *
ForwardAgent ${yn cfg.forwardAgent}
diff --git a/tests/modules/programs/ssh/default-config-expected.conf b/tests/modules/programs/ssh/default-config-expected.conf
index 6885392b..d205cab1 100644
--- a/tests/modules/programs/ssh/default-config-expected.conf
+++ b/tests/modules/programs/ssh/default-config-expected.conf
@@ -1,7 +1,5 @@
-
-
Host *
ForwardAgent no
Compression no
diff --git a/tests/modules/programs/ssh/default.nix b/tests/modules/programs/ssh/default.nix
index 507eef0b..b2f832c9 100644
--- a/tests/modules/programs/ssh/default.nix
+++ b/tests/modules/programs/ssh/default.nix
@@ -1,5 +1,6 @@
{
ssh-defaults = ./default-config.nix;
+ ssh-includes = ./includes.nix;
ssh-match-blocks = ./match-blocks-attrs.nix;
ssh-forwards-dynamic-valid-bind-no-asserts =
diff --git a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf
index 02268e8c..a67a96ca 100644
--- a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf
+++ b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf
@@ -1,8 +1,5 @@
-
-
Host dynamicBindAddressWithPort
DynamicForward [127.0.0.1]:3000
-
Host dynamicBindPathNoPort
DynamicForward /run/user/1000/gnupg/S.gpg-agent.extra
diff --git a/tests/modules/programs/ssh/includes.nix b/tests/modules/programs/ssh/includes.nix
new file mode 100644
index 00000000..12e2c6df
--- /dev/null
+++ b/tests/modules/programs/ssh/includes.nix
@@ -0,0 +1,15 @@
+{ config, lib, pkgs, ... }:
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ includes = [ "config.d/*" "other/dir" ];
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.ssh/config
+ assertFileContains home-files/.ssh/config "Include config.d/* other/dir"
+ '';
+ };
+}
diff --git a/tests/modules/programs/ssh/match-blocks-attrs-expected.conf b/tests/modules/programs/ssh/match-blocks-attrs-expected.conf
index e2c32901..1a197b26 100644
--- a/tests/modules/programs/ssh/match-blocks-attrs-expected.conf
+++ b/tests/modules/programs/ssh/match-blocks-attrs-expected.conf
@@ -1,13 +1,9 @@
-
-
Host * !github.com
Port 516
IdentityFile file1
IdentityFile file2
-
Host abc
ProxyJump jump-host
-
Host xyz
ServerAliveInterval 60
ServerAliveCountMax 10
@@ -16,7 +12,6 @@ Host xyz
RemoteForward [localhost]:8081 [10.0.0.2]:80
RemoteForward /run/user/1000/gnupg/S.gpg-agent.extra /run/user/1000/gnupg/S.gpg-agent
DynamicForward [localhost]:2839
-
Host ordered
Port 1