Skip to content

Commit

Permalink
Merge #171: Hardening DAC
Browse files Browse the repository at this point in the history
b8e10af recurring-donations: Run under recurring-donations user (nixbitcoin)
5d01ea7 nodeinfo: Convert to module and allow alternative operator username (nixbitcoin)
95d230d Remove bitcoinrpc group remnants (nixbitcoin)
563b210 spark-wallet: Run under spark-wallet user (nixbitcoin)
205fca3 bitcoind: only make blocksdir group-readable when dataDirReadableByGroup (nixbitcoin)
81a04a4 lightning-charge: add dedicated user (nixbitcoin)
e67a818 lightning-charge: 0.4.14 -> 0.4.19 (nixbitcoin)
0ba5575 clightning: allow group access to RPC socket (nixbitcoin)
304dd29 clightning: remove config group read access (nixbitcoin)
04c6936 clightning: Remove clightning "bitcoinrpc" membership (nixbitcoin)
393ab0f electrs: Remove electrs user from "bitcoinrpc" and "bitcoin" sometimes (nixbitcoin)
7cfae66 electrs: Drop insecure TLS ciphers (nixbitcoin)
4c139a6 electrs: Make TLSProxy truly optional (nixbitcoin)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK b8e10af

Tree-SHA512: d3828961b42b8730818b6f55bd9cb19a9c1a1fcecc426da903ba1304251bb4b3b38ff0e4d7b29945ae1bf3c7a42719431b8c91b74b01aeb8d3671026c3d6df75
  • Loading branch information
