Skip to content

Commit

Permalink
Merge branch 'service-hardening'
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasnick committed May 3, 2019
2 parents be5513a + e1ee502 commit 54a6a33
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 58 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
nix-bitcoin
===

Nix packages and nixos modules for easily installing Bitcoin nodes and higher layer protocols.
Nix packages and nixos modules for easily installing Bitcoin nodes and higher layer protocols with an emphasis on security.
This is a work in progress - don't expect it to be bug free or secure.

The default configuration sets up a Bitcoin Core node and c-lightning. The user can enable spark-wallet in `configuration.nix` to make c-lightning accessible with a smartphone using spark-wallet.
Expand Down Expand Up @@ -49,6 +49,19 @@ The easiest way is to run `nix-shell` (on a Linux machine) in the nix-bitcoin di
Fix the FIXMEs in configuration.nix and deploy with nixops in nix-shell.
See [install.md](docs/install.md) for a detailed tutorial.

Security
---
* Nix package manager, NixOS and packages can be built from source to reduce reliance on binary caches.
* Builds happen in a [sandboxed environment](https://nixos.org/nix/manual/).
* Packages dependencies are [pinned](pkgs/nixpkgs-pinned.nix). Most packages are built from the [nixos stable channel](https://github.com/NixOS/nixpkgs-channels/tree/nixos-19.03), with a few exceptions that are built from the nixpkgs unstable channel.
* nix-bitcoin merge commits are signed.
* nix-bitcoin is built with a [hardened kernel](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix) by default.
* Services operate with least privileges. They each have their own user and are restricted further with [systemd options](modules/nix-bitcoin-services.nix).
* There's a non-root user *operator* to interact with the various services.

Note that nix-bitcoin is still experimental.
Also, by design if the machine you're deploying *from* is insecure, there is nothing nix-bitcoin can do to protect itself.

Hardware requirements
---
* Disk space: 300 GB (235GB for Bitcoin blockchain + some room)
Expand Down
4 changes: 4 additions & 0 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ This is borrowed from the [NixOS manual](https://nixos.org/nixos/manual/index.ht
swapon /dev/sda2
```

4. Option 3: Set up encrypted partitions:

Follow the guide at https://gist.github.com/martijnvermaat/76f2e24d0239470dd71050358b4d5134.

5. Generate NixOS config

```
Expand Down
18 changes: 9 additions & 9 deletions modules/bitcoind.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.bitcoind;
pidFile = "${cfg.dataDir}/bitcoind.pid";
configFile = pkgs.writeText "bitcoin.conf" ''
Expand Down Expand Up @@ -192,6 +193,7 @@ in {
to stay under the specified target size in MiB)
'';
};
enforceTor = nix-bitcoin-services.enforceTor;
};
};

Expand Down Expand Up @@ -235,7 +237,11 @@ in {

# Permission for preStart
PermissionsStartOnly = "true";
};
} // nix-bitcoin-services.defaultHardening
// (if cfg.enforceTor
then nix-bitcoin-services.allowTor
else nix-bitcoin-services.allowAnyIP
);
};
systemd.services.bitcoind-import-banlist = {
description = "Bitcoin daemon banlist importer";
Expand Down Expand Up @@ -269,16 +275,10 @@ in {
ExecStart = "${pkgs.bash}/bin/bash ${pkgs.banlist}/bin/banlist ${pkgs.altcoins.bitcoind}";
StateDirectory = "bitcoind";

# Hardening measures
PrivateTmp = "true";
ProtectSystem = "full";
NoNewPrivileges = "true";
PrivateDevices = "true";
MemoryDenyWriteExecute = "true";

# Permission for preStart
PermissionsStartOnly = "true";
};
} // nix-bitcoin-services.defaultHardening
// nix-bitcoin-services.allowTor;
};

users.users.${cfg.user} = {
Expand Down
13 changes: 7 additions & 6 deletions modules/clightning.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.clightning;
configFile = pkgs.writeText "config" ''
autolisten=${if cfg.autolisten then "true" else "false"}
Expand Down Expand Up @@ -56,6 +57,7 @@ in {
default = "/var/lib/clightning";
description = "The data directory for clightning.";
};
enforceTor = nix-bitcoin-services.enforceTor;
};

