From 64fc63cc40f1b673651170e837356ab70d1930de Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:04:57 +0200 Subject: [PATCH 01/13] remove pidFile - service type "simple" is the default - pidFile is not needed for service type "simple" --- modules/bitcoind.nix | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 409d264..376f3f9 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -5,7 +5,6 @@ with lib; let cfg = config.services.bitcoind; inherit (config) nix-bitcoin-services; - pidFile = "${cfg.dataDir}/bitcoind.pid"; configFile = pkgs.writeText "bitcoin.conf" '' ${optionalString cfg.testnet "testnet=1"} ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} @@ -44,7 +43,6 @@ let ''; cmdlineOptions = concatMapStringsSep " " (arg: "'${arg}'") [ "-datadir=${cfg.dataDir}" - "-pid=${pidFile}" ]; hexStr = types.strMatching "[0-9a-f]+"; rpcUserOpts = { name, ... }: { @@ -282,11 +280,9 @@ in { done ''; serviceConfig = { - Type = "simple"; User = "${cfg.user}"; Group = "${cfg.group}"; ExecStart = "${cfg.package}/bin/bitcoind ${cmdlineOptions}"; - PIDFile = "${pidFile}"; Restart = "on-failure"; # Hardening measures From 47fd6cd0f3e4cc65f1d73e6e3022f14deb574c4f Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:04:58 +0200 Subject: [PATCH 02/13] simplify ExecStart --- modules/bitcoind.nix | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 376f3f9..a1305e2 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -41,9 +41,6 @@ let # Extra config options (from bitcoind nixos service) ${cfg.extraConfig} ''; - cmdlineOptions = concatMapStringsSep " " (arg: "'${arg}'") [ - "-datadir=${cfg.dataDir}" - ]; hexStr = types.strMatching "[0-9a-f]+"; rpcUserOpts = { name, ... }: { options = { @@ -282,7 +279,7 @@ in { serviceConfig = { User = "${cfg.user}"; Group = "${cfg.group}"; - ExecStart = "${cfg.package}/bin/bitcoind ${cmdlineOptions}"; + ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'"; Restart = "on-failure"; # Hardening measures From 4e92b1c818a1d04149dccb61e615c6c5ea022dcb Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:04:59 +0200 Subject: [PATCH 03/13] remove redundant hardening options These are already defined in nix-bitcoin-services.defaultHardening. --- modules/bitcoind.nix | 7 ------- 1 file changed, 7 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index a1305e2..e89d63c 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -282,13 +282,6 @@ in { ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'"; Restart = "on-failure"; - # Hardening measures - PrivateTmp = "true"; - ProtectSystem = "full"; - NoNewPrivileges = "true"; - PrivateDevices = "true"; - MemoryDenyWriteExecute = "true"; - # Permission for preStart PermissionsStartOnly = "true"; } // nix-bitcoin-services.defaultHardening From 1a2271fb14c34a90b395d41e17a3e15875e84a36 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:00 +0200 Subject: [PATCH 04/13] remove unused variable 'hexStr' --- modules/bitcoind.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index e89d63c..29661f2 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -41,7 +41,6 @@ let # Extra config options (from bitcoind nixos service) ${cfg.extraConfig} ''; - hexStr = types.strMatching "[0-9a-f]+"; rpcUserOpts = { name, ... }: { options = { name = mkOption { From d60a5aa4db891cd26e85f7a268af8022ea64a0fe Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:01 +0200 Subject: [PATCH 05/13] define rpc.users submodule inline Improves readability. --- modules/bitcoind.nix | 45 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 29661f2..de1f1e8 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -41,28 +41,6 @@ let # Extra config options (from bitcoind nixos service) ${cfg.extraConfig} ''; - rpcUserOpts = { name, ... }: { - options = { - name = mkOption { - type = types.str; - example = "alice"; - description = '' - Username for JSON-RPC connections. - ''; - }; - passwordHMAC = mkOption { - type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}"); - example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae"; - description = '' - Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the - format $. - ''; - }; - }; - config = { - name = mkDefault name; - }; - }; in { options = { @@ -120,7 +98,28 @@ in { alice.passwordHMAC = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae"; bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99"; }; - type = with types; loaOf (submodule rpcUserOpts); + type = with types; loaOf (submodule ({ name, ... }: { + options = { + name = mkOption { + type = types.str; + example = "alice"; + description = '' + Username for JSON-RPC connections. + ''; + }; + passwordHMAC = mkOption { + type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}"); + example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae"; + description = '' + Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the + format $. + ''; + }; + }; + config = { + name = mkDefault name; + }; + })); description = '' RPC user information for JSON-RPC connnections. ''; From 5e81d60d63d017d7d3f71b961d0703ddb093f672 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:02 +0200 Subject: [PATCH 06/13] improve formatting --- modules/bitcoind.nix | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index de1f1e8..cadf041 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -5,6 +5,7 @@ with lib; let cfg = config.services.bitcoind; inherit (config) nix-bitcoin-services; + configFile = pkgs.writeText "bitcoin.conf" '' ${optionalString cfg.testnet "testnet=1"} ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} @@ -43,10 +44,8 @@ let ''; in { options = { - services.bitcoind = { enable = mkEnableOption "Bitcoin daemon"; - package = mkOption { type = types.package; default = pkgs.nix-bitcoin.bitcoind; @@ -60,7 +59,6 @@ in { par=16 rpcthreads=16 logips=1 - ''; description = "Additional configurations to be appended to bitcoin.conf."; }; @@ -74,7 +72,6 @@ in { default = configFile; description = "The data directory for bitcoind."; }; - user = mkOption { type = types.str; default = "bitcoin"; @@ -85,7 +82,6 @@ in { default = cfg.user; description = "The group as which to run bitcoind."; }; - rpc = { port = mkOption { type = types.ints.u16; @@ -125,7 +121,6 @@ in { ''; }; }; - rpcuser = mkOption { type = types.nullOr types.str; default = "bitcoinrpc"; @@ -136,7 +131,6 @@ in { default = null; description = "Password for JSON-RPC connections"; }; - testnet = mkOption { type = types.bool; default = false; @@ -163,14 +157,15 @@ in { type = types.nullOr types.bool; default = null; description = '' - Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) + Create new files with system default permissions, instead of umask 077 + (only effective with disabled wallet functionality) ''; }; disablewallet = mkOption { type = types.nullOr types.bool; default = null; description = '' - Do not load the wallet and disable wallet RPC calls + Do not load the wallet and disable wallet RPC calls ''; }; dbCache = mkOption { From a05551fd1c5af487d0562225b6e4da1903228fbb Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:03 +0200 Subject: [PATCH 07/13] improve config file formatting --- modules/bitcoind.nix | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index cadf041..357f975 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -14,7 +14,6 @@ let ${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"} ${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"} - # Connection options ${optionalString (cfg.port != null) "port=${toString cfg.port}"} ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} @@ -22,7 +21,6 @@ let ${optionalString (cfg.discover != null) "discover=${if cfg.discover then "1" else "0"}"} ${lib.concatMapStrings (node: "addnode=${node}\n") cfg.addnodes} - # RPC server options rpcport=${toString cfg.rpc.port} ${concatMapStringsSep "\n" @@ -39,7 +37,7 @@ let ${optionalString (cfg.zmqpubrawblock != null) "zmqpubrawblock=${cfg.zmqpubrawblock}"} ${optionalString (cfg.zmqpubrawtx != null) "zmqpubrawtx=${cfg.zmqpubrawtx}"} - # Extra config options (from bitcoind nixos service) + # Extra options ${cfg.extraConfig} ''; in { From 4e5c1d7551796136ef6d341e99302320f20734e4 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:05 +0200 Subject: [PATCH 08/13] disable redundant logfile --- modules/bitcoind.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 357f975..0620e6b 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -7,6 +7,9 @@ let inherit (config) nix-bitcoin-services; configFile = pkgs.writeText "bitcoin.conf" '' + # We're already logging via journald + nodebuglogfile=1 + ${optionalString cfg.testnet "testnet=1"} ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} ${optionalString (cfg.prune != null) "prune=${toString cfg.prune}"} From 1f8fe310d065fc744a455d205af9f9a9c9109d97 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:06 +0200 Subject: [PATCH 09/13] remove option 'configFileOption' It doesn't make sense for bitcoind users to completely redefine their config file. Also, it's poorly named and the description is faulty. This is a breaking change, but this option has probably no actual users. --- modules/bitcoind.nix | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 0620e6b..08258a8 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -68,11 +68,6 @@ in { default = "/var/lib/bitcoind"; description = "The data directory for bitcoind."; }; - configFileOption = mkOption { - type = types.path; - default = configFile; - description = "The data directory for bitcoind."; - }; user = mkOption { type = types.str; default = "bitcoin"; @@ -258,7 +253,7 @@ in { if ! test -e ${cfg.dataDir}/blocks; then mkdir -m 0770 -p '${cfg.dataDir}/blocks' fi - cp '${cfg.configFileOption}' '${cfg.dataDir}/bitcoin.conf' + cp '${configFile}' '${cfg.dataDir}/bitcoin.conf' chmod o-rw '${cfg.dataDir}/bitcoin.conf' chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}' echo "rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/bitcoin.conf' From 201fc3378297e1451f9d344f574abb570a137841 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:07 +0200 Subject: [PATCH 10/13] move line to relevant code section (blocks dir setup) --- modules/bitcoind.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 08258a8..db381ff 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -253,11 +253,12 @@ in { if ! test -e ${cfg.dataDir}/blocks; then mkdir -m 0770 -p '${cfg.dataDir}/blocks' fi + chmod -R g+rX '${cfg.dataDir}/blocks' + cp '${configFile}' '${cfg.dataDir}/bitcoin.conf' chmod o-rw '${cfg.dataDir}/bitcoin.conf' chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}' echo "rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/bitcoin.conf' - chmod -R g+rX '${cfg.dataDir}/blocks' ''; # Wait until RPC port is open. This usually takes just a few ms. postStart = '' From 08322eed9be055a2999d93ee5af77f0227465df3 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:08 +0200 Subject: [PATCH 11/13] use [[ test --- modules/bitcoind.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index db381ff..d334ec1 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -247,10 +247,10 @@ in { after = [ "network.target" "nix-bitcoin-secrets.target" ]; wantedBy = [ "multi-user.target" ]; preStart = '' - if ! test -e ${cfg.dataDir}; then + if [[ ! -e ${cfg.dataDir} ]]; then mkdir -m 0770 -p '${cfg.dataDir}' fi - if ! test -e ${cfg.dataDir}/blocks; then + if [[ ! -e ${cfg.dataDir}/blocks ]]; then mkdir -m 0770 -p '${cfg.dataDir}/blocks' fi chmod -R g+rX '${cfg.dataDir}/blocks' From 3e188238d08ce0090b2affa150f25210c42b219e Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:09 +0200 Subject: [PATCH 12/13] only update bitcoin.conf when changed --- modules/bitcoind.nix | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index d334ec1..2588559 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -253,12 +253,14 @@ in { if [[ ! -e ${cfg.dataDir}/blocks ]]; then mkdir -m 0770 -p '${cfg.dataDir}/blocks' fi + chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}' chmod -R g+rX '${cfg.dataDir}/blocks' - cp '${configFile}' '${cfg.dataDir}/bitcoin.conf' - chmod o-rw '${cfg.dataDir}/bitcoin.conf' - chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}' - echo "rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/bitcoin.conf' + cfg=$(cat ${configFile}; printf "rpcpassword="; cat "${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword") + confFile='${cfg.dataDir}/bitcoin.conf' + if [[ ! -e $confFile || $cfg != $(cat $confFile) ]]; then + install -o '${cfg.user}' -g '${cfg.group}' -m 640 <(echo "$cfg") $confFile + fi ''; # Wait until RPC port is open. This usually takes just a few ms. postStart = '' From 4dc6c3ba5d627d40a9eb2bd5b408fe0c87f56c9d Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Tue, 7 Apr 2020 23:05:10 +0200 Subject: [PATCH 13/13] add option 'dataDirReadableByGroup' These settings are now more accessible for users that don't use nix-bitcoin's default node config. Additionally, remove 'other' permissions via umask. --- modules/bitcoind.nix | 15 +++++++++++++++ modules/electrs.nix | 9 ++++++++- modules/presets/secure-node.nix | 3 +-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 2588559..4dcd020 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -149,6 +149,14 @@ in { If enabled, the bitcoin service will listen. ''; }; + dataDirReadableByGroup = mkOption { + type = types.bool; + default = false; + description = '' + If enabled, data dir content is readable by the bitcoind service group. + Warning: This disables bitcoind's wallet support. + ''; + }; sysperms = mkOption { type = types.nullOr types.bool; default = null; @@ -241,6 +249,12 @@ in { config = mkIf cfg.enable { environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ]; + + services.bitcoind = mkIf cfg.dataDirReadableByGroup { + disablewallet = true; + sysperms = true; + }; + systemd.services.bitcoind = { description = "Bitcoin daemon"; requires = [ "nix-bitcoin-secrets.target" ]; @@ -273,6 +287,7 @@ in { Group = "${cfg.group}"; ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'"; Restart = "on-failure"; + UMask = mkIf cfg.dataDirReadableByGroup "0027"; # Permission for preStart PermissionsStartOnly = "true"; diff --git a/modules/electrs.nix b/modules/electrs.nix index 3d30187..a7f0ee3 100644 --- a/modules/electrs.nix +++ b/modules/electrs.nix @@ -81,7 +81,14 @@ in { PermissionsStartOnly = "true"; ExecStart = '' ${pkgs.nix-bitcoin.electrs}/bin/electrs -vvv \ - ${optionalString (!cfg.high-memory) "--jsonrpc-import --index-batch-size=10"} \ + ${if cfg.high-memory then + traceIf (!config.services.bitcoind.dataDirReadableByGroup) '' + Warning: For optimal electrs syncing performance, enable services.bitcoind.dataDirReadableByGroup. + Note that this disables wallet support in bitcoind. + '' "" + else + "--jsonrpc-import --index-batch-size=10" + } \ --db-dir '${cfg.dataDir}' --daemon-dir '${config.services.bitcoind.dataDir}' \ --electrum-rpc-addr=${toString cfg.address}:${toString cfg.port} ${cfg.extraArgs} ''; diff --git a/modules/presets/secure-node.nix b/modules/presets/secure-node.nix index 0d2b666..f36b2f6 100644 --- a/modules/presets/secure-node.nix +++ b/modules/presets/secure-node.nix @@ -46,8 +46,7 @@ in { services.bitcoind = { enable = true; listen = true; - sysperms = if cfg.electrs.enable then true else null; - disablewallet = if cfg.electrs.enable then true else null; + dataDirReadableByGroup = mkIf cfg.electrs.enable true; proxy = cfg.tor.client.socksListenAddress; enforceTor = true; port = 8333;