jonasnick committed May 19, 2020
2 parents ca7f287 + b8e10af commit 0ac1e49
Show file tree
Hide file tree
Showing 17 changed files with 427 additions and 777 deletions.
4 changes: 1 addition & 3 deletions modules/bitcoind.nix
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ in {
mkdir -m 0770 -p '${cfg.dataDir}/blocks'
fi
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
chmod -R g+rX '${cfg.dataDir}/blocks'
${optionalString cfg.dataDirReadableByGroup "chmod -R g+rX '${cfg.dataDir}/blocks'"}
cfg=$(cat ${configFile}; printf "rpcpassword="; cat "${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword")
confFile='${cfg.dataDir}/bitcoin.conf'
Expand Down Expand Up @@ -332,11 +332,9 @@ in {
description = "Bitcoin daemon user";
};
users.groups.${cfg.group} = {};
users.groups.bitcoinrpc = {};

nix-bitcoin.secrets.bitcoin-rpcpassword = {
user = "bitcoin";
group = "bitcoinrpc";
};
};
}
11 changes: 5 additions & 6 deletions modules/clightning.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let
always-use-proxy=${if cfg.always-use-proxy then "true" else "false"}
${optionalString (cfg.bind-addr != null) "bind-addr=${cfg.bind-addr}"}
bitcoin-rpcuser=${cfg.bitcoin-rpcuser}
rpc-file-mode=0660
'';
in {
options.services.clightning = {
Expand Down Expand Up @@ -61,10 +62,8 @@ in {
cli = mkOption {
readOnly = true;
default = pkgs.writeScriptBin "lightning-cli"
# Switch user because c-lightning doesn't allow setting the permissions of the rpc socket
# https://github.com/ElementsProject/lightning/issues/1366
''
exec sudo -u clightning ${pkgs.nix-bitcoin.clightning}/bin/lightning-cli --lightning-dir='${cfg.dataDir}' "$@"
${pkgs.nix-bitcoin.clightning}/bin/lightning-cli --lightning-dir='${cfg.dataDir}' "$@"
'';
description = "Binary to connect with the clightning instance.";
};
Expand All @@ -76,7 +75,6 @@ in {
users.users.clightning = {
description = "clightning User";
group = "clightning";
extraGroups = [ "bitcoinrpc" ];
};
users.groups.clightning = {};

Expand All @@ -90,10 +88,9 @@ in {
mkdir -m 0770 -p ${cfg.dataDir}
cp ${configFile} ${cfg.dataDir}/config
chown -R 'clightning:clightning' '${cfg.dataDir}'
# give group read access to allow using lightning-cli
chmod u=rw,g=r,o= ${cfg.dataDir}/config
# The RPC socket has to be removed otherwise we might have stale sockets
rm -f ${cfg.dataDir}/bitcoin/lightning-rpc
chmod 600 ${cfg.dataDir}/config
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/config'
'';
serviceConfig = {
Expand All @@ -112,6 +109,8 @@ in {
while [[ ! -e ${cfg.dataDir}/bitcoin/lightning-rpc ]]; do
sleep 0.1
done
# Needed to enable lightning-cli for users with group 'clightning'
chmod g+x ${cfg.dataDir}/bitcoin
'';
};
};
Expand Down
4 changes: 2 additions & 2 deletions modules/electrs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ in {
users.users.${cfg.user} = {
description = "electrs User";
group = cfg.group;
extraGroups = [ "bitcoinrpc" "bitcoin"];
extraGroups = optionals cfg.high-memory [ "bitcoin" ];
};
users.groups.${cfg.group} = {};
}
Expand Down Expand Up @@ -136,7 +136,7 @@ in {
ssl_certificate_key ${secretsDir}/nginx-key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 4h;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
}
}
Expand Down
42 changes: 30 additions & 12 deletions modules/lightning-charge.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ with lib;
let
cfg = config.services.lightning-charge;
inherit (config) nix-bitcoin-services;
user = config.users.users.lightning-charge.name;
group = config.users.users.lightning-charge.group;
in {
options.services.lightning-charge = {
enable = mkOption {
Expand All @@ -14,35 +16,51 @@ in {
If enabled, the lightning-charge service will be installed.
'';
};
clightning-datadir = mkOption {
type = types.str;
default = "/var/lib/clighting/";
description = ''
Data directory of the clightning service
'';
dataDir = mkOption {
type = types.path;
default = "/var/lib/lightning-charge";
description = "The data directory for lightning-charge.";
};
};

config = mkIf cfg.enable {
users.users.lightning-charge = {
description = "lightning-charge User";
group = "lightning-charge";
extraGroups = [ "clightning" ];
};
users.groups.lightning-charge = {};

systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 ${user} ${group} - -"
];

environment.systemPackages = [ pkgs.nix-bitcoin.lightning-charge ];
systemd.services.lightning-charge = {
description = "Run lightning-charge";
wantedBy = [ "multi-user.target" ];
requires = [ "clightning.service" ];
after = [ "clightning.service" ];
preStart = ''
# Move existing lightning-charge.db
# TODO: Remove eventually
if [[ -e ${config.services.clightning.dataDir}/lightning-charge.db ]]; then
mv ${config.services.clightning.dataDir}/lightning-charge.db ${cfg.dataDir}/lightning-charge.db
chown ${user}: ${cfg.dataDir}/lightning-charge.db
chmod 600 ${cfg.dataDir}/lightning-charge.db
fi
'';
serviceConfig = {
PermissionsStartOnly = "true";
EnvironmentFile = "${config.nix-bitcoin.secretsDir}/lightning-charge-env";
ExecStart = "${pkgs.nix-bitcoin.lightning-charge}/bin/charged -l ${config.services.clightning.dataDir}/bitcoin -d ${config.services.clightning.dataDir}/lightning-charge.db";
# Unfortunately c-lightning doesn't allow setting the permissions of the rpc socket,
# so this must run as the clightning user
# https://github.com/ElementsProject/lightning/issues/1366
User = "clightning";
ExecStart = "${pkgs.nix-bitcoin.lightning-charge}/bin/charged -l ${config.services.clightning.dataDir}/bitcoin -d ${cfg.dataDir}/lightning-charge.db";
User = user;
Restart = "on-failure";
RestartSec = "10s";
} // nix-bitcoin-services.defaultHardening
// nix-bitcoin-services.nodejs
// nix-bitcoin-services.allowTor;
};
nix-bitcoin.secrets.lightning-charge-env.user = "clightning";
nix-bitcoin.secrets.lightning-charge-env.user = user;
};
}
1 change: 0 additions & 1 deletion modules/lnd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ in {
users.users.lnd = {
description = "LND User";
group = "lnd";
extraGroups = [ "bitcoinrpc" ];
home = cfg.dataDir; # lnd creates .lnd dir in HOME
};
users.groups.lnd = {};
Expand Down
1 change: 0 additions & 1 deletion modules/modules.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
./clightning.nix
./lightning-charge.nix
./nanopos.nix
./nix-bitcoin-webindex.nix
./liquid.nix
./spark-wallet.nix
./electrs.nix
Expand Down
2 changes: 1 addition & 1 deletion modules/nix-bitcoin-webindex.nix
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ in {
wantedBy = [ "multi-user.target" ];
after = [ "nodeinfo.service" ];
path = with pkgs; [
nix-bitcoin.nodeinfo
config.programs.nodeinfo
config.services.clightning.cli
config.services.lnd.cli
jq
Expand Down
68 changes: 68 additions & 0 deletions modules/nodeinfo.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{ config, lib, pkgs, ... }:

with lib;

let
operatorName = config.nix-bitcoin.operatorName;
script = pkgs.writeScriptBin "nodeinfo" ''
set -eo pipefail
BITCOIND_ONION="$(cat /var/lib/onion-chef/${operatorName}/bitcoind)"
echo BITCOIND_ONION="$BITCOIND_ONION"
if systemctl is-active --quiet clightning; then
CLIGHTNING_NODEID=$(lightning-cli getinfo | jq -r '.id')
CLIGHTNING_ONION="$(cat /var/lib/onion-chef/${operatorName}/clightning)"
CLIGHTNING_ID="$CLIGHTNING_NODEID@$CLIGHTNING_ONION:9735"
echo CLIGHTNING_NODEID="$CLIGHTNING_NODEID"
echo CLIGHTNING_ONION="$CLIGHTNING_ONION"
echo CLIGHTNING_ID="$CLIGHTNING_ID"
fi
if systemctl is-active --quiet lnd; then
LND_NODEID=$(lncli getinfo | jq -r '.uris[0]')
echo LND_NODEID="$LND_NODEID"
fi
NGINX_ONION_FILE=/var/lib/onion-chef/${operatorName}/nginx
if [ -e "$NGINX_ONION_FILE" ]; then
NGINX_ONION="$(cat $NGINX_ONION_FILE)"
echo NGINX_ONION="$NGINX_ONION"
fi
LIQUIDD_ONION_FILE=/var/lib/onion-chef/${operatorName}/liquidd
if [ -e "$LIQUIDD_ONION_FILE" ]; then
LIQUIDD_ONION="$(cat $LIQUIDD_ONION_FILE)"
echo LIQUIDD_ONION="$LIQUIDD_ONION"
fi
SPARKWALLET_ONION_FILE=/var/lib/onion-chef/${operatorName}/spark-wallet
if [ -e "$SPARKWALLET_ONION_FILE" ]; then
SPARKWALLET_ONION="$(cat $SPARKWALLET_ONION_FILE)"
echo SPARKWALLET_ONION="http://$SPARKWALLET_ONION"
fi
ELECTRS_ONION_FILE=/var/lib/onion-chef/${operatorName}/electrs
if [ -e "$ELECTRS_ONION_FILE" ]; then
ELECTRS_ONION="$(cat $ELECTRS_ONION_FILE)"
echo ELECTRS_ONION="$ELECTRS_ONION"
fi
SSHD_ONION_FILE=/var/lib/onion-chef/${operatorName}/sshd
if [ -e "$SSHD_ONION_FILE" ]; then
SSHD_ONION="$(cat $SSHD_ONION_FILE)"
echo SSHD_ONION="$SSHD_ONION"
fi
'';
in {
options = {
programs.nodeinfo = mkOption {
readOnly = true;
default = script;
};
};

config = {
environment.systemPackages = [ script ];
};
}
32 changes: 18 additions & 14 deletions modules/presets/secure-node.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,35 @@ with lib;
let
cfg = config.services;

operatorName = config.nix-bitcoin.operatorName;

mkHiddenService = map: {
map = [ map ];
version = 3;
};
in {
imports = [ ../modules.nix ];
imports = [
../modules.nix
../nodeinfo.nix
../nix-bitcoin-webindex.nix
];

options = {
services.clightning.onionport = mkOption {
type = types.ints.u16;
default = 9735;
description = "Port on which to listen for tor client connections.";
};

services.electrs.onionport = mkOption {
type = types.ints.u16;
default = 50002;
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 = {
Expand Down Expand Up @@ -99,7 +109,7 @@ in {
};
services.tor.hiddenServices.electrs = mkHiddenService {
port = cfg.electrs.onionport;
toPort = cfg.electrs.TLSProxy.port;
toPort = if cfg.electrs.TLSProxy.enable then cfg.electrs.TLSProxy.port else cfg.electrs.port;
};

services.spark-wallet.onion-service = true;
Expand All @@ -111,11 +121,10 @@ in {
tor
jq
qrencode
nix-bitcoin.nodeinfo
];

# Create user 'operator' which can access the node's services
users.users.operator = {
# Create operator user which can access the node's services
users.users.${operatorName} = {
isNormalUser = true;
extraGroups = [
"systemd-journal"
Expand All @@ -130,23 +139,18 @@ in {
};
# Give operator access to onion hostnames
services.onion-chef.enable = true;
services.onion-chef.access.operator = [ "bitcoind" "clightning" "nginx" "liquidd" "spark-wallet" "electrs" "sshd" ];
services.onion-chef.access.${operatorName} = [ "bitcoind" "clightning" "nginx" "liquidd" "spark-wallet" "electrs" "sshd" ];

# Unfortunately c-lightning doesn't allow setting the permissions of the rpc socket
# https://github.com/ElementsProject/lightning/issues/1366
security.sudo.configFile =
(optionalString cfg.clightning.enable ''
operator ALL=(clightning) NOPASSWD: ALL
'') +
(optionalString cfg.lnd.enable ''
operator ALL=(lnd) NOPASSWD: ALL
${operatorName} ALL=(lnd) 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) {
postStart = ''
cp "${config.users.users.root.home}/.vbox-nixops-client-key" "${config.users.users.operator.home}"
cp "${config.users.users.root.home}/.vbox-nixops-client-key" "${config.users.users.${operatorName}.home}"
'';
};
};
Expand Down
11 changes: 8 additions & 3 deletions modules/recurring-donations.nix
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,21 @@ in {
};

config = mkIf cfg.enable {
users.users.recurring-donations = {
description = "recurring-donations User";
group = "recurring-donations";
extraGroups = [ "clightning" ];
};
users.groups.recurring-donations = {};

systemd.services.recurring-donations = {
description = "Run recurring-donations";
requires = [ "clightning.service" ];
after = [ "clightning.service" ];
path = with pkgs; [ nix-bitcoin.clightning curl torsocks sudo jq ];
serviceConfig = {
ExecStart = "${pkgs.bash}/bin/bash ${recurring-donations-script}";
# TODO: would be better if this was operator, but I don't get sudo
# working inside the shell script
User = "clightning";
User = "recurring-donations";
Type = "oneshot";
} // nix-bitcoin-services.defaultHardening
// nix-bitcoin-services.allowTor;
Expand Down
Loading

0 comments on commit 0ac1e49

Please sign in to comment.