mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-10-30 16:10:36 +00:00
nixos/ssh: add programs.ssh.hosts to specify Host ... defintions
This new option is intentionally not `programs.ssh.settings`, as [that option name is already used by home-manager][1], and there it works a bit differently. The reasons for not taking home-manager's design as is, are: - Nixpkgs lacks the DAG implementation like [home-manager's][2] (See also [discourse discussion][3]). - nixos/pam is an existing Nixpkgs module that already requires the exact same features as ssh, so model the behavior of `programs.ssh.hosts` after it. See [PR][4], [1]: https://github.com/nix-community/home-manager/blob/master/modules/programs/ssh.nix [2]: https://github.com/nix-community/home-manager/blob/master/modules/lib/dag.nix [3]: https://discourse.nixos.org/t/an-equivalent-of-lib-hm-dag-or-some-other-mechanism-for-ordering-in-nixpkgs-lib/75195 [4]: https://github.com/NixOS/nixpkgs/pull/255547 Assisted-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -409,6 +409,8 @@ The above example can be migrated via the following structured code block:
|
||||
```
|
||||
:::
|
||||
|
||||
- The new {option}`programs.ssh.hosts` option can be used to add `Host` blocks to the client {file}`ssh_config`, keyed by `Host` pattern, instead of writing them by hand via {option}`programs.ssh.extraConfig`. Each block declares an {option}`programs.ssh.hosts.<name>.order`, since `ssh_config` applies the first obtained value for each keyword.
|
||||
|
||||
- NixOS VM tests now prefer to express durations and timeouts as `datetime.timedelta` values instead of bare numbers. Methods such as `machine.wait_until_succeeds`, `machine.sleep`, `retry`, and `polling_condition` now accept a `timedelta` (e.g., `machine.wait_for_unit("sshd.service", timeout=datetime.timedelta(minutes=1))`). Passing an `int`/`float` as seconds still works but now emits a deprecation warning. Argument names that explicitly defined units were preserved but have had `timedelta` equivalents introduced (`timeout_seconds` → `timeout`, `secs` → `duration`, `seconds_interval` → `interval`).
|
||||
|
||||
- `darwin.linux-builder-vz` has been added: a variant of `darwin.linux-builder` that runs the builder guest on Apple's Virtualization.framework via the new `vzvm` package, translating `x86_64-linux` builds with Rosetta instead of emulating them. Apple silicon hosts only. As part of this, the `nixos/modules/profiles/nix-builder-vm.nix` profile has been split into the backend-neutral `nixos/modules/profiles/nix-builder.nix` and a QEMU-specific part. Existing imports of `nix-builder-vm.nix` keep working unchanged.
|
||||
|
||||
@@ -35,6 +35,40 @@ let
|
||||
]
|
||||
++ map pkgs.copyPathToStore cfg.knownHostsFiles;
|
||||
|
||||
sshConfigValue = v: if builtins.isBool v then lib.boolToYesNo v else toString v;
|
||||
|
||||
hostSettingsText = lib.generators.toKeyValue {
|
||||
mkKeyValue = lib.generators.mkKeyValueDefault {
|
||||
mkValueString = sshConfigValue;
|
||||
} " ";
|
||||
indent = " ";
|
||||
};
|
||||
|
||||
hostsText = lib.pipe cfg.hosts [
|
||||
(lib.mapAttrsToList (
|
||||
pattern: hostCfg:
|
||||
# `order` is forced here so that it is required for a lone block too,
|
||||
# which `sort` would otherwise never compare against anything.
|
||||
lib.seq hostCfg.order {
|
||||
inherit pattern;
|
||||
inherit (hostCfg) order;
|
||||
settings = removeAttrs hostCfg [ "order" ];
|
||||
}
|
||||
))
|
||||
# `ssh_config(5)` applies the first obtained value for each keyword, so the
|
||||
# blocks are written in ascending `order`, and sharing an `order` value is
|
||||
# an error rather than an arbitrary choice between the two blocks.
|
||||
(lib.sort (
|
||||
a: b:
|
||||
if a.order != b.order then
|
||||
a.order < b.order
|
||||
else
|
||||
throw "programs.ssh.hosts: blocks '${a.pattern}' and '${b.pattern}' cannot have the same order value (${toString a.order})"
|
||||
))
|
||||
(map (host: "Host ${host.pattern}\n" + hostSettingsText host.settings))
|
||||
(lib.concatStringsSep "\n")
|
||||
];
|
||||
|
||||
in
|
||||
{
|
||||
###### interface
|
||||
@@ -124,6 +158,76 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
hosts = lib.mkOption {
|
||||
default = { };
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
freeformType = lib.types.attrsOf (
|
||||
lib.types.oneOf [
|
||||
lib.types.bool
|
||||
lib.types.int
|
||||
lib.types.str
|
||||
]
|
||||
);
|
||||
options.order = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
example = 100;
|
||||
description = ''
|
||||
Position of this block in {file}`ssh_config`. Blocks are
|
||||
written in ascending order of this value, and two blocks
|
||||
may not share a value.
|
||||
|
||||
Since {manpage}`ssh_config(5)` applies the *first* obtained
|
||||
value for each keyword, a block with a lower value takes
|
||||
precedence over the blocks that follow it. In particular, a
|
||||
catch-all pattern such as `"*"` should have the highest
|
||||
value, so that it does not shadow the more specific blocks.
|
||||
|
||||
To place a block relative to one that another module
|
||||
declares, derive this value from that block's one instead of
|
||||
hardcoding it, e.g.
|
||||
`config.programs.ssh.hosts."*".order - 100`.
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
description = ''
|
||||
Per-host (or host-pattern) client configuration, added as `Host`
|
||||
blocks to {file}`ssh_config`.
|
||||
|
||||
Attribute names are used as the `Host` pattern, as accepted by
|
||||
{manpage}`ssh_config(5)`. Several space-separated patterns can be
|
||||
given to apply one block to all of them, e.g.
|
||||
`"foo bar *.baz.org"`.
|
||||
|
||||
Every attribute of a block besides {option}`order` becomes a
|
||||
`Key Value` line within that block; boolean values are rendered as
|
||||
`yes`/`no`.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
jumphost = {
|
||||
order = 100;
|
||||
User = "deploy";
|
||||
Port = 2222;
|
||||
IdentityFile = "/root/.ssh/id_deploy";
|
||||
IdentitiesOnly = true;
|
||||
};
|
||||
"*.example.org" = {
|
||||
order = 200;
|
||||
ControlMaster = "auto";
|
||||
ControlPath = "/root/.ssh/master-%r@%n:%p";
|
||||
ControlPersist = "5m";
|
||||
};
|
||||
# Written last, so that it does not shadow the blocks above.
|
||||
"*" = {
|
||||
order = 300;
|
||||
ServerAliveInterval = 60;
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
startAgent = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
@@ -342,6 +446,7 @@ in
|
||||
environment.etc."ssh/ssh_config".text = lib.concatStringsSep "\n" (
|
||||
# Custom options from `extraConfig`, to override generated options
|
||||
lib.optional (cfg.extraConfig != "") cfg.extraConfig
|
||||
++ lib.optional (cfg.hosts != { }) hostsText
|
||||
++ [
|
||||
''
|
||||
# Generated options from other settings
|
||||
|
||||
Reference in New Issue
Block a user