diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 5862190..3b1e5d1 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -380,6 +380,7 @@ in { }; users.groups.${cfg.group} = {}; users.groups.bitcoinrpc = {}; + nix-bitcoin.operator.groups = [ cfg.group ]; nix-bitcoin.secrets.bitcoin-rpcpassword-privileged.user = "bitcoin"; nix-bitcoin.secrets.bitcoin-rpcpassword-public = { diff --git a/modules/clightning.nix b/modules/clightning.nix index edc42e9..1e654ee 100644 --- a/modules/clightning.nix +++ b/modules/clightning.nix @@ -99,6 +99,7 @@ in { extraGroups = [ "bitcoinrpc" ]; }; users.groups.${cfg.group} = {}; + nix-bitcoin.operator.groups = [ cfg.group ]; systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" diff --git a/modules/hardware-wallets.nix b/modules/hardware-wallets.nix index 4d53884..8ff94e2 100644 --- a/modules/hardware-wallets.nix +++ b/modules/hardware-wallets.nix @@ -48,6 +48,7 @@ in { usbutils ]; users.groups."${cfg.group}" = {}; + nix-bitcoin.operator.groups = [ cfg.group ]; }) (mkIf cfg.ledger { diff --git a/modules/joinmarket.nix b/modules/joinmarket.nix index 7ce8b53..752c0dc 100644 --- a/modules/joinmarket.nix +++ b/modules/joinmarket.nix @@ -125,6 +125,10 @@ in { home = cfg.dataDir; }; users.groups.${cfg.group} = {}; + nix-bitcoin.operator = { + groups = [ cfg.group ]; + sudoUsers = [ cfg.group ]; + }; systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" diff --git a/modules/liquid.nix b/modules/liquid.nix index ae2b07e..e3b4de3 100644 --- a/modules/liquid.nix +++ b/modules/liquid.nix @@ -263,12 +263,15 @@ in { else nix-bitcoin-services.allowAnyIP ); }; + users.users.${cfg.user} = { group = cfg.group; extraGroups = [ "bitcoinrpc" ]; description = "Liquid sidechain user"; }; users.groups.${cfg.group} = {}; + nix-bitcoin.operator.groups = [ cfg.group ]; + nix-bitcoin.secrets.liquid-rpcpassword.user = "liquid"; }; } diff --git a/modules/lnd.nix b/modules/lnd.nix index e489d07..c58263e 100644 --- a/modules/lnd.nix +++ b/modules/lnd.nix @@ -259,6 +259,7 @@ in { else nix-bitcoin-services.allowAnyIP ) // nix-bitcoin-services.allowAnyProtocol; # For ZMQ }; + users.users.lnd = { description = "LND User"; group = "lnd"; @@ -266,6 +267,11 @@ in { home = cfg.dataDir; # lnd creates .lnd dir in HOME }; users.groups.lnd = {}; + nix-bitcoin.operator = { + groups = [ "lnd" ]; + sudoUsers = [ "lnd" ]; + }; + nix-bitcoin.secrets = { lnd-wallet-password.user = "lnd"; lnd-key.user = "lnd"; diff --git a/modules/modules.nix b/modules/modules.nix index 8efe809..64619b2 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -4,6 +4,7 @@ imports = [ # Core modules ./secrets/secrets.nix + ./operator.nix # Main features ./bitcoind.nix diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index cfeb253..d81b780 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -82,6 +82,7 @@ in { User that is allowed to execute commands in the service network namespaces. The user's group is also authorized. ''; + default = config.nix-bitcoin.operator.name; }; netns = mkOption { diff --git a/modules/nodeinfo.nix b/modules/nodeinfo.nix index 5577d52..86f4174 100644 --- a/modules/nodeinfo.nix +++ b/modules/nodeinfo.nix @@ -3,7 +3,7 @@ with lib; let - operatorName = config.nix-bitcoin.operatorName; + operatorName = config.nix-bitcoin.operator.name; script = pkgs.writeScriptBin "nodeinfo" '' set -eo pipefail diff --git a/modules/operator.nix b/modules/operator.nix new file mode 100644 index 0000000..a7a7361 --- /dev/null +++ b/modules/operator.nix @@ -0,0 +1,47 @@ +# Define an operator user for convenient interactive access to nix-bitcoin +# features and services. +# +# When using nix-bitcoin as part of a larger system config, set +# `nix-bitcoin.operator.name` to your main user name. + +{ config, lib, pkgs, options, ... }: + +with lib; +let + cfg = config.nix-bitcoin.operator; +in { + options.nix-bitcoin.operator = { + enable = mkEnableOption "operator user"; + name = mkOption { + type = types.str; + default = "operator"; + description = "User name."; + }; + groups = mkOption { + type = with types; listOf str; + default = []; + description = "Extra groups."; + }; + sudoUsers = mkOption { + type = with types; listOf str; + default = []; + description = "Users as which the operator is allowed to run commands."; + }; + }; + + config = mkIf cfg.enable { + users.users.${cfg.name} = { + isNormalUser = true; + extraGroups = [ + "systemd-journal" + "proc" # Enable full /proc access and systemd-status + ] ++ cfg.groups; + }; + + security.sudo.extraConfig = mkIf (cfg.sudoUsers != []) (let + users = builtins.concatStringsSep "," cfg.sudoUsers; + in '' + ${cfg.name} ALL=(${users}) NOPASSWD: ALL + ''); + }; +} diff --git a/modules/presets/secure-node.nix b/modules/presets/secure-node.nix index dd1839b..fbbcb05 100644 --- a/modules/presets/secure-node.nix +++ b/modules/presets/secure-node.nix @@ -5,7 +5,7 @@ with lib; let cfg = config.services; - operatorName = config.nix-bitcoin.operatorName; + operatorName = config.nix-bitcoin.operator.name; mkHiddenService = map: { map = [ map ]; @@ -29,11 +29,6 @@ in { default = 9735; description = "Port on which to listen for tor client connections."; }; - nix-bitcoin.operatorName = mkOption { - type = types.str; - default = "operator"; - description = "Less-privileged user's name."; - }; }; config = { @@ -159,35 +154,15 @@ in { qrencode ]; - # Create operator user which can access the node's services + services.onion-chef = { + enable = true; + access.${operatorName} = [ "bitcoind" "clightning" "nginx" "liquidd" "spark-wallet" "electrs" "btcpayserver" "sshd" ]; + }; + + nix-bitcoin.operator.enable = true; users.users.${operatorName} = { - isNormalUser = true; - extraGroups = [ - "systemd-journal" - "proc" # Enable full /proc access and systemd-status - cfg.bitcoind.group - ] - ++ (optionals cfg.clightning.enable [ "clightning" ]) - ++ (optionals cfg.lnd.enable [ "lnd" ]) - ++ (optionals cfg.liquidd.enable [ cfg.liquidd.group ]) - ++ (optionals (cfg.hardware-wallets.ledger || cfg.hardware-wallets.trezor) - [ cfg.hardware-wallets.group ]) - ++ (optionals cfg.joinmarket.enable [ cfg.joinmarket.group ]); openssh.authorizedKeys.keys = config.users.users.root.openssh.authorizedKeys.keys; }; - nix-bitcoin.netns-isolation.allowedUser = operatorName; - # Give operator access to onion hostnames - services.onion-chef.enable = true; - services.onion-chef.access.${operatorName} = [ "bitcoind" "clightning" "nginx" "liquidd" "spark-wallet" "electrs" "btcpayserver" "sshd" ]; - - security.sudo.configFile = - (optionalString cfg.lnd.enable '' - ${operatorName} ALL=(lnd) NOPASSWD: ALL - '') + - (optionalString cfg.joinmarket.enable '' - ${operatorName} ALL=(${cfg.joinmarket.user}) NOPASSWD: ALL - ''); - # Enable nixops ssh for operator (`nixops ssh operator@mynode`) on nixops-vbox deployments systemd.services.get-vbox-nixops-client-key = mkIf (builtins.elem ".vbox-nixops-client-key" config.services.openssh.authorizedKeysFiles) {