diff --git a/modules/lnd.nix b/modules/lnd.nix index 720dcb9..a66d9a8 100644 --- a/modules/lnd.nix +++ b/modules/lnd.nix @@ -95,71 +95,73 @@ in { requires = [ "bitcoind.service" ]; after = [ "bitcoind.service" ]; preStart = '' - cp ${configFile} ${cfg.dataDir}/lnd.conf - chown -R 'lnd:lnd' '${cfg.dataDir}' - chmod u=rw,g=r,o= ${cfg.dataDir}/lnd.conf + install -m600 ${configFile} '${cfg.dataDir}/lnd.conf' echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/lnd.conf' ''; serviceConfig = nix-bitcoin-services.defaultHardening // { - PermissionsStartOnly = "true"; ExecStart = "${cfg.package}/bin/lnd --configfile=${cfg.dataDir}/lnd.conf"; User = "lnd"; Restart = "on-failure"; RestartSec = "10s"; - ProtectSystem = "full"; # ToDo: Make more restrictive + ReadWritePaths = "${cfg.dataDir}"; + ExecStartPost = [ + # Run fully privileged for secrets dir write access + "+${nix-bitcoin-services.script '' + attempts=50 + while ! { exec 3>/dev/tcp/127.0.0.1/8080 && exec 3>&-; } &>/dev/null; do + ((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; } + sleep 0.1 + done + + mnemonic=${secretsDir}/lnd-seed-mnemonic + if [[ ! -f $mnemonic ]]; then + echo Create lnd seed + + ${pkgs.curl}/bin/curl -s \ + --cacert ${secretsDir}/lnd-cert \ + -X GET https://127.0.0.1:8080/v1/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > "$mnemonic" + fi + chown lnd: "$mnemonic" + chmod 400 "$mnemonic" + ''}" + "${let + mainnetDir = "${cfg.dataDir}/chain/bitcoin/mainnet"; + in nix-bitcoin-services.script '' + if [[ ! -f ${mainnetDir}/wallet.db ]]; then + echo Create lnd wallet + + ${pkgs.curl}/bin/curl -s --output /dev/null --show-error \ + --cacert ${secretsDir}/lnd-cert \ + -X POST -d "{\"wallet_password\": \"$(cat ${secretsDir}/lnd-wallet-password | tr -d '\n' | base64 -w0)\", \ + \"cipher_seed_mnemonic\": $(cat ${secretsDir}/lnd-seed-mnemonic | tr -d '\n')}" \ + https://127.0.0.1:8080/v1/initwallet + + # Guarantees that RPC calls with cfg.cli succeed after the service is started + echo Wait until wallet is created + while [[ ! -f ${mainnetDir}/admin.macaroon ]]; do + sleep 0.1 + done + else + echo Unlock lnd wallet + + ${pkgs.curl}/bin/curl -s \ + -H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 99999 '${mainnetDir}/admin.macaroon')" \ + --cacert ${secretsDir}/lnd-cert \ + -X POST \ + -d "{\"wallet_password\": \"$(cat ${secretsDir}/lnd-wallet-password | tr -d '\n' | base64 -w0)\"}" \ + https://127.0.0.1:8080/v1/unlockwallet + fi + + # Wait until the RPC port is open + while ! { exec 3>/dev/tcp/127.0.0.1/${toString cfg.rpcPort}; } &>/dev/null; do + sleep 0.1 + done + ''}" + ]; } // (if cfg.enforceTor then nix-bitcoin-services.allowTor else nix-bitcoin-services.allowAnyIP ) // nix-bitcoin-services.allowAnyProtocol; # For ZMQ - postStart = let - mainnetDir = "${cfg.dataDir}/chain/bitcoin/mainnet"; - in '' - umask 377 - - attempts=50 - while ! { exec 3>/dev/tcp/127.0.0.1/8080 && exec 3>&-; } &>/dev/null; do - ((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; } - sleep 0.1 - done - - if [[ ! -f ${secretsDir}/lnd-seed-mnemonic ]]; then - echo Create lnd seed - - ${pkgs.curl}/bin/curl -s \ - --cacert ${secretsDir}/lnd-cert \ - -X GET https://127.0.0.1:8080/v1/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > ${secretsDir}/lnd-seed-mnemonic - fi - - if [[ ! -f ${mainnetDir}/wallet.db ]]; then - echo Create lnd wallet - - ${pkgs.curl}/bin/curl -s --output /dev/null --show-error \ - --cacert ${secretsDir}/lnd-cert \ - -X POST -d "{\"wallet_password\": \"$(cat ${secretsDir}/lnd-wallet-password | tr -d '\n' | base64 -w0)\", \ - \"cipher_seed_mnemonic\": $(cat ${secretsDir}/lnd-seed-mnemonic | tr -d '\n')}" \ - https://127.0.0.1:8080/v1/initwallet - - # Guarantees that RPC calls with cfg.cli succeed after the service is started - echo Wait until wallet is created - while [[ ! -f ${mainnetDir}/admin.macaroon ]]; do - sleep 0.1 - done - else - echo Unlock lnd wallet - - ${pkgs.curl}/bin/curl -s \ - -H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 99999 '${mainnetDir}/admin.macaroon')" \ - --cacert ${secretsDir}/lnd-cert \ - -X POST \ - -d "{\"wallet_password\": \"$(cat ${secretsDir}/lnd-wallet-password | tr -d '\n' | base64 -w0)\"}" \ - https://127.0.0.1:8080/v1/unlockwallet - fi - - # Wait until the RPC port is open - while ! { exec 3>/dev/tcp/127.0.0.1/${toString cfg.rpcPort}; } &>/dev/null; do - sleep 0.1 - done - ''; }; users.users.lnd = { description = "LND User"; diff --git a/modules/modules.nix b/modules/modules.nix index 4c6d291..faf12a7 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -21,7 +21,7 @@ options = { nix-bitcoin-services = lib.mkOption { readOnly = true; - default = import ./nix-bitcoin-services.nix lib; + default = import ./nix-bitcoin-services.nix lib pkgs; }; }; diff --git a/modules/nix-bitcoin-services.nix b/modules/nix-bitcoin-services.nix index e899bd9..db875ba 100644 --- a/modules/nix-bitcoin-services.nix +++ b/modules/nix-bitcoin-services.nix @@ -1,7 +1,7 @@ # See `man systemd.exec` and `man systemd.resource-control` for an explanation # of the various systemd options available through this module. -lib: +lib: pkgs: with lib; { @@ -42,4 +42,9 @@ with lib; to 127.0.0.1;"; ''; }; + + script = src: pkgs.writers.writeBash "script" '' + set -eo pipefail + ${src} + ''; }