config = mkIf cfg.enable {
Expand Down Expand Up @@ -93,12 +95,11 @@ in {
User = "clightning";
Restart = "on-failure";
RestartSec = "10s";
PrivateTmp = "true";
ProtectSystem = "full";
NoNewPrivileges = "true";
PrivateDevices = "true";
MemoryDenyWriteExecute = "true";
};
} // nix-bitcoin-services.defaultHardening
// (if cfg.enforceTor
then nix-bitcoin-services.allowTor
else nix-bitcoin-services.allowAnyIP
);
};
};
}
12 changes: 7 additions & 5 deletions modules/electrs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.electrs;
index-batch-size = "${if cfg.high-memory then "" else "--index-batch-size=10"}";
jsonrpc-import = "${if cfg.high-memory then "" else "--jsonrpc-import"}";
Expand Down Expand Up @@ -42,6 +43,7 @@ in {
default = 50003;
description = "Override the default port on which to listen for connections.";
};
enforceTor = nix-bitcoin-services.enforceTor;
};

config = mkIf cfg.enable {
Expand Down Expand Up @@ -74,11 +76,11 @@ in {
User = "electrs";
Restart = "on-failure";
RestartSec = "10s";
PrivateTmp = "true";
ProtectSystem = "full";
NoNewPrivileges = "true";
PrivateDevices = "true";
};
} // nix-bitcoin-services.defaultHardening
// (if cfg.enforceTor
then nix-bitcoin-services.allowTor
else nix-bitcoin-services.allowAnyIP
);
};

services.nginx = {
Expand Down
9 changes: 4 additions & 5 deletions modules/lightning-charge.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.lightning-charge;
in {
options.services.lightning-charge = {
Expand Down Expand Up @@ -37,11 +38,9 @@ in {
User = "clightning";
Restart = "on-failure";
RestartSec = "10s";
PrivateTmp = "true";
ProtectSystem = "full";
NoNewPrivileges = "true";
PrivateDevices = "true";
};
} // nix-bitcoin-services.defaultHardening
// nix-bitcoin-services.nodejs
// nix-bitcoin-services.allowTor;
};
};
}
17 changes: 7 additions & 10 deletions modules/liquid.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.liquidd;
pidFile = "${cfg.dataDir}/liquidd.pid";
configFile = pkgs.writeText "liquid.conf" ''
Expand Down Expand Up @@ -165,6 +166,7 @@ in {
to stay under the specified target size in MiB)
'';
};
enforceTor = nix-bitcoin-services.enforceTor;
};
};

Expand Down Expand Up @@ -195,28 +197,23 @@ in {
PIDFile = "${pidFile}";
Restart = "on-failure";

# Hardening measures
PrivateTmp = "true";
ProtectSystem = "full";
NoNewPrivileges = "true";
PrivateDevices = "true";
MemoryDenyWriteExecute = "true";

# Permission for preStart
PermissionsStartOnly = "true";
};
} // nix-bitcoin-services.defaultHardening
// (if cfg.enforceTor
then nix-bitcoin-services.allowTor
else nix-bitcoin-services.allowAnyIP
);
};
users.users.${cfg.user} = {
name = cfg.user;
#uid = config.ids.uids.liquid;
group = cfg.group;
extraGroups = [ "keys" ];
description = "Liquid daemon user";
home = cfg.dataDir;
};
users.groups.${cfg.group} = {
name = cfg.group;
#gid = config.ids.gids.liquid;
};
};
}
9 changes: 4 additions & 5 deletions modules/nanopos.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.nanopos;
defaultItemsFile = pkgs.writeText "items.yaml" ''
tea:
Expand Down Expand Up @@ -73,11 +74,9 @@ in {
User = "nanopos";
Restart = "on-failure";
RestartSec = "10s";
PrivateTmp = "true";
ProtectSystem = "full";
NoNewPrivileges = "true";
PrivateDevices = "true";
};
} // nix-bitcoin-services.defaultHardening
// nix-bitcoin-services.nodejs
// nix-bitcoin-services.allowTor;
};
};
}
44 changes: 44 additions & 0 deletions modules/nix-bitcoin-services.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{ config, lib, pkgs, ... }:

with lib;

