lnd, joinmarket: don't write to secrets dir

Keeping the secrets dir read-only is more simple and robust.

- lnd seed mnemonic creation and joinmarket wallet creation can be
  run as the regular service user instead of root.

- It is easier to switch to a third-party secrets deployment
  method in the future.

Don't create a seed mnemonic for lnd when a wallet exists.
This avoids creating unused mnemonics and helps simplifying
the migration command in `versioning.nix`.
This commit is contained in:
Erik Arvstedt 2021-03-10 14:08:37 +01:00
parent 55d87490ec
commit 03db1a61b1
No known key found for this signature in database
GPG key ID: 33312B944DD97846
6 changed files with 56 additions and 33 deletions

View file

@ -4,7 +4,6 @@ with lib;
let
cfg = config.services.backups;
secretsDir = config.nix-bitcoin.secretsDir;
filelist = pkgs.writeText "filelist.txt" ''
${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/blocks"}
@ -12,7 +11,6 @@ let
${config.services.bitcoind.dataDir}
${config.services.clightning.dataDir}
${config.services.lnd.dataDir}
${secretsDir}/lnd-seed-mnemonic
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/blocks"}
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/chainstate"}
${config.services.liquidd.dataDir}
@ -20,8 +18,8 @@ let
${config.services.nbxplorer.dataDir}
${config.services.btcpayserver.dataDir}
${config.services.joinmarket.dataDir}
${secretsDir}/jm-wallet-seed
${config.services.postgresqlBackup.location}/btcpaydb.sql.gz
${optionalString config.nix-bitcoin.generateSecrets "${config.nix-bitcoin.secretsDir}"}
/var/lib/tor
# Extra files
${cfg.extraFiles}

View file

@ -240,20 +240,19 @@ in {
'';
# Generating wallets (jmclient/wallet.py) is only supported for mainnet or testnet
ExecStartPost = mkIf (bitcoind.network == "mainnet")
(nbLib.privileged "joinmarket-create-wallet" ''
(nbLib.script "joinmarket-create-wallet" ''
walletname=wallet.jmdat
wallet=${cfg.dataDir}/wallets/$walletname
if [[ ! -f $wallet ]]; then
echo "Create wallet"
pw=$(cat "${secretsDir}"/jm-wallet-password)
cd ${cfg.dataDir}
if ! ${pkgs.utillinux}/bin/runuser -u ${cfg.user} -- \
${nbPkgs.joinmarket}/bin/jm-genwallet --datadir=${cfg.dataDir} $walletname $pw \
if ! ${nbPkgs.joinmarket}/bin/jm-genwallet --datadir=${cfg.dataDir} $walletname $pw \
| grep 'recovery_seed' \
| cut -d ':' -f2 \
| (umask u=r,go=; cat > "${secretsDir}/jm-wallet-seed"); then
| (umask u=r,go=; cat > jm-wallet-seed); then
echo "wallet creation failed"
rm -f "$wallet" "${secretsDir}/jm-wallet-seed"
rm -f "$wallet" jm-wallet-seed
exit 1
fi
fi

View file

@ -200,32 +200,28 @@ in {
ExecStartPost = let
restUrl = "https://${cfg.restAddress}:${toString cfg.restPort}/v1";
in [
# Run fully privileged for secrets dir write access
(nbLib.privileged "lnd-create-mnemonic" ''
(nbLib.script "lnd-create-wallet" ''
attempts=250
while ! { exec 3>/dev/tcp/${cfg.restAddress}/${toString cfg.restPort} && 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
umask u=r,go=
${pkgs.curl}/bin/curl -s \
--cacert ${secretsDir}/lnd-cert \
-X GET ${restUrl}/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > "$mnemonic"
fi
chown ${cfg.user}: "$mnemonic"
'')
(nbLib.script "lnd-create-wallet" ''
if [[ ! -f ${networkDir}/wallet.db ]]; then
echo Create lnd wallet
mnemonic="${cfg.dataDir}/lnd-seed-mnemonic"
if [[ ! -f "$mnemonic" ]]; then
echo Create lnd seed
umask u=r,go=
${pkgs.curl}/bin/curl -s \
--cacert ${secretsDir}/lnd-cert \
-X GET ${restUrl}/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > "$mnemonic"
fi
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')}" \
\"cipher_seed_mnemonic\": $(cat "$mnemonic" | tr -d '\n')}" \
${restUrl}/initwallet
# Guarantees that RPC calls with cfg.cli succeed after the service is started
@ -248,9 +244,8 @@ in {
while ! { exec 3>/dev/tcp/${cfg.rpcAddress}/${toString cfg.rpcPort}; } &>/dev/null; do
sleep 0.1
done
'')
# Run fully privileged for chown
# Setting macaroon permission for other users needs root permissions
(nbLib.privileged "lnd-create-macaroons" ''
umask ug=r,o=
${lib.concatMapStrings (macaroon: ''

View file

@ -69,6 +69,28 @@ let
(mkOnionServiceChange "clightning")
(mkOnionServiceChange "lnd")
(mkOnionServiceChange "btcpayserver")
{
version = "0.0.41";
condition = config.services.lnd.enable || config.services.joinmarket.enable;
message = let
secretsDir = config.nix-bitcoin.secretsDir;
lnd = config.services.lnd;
jm = config.services.joinmarket;
in ''
Secret files generated by services at runtime are now stored in the service
data dirs instead of the global secrets dir.
To migrate, run the following Bash script as root on your nix-bitcoin node:
if [[ -e ${secretsDir}/lnd-seed-mnemonic ]]; then
install -o ${lnd.user} -g ${lnd.group} -m400 "${secretsDir}/lnd-seed-mnemonic" "${lnd.dataDir}"
fi
if [[ -e ${secretsDir}/jm-wallet-seed ]]; then
install -o ${jm.user} -g ${jm.group} -m400 "${secretsDir}/jm-wallet-seed" "${jm.dataDir}"
fi
rm -f "${secretsDir}"/{lnd-seed-mnemonic,jm-wallet-seed}
'';
}
];
incompatibleChanges = optionals