nixos/rush: init module (#398463)

Changed files
+203
nixos
doc
manual
release-notes
modules
tests
pkgs
by-name
ru
+2
nixos/doc/manual/release-notes/rl-2505.section.md
···
- [Pareto Security](https://paretosecurity.com/) is an alternative to corporate compliance solutions for companies that care about security but know it doesn't have to be invasive. Available as [services.paretosecurity](#opt-services.paretosecurity.enable)
+
- [GNU Rush](https://gnu.org/software/rush/) is a Restricted User Shell, designed for systems providing limited remote access to their resources. Available as [programs.rush](#opt-programs.rush.enable).
+
- [ipfs-cluster](https://ipfscluster.io/), Pinset orchestration for IPFS. Available as [services.ipfs-cluster](#opt-services.ipfs-cluster.enable)
- [bitbox-bridge](https://github.com/BitBoxSwiss/bitbox-bridge), a bridge software that connects BitBox hardware wallets to computers & web wallets like [Rabby](https://rabby.io/). Allows one to interact & transact with smart contracts, Web3 websites & financial services without storing private keys anywhere other than the hardware wallet. Available as [services.bitbox-bridge](#opt-services.bitbox-bridge.enable).
+1
nixos/modules/module-list.nix
···
./programs/quark-goldleaf.nix
./programs/regreet.nix
./programs/rog-control-center.nix
+
./programs/rush.nix
./programs/rust-motd.nix
./programs/ryzen-monitor-ng.nix
./programs/screen.nix
+109
nixos/modules/programs/rush.nix
···
+
{
+
config,
+
lib,
+
pkgs,
+
...
+
}:
+
let
+
cfg = config.programs.rush;
+
+
indent =
+
lines:
+
lib.pipe lines [
+
(lib.splitString "\n")
+
(builtins.filter (line: line != ""))
+
(map (line: " " + line))
+
(builtins.concatStringsSep "\n")
+
];
+
in
+
{
+
meta.maintainers = pkgs.rush.meta.maintainers;
+
+
options.programs.rush = with lib.types; {
+
enable = lib.mkEnableOption "Restricted User Shell.";
+
+
package = lib.mkPackageOption pkgs "rush" { } // {
+
type = shellPackage;
+
};
+
+
global = lib.mkOption {
+
type = lines;
+
description = "The `global` statement defines global settings.";
+
default = "";
+
};
+
+
rules = lib.mkOption {
+
type = attrsOf lines;
+
default = { };
+
+
description = ''
+
The rule statement configures a GNU Rush rule. This is a block statement, which means that all
+
statements located between it and the next rule statement (or end of file, whichever occurs first)
+
modify the definition of that rule.
+
'';
+
};
+
+
shell = lib.mkOption {
+
readOnly = true;
+
type = either shellPackage path;
+
+
description = ''
+
The resolved shell path that users can inherit to set `rush` as their login shell.
+
This is a convenience option for use in user definitions. Example:
+
`users.users.alice = { inherit (config.programs.rush) shell; ... };`
+
'';
+
};
+
+
wrap = lib.mkOption {
+
type = bool;
+
default = config.security.enableWrappers;
+
defaultText = lib.literalExpression "config.security.enableWrappers";
+
+
description = ''
+
Whether to wrap the `rush` binary with a SUID-enabled wrapper.
+
This is required if {option}`security.enableWrappers` is enabled in your configuration.
+
'';
+
};
+
};
+
+
config = lib.mkIf cfg.enable (
+
lib.mkMerge [
+
(lib.mkIf cfg.wrap {
+
security.wrappers.rush = lib.mkDefault {
+
group = "root";
+
owner = "root";
+
permissions = "u+rx,g+x,o+x";
+
setgid = false;
+
setuid = true;
+
source = lib.getExe cfg.package;
+
};
+
})
+
+
{
+
programs.rush.shell = if cfg.wrap then config.security.wrapperDir + "/rush" else cfg.package;
+
+
environment = {
+
shells = [ cfg.shell ];
+
systemPackages = [ cfg.package ];
+
+
etc."rush.rc".text =
+
lib.pipe
+
[
+
"# This file was created by the module `programs.rush`;"
+
"rush 2.0"
+
(lib.optionalString (cfg.global != "") "global\n${indent cfg.global}")
+
(lib.optionals (cfg.rules != { }) (
+
lib.mapAttrsToList (name: content: "rule ${name}\n${indent content}") cfg.rules
+
))
+
]
+
[
+
(lib.flatten)
+
(builtins.filter (line: line != ""))
+
(builtins.concatStringsSep "\n\n")
+
(lib.mkDefault)
+
];
+
};
+
}
+
]
+
);
+
}
+1
nixos/tests/all-tests.nix
···
rsyslogd = handleTest ./rsyslogd.nix { };
rtkit = runTest ./rtkit.nix;
rtorrent = handleTest ./rtorrent.nix { };
+
rush = runTest ./rush.nix;
rustls-libssl = handleTest ./rustls-libssl.nix { };
rxe = handleTest ./rxe.nix { };
sabnzbd = handleTest ./sabnzbd.nix { };
+88
nixos/tests/rush.nix
···
+
{ pkgs, ... }:
+
let
+
inherit (import ./ssh-keys.nix pkgs) snakeOilEd25519PrivateKey snakeOilEd25519PublicKey;
+
username = "nix-remote-builder";
+
in
+
{
+
name = "rush";
+
meta = { inherit (pkgs.rush.meta) maintainers platforms; };
+
+
nodes = {
+
client =
+
{ ... }:
+
{
+
nix.settings.extra-experimental-features = [ "nix-command" ];
+
};
+
+
server =
+
{ config, ... }:
+
{
+
nix.settings.trusted-users = [ "${username}" ];
+
+
programs.rush = {
+
enable = true;
+
global = "debug 1";
+
+
rules = {
+
daemon = ''
+
match $# == 2
+
match $0 == "nix-daemon"
+
match $1 == "--stdio"
+
match $user == "${username}"
+
chdir "${config.nix.package}/bin"
+
'';
+
+
whoami = ''
+
match $# == 1
+
match $0 == "whoami"
+
match $user == "${username}"
+
chdir "${dirOf config.environment.usrbinenv}"
+
'';
+
};
+
};
+
+
services.openssh = {
+
enable = true;
+
+
extraConfig = ''
+
Match User ${username}
+
AllowAgentForwarding no
+
AllowTcpForwarding no
+
PermitTTY no
+
PermitTunnel no
+
X11Forwarding no
+
Match All
+
'';
+
};
+
+
users = {
+
groups."${username}" = { };
+
+
users."${username}" = {
+
inherit (config.programs.rush) shell;
+
group = "${username}";
+
isSystemUser = true;
+
openssh.authorizedKeys.keys = [ snakeOilEd25519PublicKey ];
+
};
+
};
+
};
+
};
+
+
testScript = ''
+
start_all()
+
+
client.succeed("mkdir -m 700 /root/.ssh")
+
client.succeed("cat '${snakeOilEd25519PrivateKey}' | tee /root/.ssh/id_ed25519")
+
client.succeed("chmod 600 /root/.ssh/id_ed25519")
+
+
server.wait_for_unit("sshd")
+
+
client.succeed("ssh-keyscan -H server | tee -a /root/.ssh/known_hosts")
+
+
client.succeed("ssh ${username}@server -- whoami")
+
client.succeed("nix store info --store 'ssh-ng://${username}@server'")
+
+
client.fail("ssh ${username}@server -- date")
+
client.fail("nix store info --store 'ssh://${username}@server'")
+
'';
+
}
+2
pkgs/by-name/ru/rush/package.nix
···
stdenv,
bash,
perl,
+
nixosTests,
}:
stdenv.mkDerivation rec {
···
passthru = {
shellPath = "/bin/rush";
+
tests = { inherit (nixosTests) rush; };
};
}