let
defaultHardening = {
PrivateTmp = "true";
ProtectSystem = "full";
ProtectHome = "true";
NoNewPrivileges = "true";
PrivateDevices = "true";
MemoryDenyWriteExecute = "true";
ProtectKernelTunables = "true";
ProtectKernelModules = "true";
ProtectControlGroups = "true";
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
RestrictNamespaces = "true";
LockPersonality = "true";
IPAddressDeny = "any";
};
in
{
inherit defaultHardening;
# nodejs applications apparently rely on memory write execute
nodejs = { MemoryDenyWriteExecute = "false"; };
# Allow tor traffic. Allow takes precedence over Deny.
allowTor = {
IPAddressAllow = "127.0.0.1/32 ::1/128";
};
# Allow any traffic
allowAnyIP = { IPAddressAllow = "any"; };

enforceTor = mkOption {
type = types.bool;
default = false;
description = ''
"Whether to force Tor on a service by only allowing connections from and
to 127.0.0.1;";
'';
};
}



8 changes: 7 additions & 1 deletion modules/nix-bitcoin-webindex.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.nix-bitcoin-webindex;
indexFile = pkgs.writeText "index.html" ''
<html>
Expand Down Expand Up @@ -43,6 +44,7 @@ in {
If enabled, the webindex service will be installed.
'';
};
enforceTor = nix-bitcoin-services.enforceTor;
};

config = mkIf cfg.enable {
Expand Down Expand Up @@ -80,7 +82,11 @@ in {
RemainAfterExit="yes";
Restart = "on-failure";
RestartSec = "10s";
};
} // nix-bitcoin-services.defaultHardening
// (if cfg.enforceTor
then nix-bitcoin-services.allowTor
else nix-bitcoin-services.allowAnyIP
);
};
};
}
8 changes: 7 additions & 1 deletion modules/nix-bitcoin.nix
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ in {
services.bitcoind.sysperms = if config.services.electrs.enable then true else null;
services.bitcoind.disablewallet = if config.services.electrs.enable then true else null;
services.bitcoind.proxy = config.services.tor.client.socksListenAddress;
services.bitcoind.enforceTor = true;
services.bitcoind.port = 8333;
services.bitcoind.rpcuser = "bitcoinrpc";
services.bitcoind.extraConfig = ''
Expand All @@ -82,6 +83,7 @@ in {
# clightning
services.clightning.bitcoin-rpcuser = config.services.bitcoind.rpcuser;
services.clightning.proxy = config.services.tor.client.socksListenAddress;
services.clightning.enforceTor = true;
services.clightning.always-use-proxy = true;
services.clightning.bind-addr = "127.0.0.1:9735";
services.tor.hiddenServices.clightning = {
Expand Down Expand Up @@ -128,6 +130,8 @@ in {
};
};

services.nix-bitcoin-webindex.enforceTor = true;

services.liquidd.rpcuser = "liquidrpc";
services.liquidd.prune = 1000;
services.liquidd.extraConfig = "
Expand All @@ -136,16 +140,18 @@ in {
";
services.liquidd.listen = true;
services.liquidd.proxy = config.services.tor.client.socksListenAddress;
services.liquidd.enforceTor = true;
services.liquidd.port = 7042;
services.tor.hiddenServices.liquidd = {
map = [{
port = config.services.liquidd.port; toPort = config.services.liquidd.port;
}];
version = 3;
};

services.spark-wallet.onion-service = true;
services.electrs.port = 50001;
services.electrs.enforceTor = true;
services.electrs.onionport = 50002;
services.electrs.nginxport = 50003;
services.electrs.high-memory = false;
Expand Down
7 changes: 2 additions & 5 deletions modules/onion-chef.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
with lib;

let
nix-bitcoin-services = pkgs.callPackage ./nix-bitcoin-services.nix { };
cfg = config.services.onion-chef;
dataDir = "/var/lib/onion-chef/";
onion-chef-script = pkgs.writeScript "onion-chef.sh" ''
Expand Down Expand Up @@ -77,11 +78,7 @@ in {
ExecStart = "${pkgs.bash}/bin/bash ${onion-chef-script}";
User = "root";
Type = "oneshot";
PrivateTmp = "true";
ProtectSystem = "full";
NoNewPrivileges = "true";
PrivateDevices = "true";
};
} // nix-bitcoin-services.defaultHardening;
};
};
}
Loading

0 comments on commit 54a6a33

Please sign in to comment.