mirror of
https://github.com/fort-nix/nix-bitcoin.git
synced 2024-11-22 22:33:46 +03:00
secrets: allow extending generate-secrets
`generate-secrets` is no longer a monolithic script. Instead, it's composed of the values of option `nix-bitcoin.generateSecretsCmds`. This has the following advantages: - generate-secrets is now extensible by users - Only secrets of enabled services are generated - RPC IPs in the `lnd` and `loop` certs are no longer hardcoded. Secrets are no longer automatically generated when entering nix-shell. Instead, they are generated before deployment (via `krops-deploy`) because secrets generation is now dependant on the node configuration.
This commit is contained in:
parent
24fd1e9bdc
commit
a2466b1127
@ -21,12 +21,22 @@ stdenv.mkDerivation rec {
|
|||||||
${toString ./fetch-release}
|
${toString ./fetch-release}
|
||||||
}
|
}
|
||||||
|
|
||||||
krops-deploy() {
|
generate-secrets() {(
|
||||||
|
set -euo pipefail
|
||||||
|
genSecrets=$(nix-build --no-out-link -I nixos-config="${cfgDir}/configuration.nix" \
|
||||||
|
'<nixpkgs/nixos>' -A config.nix-bitcoin.generateSecretsScript)
|
||||||
|
mkdir -p "${cfgDir}/secrets"
|
||||||
|
(cd "${cfgDir}/secrets"; $genSecrets)
|
||||||
|
)}
|
||||||
|
|
||||||
|
krops-deploy() {(
|
||||||
|
set -euo pipefail
|
||||||
|
generate-secrets
|
||||||
# Ensure strict permissions on secrets/ directory before rsyncing it to
|
# Ensure strict permissions on secrets/ directory before rsyncing it to
|
||||||
# the target machine
|
# the target machine
|
||||||
chmod 700 "${cfgDir}/secrets"
|
chmod 700 "${cfgDir}/secrets"
|
||||||
$(nix-build --no-out-link "${cfgDir}/krops/deploy.nix")
|
$(nix-build --no-out-link "${cfgDir}/krops/deploy.nix")
|
||||||
}
|
)}
|
||||||
|
|
||||||
# Print logo if
|
# Print logo if
|
||||||
# 1. stdout is a TTY, i.e. we're not piping the output
|
# 1. stdout is a TTY, i.e. we're not piping the output
|
||||||
|
@ -98,6 +98,12 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
nix-bitcoin.secrets.backup-encryption-env.user = "root";
|
nix-bitcoin.secrets.backup-encryption-env.user = "root";
|
||||||
|
nix-bitcoin.generateSecretsCmds.backups = ''
|
||||||
|
makePasswordSecret backup-encryption-password
|
||||||
|
if [[ backup-encryption-password -nt backup-encryption-env ]]; then
|
||||||
|
echo "PASSPHRASE=$(cat backup-encryption-password)" > backup-encryption-env
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
services.backups.postgresqlDatabases = mkIf config.services.btcpayserver.enable [ "btcpaydb" ];
|
services.backups.postgresqlDatabases = mkIf config.services.btcpayserver.enable [ "btcpaydb" ];
|
||||||
};
|
};
|
||||||
|
@ -394,15 +394,22 @@ in {
|
|||||||
};
|
};
|
||||||
users.groups.${cfg.group} = {};
|
users.groups.${cfg.group} = {};
|
||||||
users.groups.bitcoinrpc-public = {};
|
users.groups.bitcoinrpc-public = {};
|
||||||
|
|
||||||
nix-bitcoin.operator.groups = [ cfg.group ];
|
nix-bitcoin.operator.groups = [ cfg.group ];
|
||||||
|
|
||||||
nix-bitcoin.secrets.bitcoin-rpcpassword-privileged.user = cfg.user;
|
nix-bitcoin.secrets = {
|
||||||
nix-bitcoin.secrets.bitcoin-rpcpassword-public = {
|
bitcoin-rpcpassword-privileged.user = cfg.user;
|
||||||
user = cfg.user;
|
bitcoin-rpcpassword-public = {
|
||||||
group = "bitcoinrpc-public";
|
user = cfg.user;
|
||||||
};
|
group = "bitcoinrpc-public";
|
||||||
|
};
|
||||||
|
|
||||||
nix-bitcoin.secrets.bitcoin-HMAC-privileged.user = cfg.user;
|
bitcoin-HMAC-privileged.user = cfg.user;
|
||||||
nix-bitcoin.secrets.bitcoin-HMAC-public.user = cfg.user;
|
bitcoin-HMAC-public.user = cfg.user;
|
||||||
|
};
|
||||||
|
nix-bitcoin.generateSecretsCmds.bitcoind = ''
|
||||||
|
makeBitcoinRPCPassword privileged
|
||||||
|
makeBitcoinRPCPassword public
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -253,5 +253,8 @@ in {
|
|||||||
};
|
};
|
||||||
bitcoin-HMAC-btcpayserver.user = cfg.bitcoind.user;
|
bitcoin-HMAC-btcpayserver.user = cfg.bitcoind.user;
|
||||||
};
|
};
|
||||||
|
nix-bitcoin.generateSecretsCmds.btcpayserver = ''
|
||||||
|
makeBitcoinRPCPassword btcpayserver
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -131,5 +131,8 @@ in {
|
|||||||
bitcoin-rpcpassword-joinmarket-ob-watcher.user = cfg.user;
|
bitcoin-rpcpassword-joinmarket-ob-watcher.user = cfg.user;
|
||||||
bitcoin-HMAC-joinmarket-ob-watcher.user = bitcoind.user;
|
bitcoin-HMAC-joinmarket-ob-watcher.user = bitcoind.user;
|
||||||
};
|
};
|
||||||
|
nix-bitcoin.generateSecretsCmds.joinmarket-ob-watcher = ''
|
||||||
|
makeBitcoinRPCPassword joinmarket-ob-watcher
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -305,6 +305,9 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
nix-bitcoin.secrets.jm-wallet-password.user = cfg.user;
|
nix-bitcoin.secrets.jm-wallet-password.user = cfg.user;
|
||||||
|
nix-bitcoin.generateSecretsCmds.joinmarket = ''
|
||||||
|
makePasswordSecret jm-wallet-password
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|
||||||
(mkIf cfg.yieldgenerator.enable {
|
(mkIf cfg.yieldgenerator.enable {
|
||||||
|
@ -112,5 +112,8 @@ in {
|
|||||||
loop-key.user = lnd.user;
|
loop-key.user = lnd.user;
|
||||||
loop-cert.user = lnd.user;
|
loop-cert.user = lnd.user;
|
||||||
};
|
};
|
||||||
|
nix-bitcoin.generateSecretsCmds.lightning-loop = ''
|
||||||
|
makeCert loop '${optionalString (cfg.rpcAddress != "localhost") "IP:${cfg.rpcAddress}"}'
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -247,5 +247,8 @@ in {
|
|||||||
nix-bitcoin.operator.groups = [ cfg.group ];
|
nix-bitcoin.operator.groups = [ cfg.group ];
|
||||||
|
|
||||||
nix-bitcoin.secrets.liquid-rpcpassword.user = cfg.user;
|
nix-bitcoin.secrets.liquid-rpcpassword.user = cfg.user;
|
||||||
|
nix-bitcoin.generateSecretsCmds.liquid = ''
|
||||||
|
makePasswordSecret liquid-rpcpassword
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,14 @@ in {
|
|||||||
lnd-wallet-password.user = cfg.user;
|
lnd-wallet-password.user = cfg.user;
|
||||||
lnd-key.user = cfg.user;
|
lnd-key.user = cfg.user;
|
||||||
lnd-cert.user = cfg.user;
|
lnd-cert.user = cfg.user;
|
||||||
lnd-cert.permissions = "0444"; # world readable
|
lnd-cert.permissions = "444"; # world readable
|
||||||
};
|
};
|
||||||
|
# Advantages of manually pre-generating certs:
|
||||||
|
# - Reduces dynamic state
|
||||||
|
# - Enables deployment of a mesh of server plus client nodes with predefined certs
|
||||||
|
nix-bitcoin.generateSecretsCmds.lnd = ''
|
||||||
|
makePasswordSecret lnd-wallet-password
|
||||||
|
makeCert lnd '${optionalString (cfg.rpcAddress != "localhost") "IP:${cfg.rpcAddress}"}'
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.nix-bitcoin;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.nix-bitcoin = {
|
options.nix-bitcoin = {
|
||||||
secretsDir = mkOption {
|
secretsDir = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
@ -29,6 +26,14 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
generateSecretsCmds = mkOption {
|
||||||
|
type = types.attrsOf types.str;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Bash expressions for generating secrets.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
# Currently, this is used only by ../deployment/nixops.nix
|
# Currently, this is used only by ../deployment/nixops.nix
|
||||||
deployment.secretsDir = mkOption {
|
deployment.secretsDir = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
@ -72,8 +77,68 @@ in
|
|||||||
- Set `nix-bitcoin.secretsSetupMethod = "manual"` if you want to manually setup secrets
|
- Set `nix-bitcoin.secretsSetupMethod = "manual"` if you want to manually setup secrets
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
generateSecretsScript = mkOption {
|
||||||
|
internal = true;
|
||||||
|
default = let
|
||||||
|
rpcauthSrc = builtins.fetchurl {
|
||||||
|
url = "https://raw.githubusercontent.com/bitcoin/bitcoin/d6cde007db9d3e6ee93bd98a9bbfdce9bfa9b15b/share/rpcauth/rpcauth.py";
|
||||||
|
sha256 = "189mpplam6yzizssrgiyv70c9899ggh8cac76j4n7v0xqzfip07n";
|
||||||
|
};
|
||||||
|
rpcauth = pkgs.writers.writeBash "rpcauth" ''
|
||||||
|
exec ${pkgs.python3}/bin/python ${rpcauthSrc} "$@"
|
||||||
|
'';
|
||||||
|
in pkgs.writers.writeBash "generate-secrets" ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
export PATH=${lib.makeBinPath (with pkgs; [ coreutils gnugrep ])}
|
||||||
|
|
||||||
|
makePasswordSecret() {
|
||||||
|
# Passwords have alphabet {a-z, A-Z, 0-9} and ~119 bits of entropy
|
||||||
|
[[ -e $1 ]] || ${pkgs.pwgen}/bin/pwgen -s 20 1 > "$1"
|
||||||
|
}
|
||||||
|
makeBitcoinRPCPassword() {
|
||||||
|
user=$1
|
||||||
|
file=bitcoin-rpcpassword-$user
|
||||||
|
HMACfile=bitcoin-HMAC-$user
|
||||||
|
makePasswordSecret "$file"
|
||||||
|
if [[ $file -nt $HMACfile ]]; then
|
||||||
|
${rpcauth} $user $(cat "$file") | grep rpcauth | cut -d ':' -f 2 > "$HMACfile"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
makeCert() {
|
||||||
|
name=$1
|
||||||
|
# Add leading comma if not empty
|
||||||
|
extraAltNames=''${2:+,}''${2:-}
|
||||||
|
if [[ ! -e $name-key ]]; then
|
||||||
|
# Create new key and cert
|
||||||
|
doMakeCert "-newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -keyout $name-key"
|
||||||
|
elif [[ ! -e $name-cert \
|
||||||
|
|| $(cat "$name-cert-alt-names" 2>/dev/null) != $extraAltNames ]]; then
|
||||||
|
# Create cert from existing key
|
||||||
|
doMakeCert "-key $name-key"
|
||||||
|
fi;
|
||||||
|
}
|
||||||
|
doMakeCert() {
|
||||||
|
# This fn uses global variables `name` and `extraAltNames`
|
||||||
|
keyOpts=$1
|
||||||
|
${pkgs.openssl}/bin/openssl req -x509 \
|
||||||
|
-sha256 -days 3650 $keyOpts -out "$name-cert" \
|
||||||
|
-subj "/CN=localhost/O=$name" \
|
||||||
|
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1$extraAltNames"
|
||||||
|
echo "$extraAltNames" > "$name-cert-alt-names"
|
||||||
|
}
|
||||||
|
|
||||||
|
umask u=rw,go=
|
||||||
|
${builtins.concatStringsSep "\n" (builtins.attrValues cfg.generateSecretsCmds)}
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cfg = config.nix-bitcoin;
|
||||||
|
in {
|
||||||
|
inherit options;
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
# This target is active when secrets have been setup successfully.
|
# This target is active when secrets have been setup successfully.
|
||||||
systemd.targets.nix-bitcoin-secrets = mkIf (cfg.secretsSetupMethod != "manual") {
|
systemd.targets.nix-bitcoin-secrets = mkIf (cfg.secretsSetupMethod != "manual") {
|
||||||
@ -106,7 +171,7 @@ in
|
|||||||
cd "${cfg.secretsDir}"
|
cd "${cfg.secretsDir}"
|
||||||
chown root: .
|
chown root: .
|
||||||
chmod 0700 .
|
chmod 0700 .
|
||||||
${cfg.pkgs.generate-secrets}
|
${cfg.generateSecretsScript}
|
||||||
''}
|
''}
|
||||||
|
|
||||||
setupSecret() {
|
setupSecret() {
|
||||||
@ -140,9 +205,11 @@ in
|
|||||||
|
|
||||||
# Make all other files accessible to root only
|
# Make all other files accessible to root only
|
||||||
unprocessedFiles=$(comm -23 <(printf '%s\n' *) <(printf '%s\n' "''${processedFiles[@]}" | sort))
|
unprocessedFiles=$(comm -23 <(printf '%s\n' *) <(printf '%s\n' "''${processedFiles[@]}" | sort))
|
||||||
IFS=$'\n'
|
if [[ $unprocessedFiles ]]; then
|
||||||
chown root: $unprocessedFiles
|
IFS=$'\n'
|
||||||
chmod 0440 $unprocessedFiles
|
chown root: $unprocessedFiles
|
||||||
|
chmod 0440 $unprocessedFiles
|
||||||
|
fi
|
||||||
|
|
||||||
# Now make the secrets dir accessible to other users
|
# Now make the secrets dir accessible to other users
|
||||||
chmod 0751 "$dir"
|
chmod 0751 "$dir"
|
||||||
|
@ -83,6 +83,13 @@ in {
|
|||||||
} // nbLib.allowedIPAddresses cfg.enforceTor
|
} // nbLib.allowedIPAddresses cfg.enforceTor
|
||||||
// nbLib.nodejs;
|
// nbLib.nodejs;
|
||||||
};
|
};
|
||||||
|
|
||||||
nix-bitcoin.secrets.spark-wallet-login.user = cfg.user;
|
nix-bitcoin.secrets.spark-wallet-login.user = cfg.user;
|
||||||
|
nix-bitcoin.generateSecretsCmds.spark-wallet = ''
|
||||||
|
makePasswordSecret spark-wallet-password
|
||||||
|
if [[ spark-wallet-password -nt spark-wallet-login ]]; then
|
||||||
|
echo "login=spark-wallet:$(cat spark-wallet-password)" > spark-wallet-login
|
||||||
|
fi
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
{ pkgs }: with pkgs;
|
|
||||||
|
|
||||||
let
|
|
||||||
rpcauthSrc = builtins.fetchurl {
|
|
||||||
url = "https://raw.githubusercontent.com/bitcoin/bitcoin/d6cde007db9d3e6ee93bd98a9bbfdce9bfa9b15b/share/rpcauth/rpcauth.py";
|
|
||||||
sha256 = "189mpplam6yzizssrgiyv70c9899ggh8cac76j4n7v0xqzfip07n";
|
|
||||||
};
|
|
||||||
rpcauth = pkgs.writeScriptBin "rpcauth" ''
|
|
||||||
exec ${pkgs.python3}/bin/python ${rpcauthSrc} "$@"
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
writers.writeBash "generate-secrets" ''
|
|
||||||
export PATH=${lib.makeBinPath [ coreutils pwgen openssl gnugrep rpcauth ]}
|
|
||||||
. ${./generate-secrets.sh} ${./openssl.cnf}
|
|
||||||
''
|
|
@ -1,44 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
opensslConf=${1:-openssl.cnf}
|
|
||||||
|
|
||||||
makePasswordSecret() {
|
|
||||||
# Passwords have alphabet {a-z, A-Z, 0-9} and ~119 bits of entropy
|
|
||||||
[[ -e $1 ]] || pwgen -s 20 1 > "$1"
|
|
||||||
}
|
|
||||||
makeHMAC() {
|
|
||||||
user=$1
|
|
||||||
rpcauth $user $(cat bitcoin-rpcpassword-$user) | grep rpcauth | cut -d ':' -f 2 > bitcoin-HMAC-$user
|
|
||||||
}
|
|
||||||
|
|
||||||
makePasswordSecret bitcoin-rpcpassword-privileged
|
|
||||||
makePasswordSecret bitcoin-rpcpassword-btcpayserver
|
|
||||||
makePasswordSecret bitcoin-rpcpassword-joinmarket-ob-watcher
|
|
||||||
makePasswordSecret bitcoin-rpcpassword-public
|
|
||||||
makePasswordSecret lnd-wallet-password
|
|
||||||
makePasswordSecret liquid-rpcpassword
|
|
||||||
makePasswordSecret spark-wallet-password
|
|
||||||
makePasswordSecret backup-encryption-password
|
|
||||||
makePasswordSecret jm-wallet-password
|
|
||||||
|
|
||||||
[[ -e bitcoin-HMAC-privileged ]] || makeHMAC privileged
|
|
||||||
[[ -e bitcoin-HMAC-public ]] || makeHMAC public
|
|
||||||
[[ -e bitcoin-HMAC-btcpayserver ]] || makeHMAC btcpayserver
|
|
||||||
[[ -e bitcoin-HMAC-joinmarket-ob-watcher ]] || makeHMAC joinmarket-ob-watcher
|
|
||||||
[[ -e spark-wallet-login ]] || echo "login=spark-wallet:$(cat spark-wallet-password)" > spark-wallet-login
|
|
||||||
[[ -e backup-encryption-env ]] || echo "PASSPHRASE=$(cat backup-encryption-password)" > backup-encryption-env
|
|
||||||
|
|
||||||
makeCert() {
|
|
||||||
if [[ ! -e $name-key || ! -e $name-cert ]]; then
|
|
||||||
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
|
|
||||||
-sha256 -days 3650 -nodes -keyout "$name-key" -out "$name-cert" \
|
|
||||||
-subj "/CN=localhost/O=$name" \
|
|
||||||
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1,IP:169.254.1.14,IP:169.254.1.22"
|
|
||||||
# TODO: Remove hardcoded lnd, loopd netns ips
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
makeCert lnd
|
|
||||||
makeCert loop
|
|
@ -1,10 +0,0 @@
|
|||||||
{ pkgs }: with pkgs;
|
|
||||||
|
|
||||||
let
|
|
||||||
generate-secrets = callPackage ./. {};
|
|
||||||
in
|
|
||||||
writeScript "make-secrets" ''
|
|
||||||
# Update from old secrets format
|
|
||||||
[[ -e secrets.nix ]] && . ${./update-secrets.sh}
|
|
||||||
${generate-secrets}
|
|
||||||
''
|
|
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -eo pipefail
|
|
||||||
|
|
||||||
# Update secrets from the old format to the current one where each secret
|
|
||||||
# has a local source file.
|
|
||||||
|
|
||||||
reportError() {
|
|
||||||
echo "Updating secrets failed. (Error in line $1)"
|
|
||||||
echo "The secret files have been moved to secrets/old-secrets"
|
|
||||||
}
|
|
||||||
trap 'reportError $LINENO' ERR
|
|
||||||
|
|
||||||
echo "Updating old secrets to the current format."
|
|
||||||
|
|
||||||
mkdir old-secrets
|
|
||||||
# move all files into old-secrets
|
|
||||||
shopt -s extglob dotglob
|
|
||||||
mv !(old-secrets) old-secrets
|
|
||||||
shopt -u dotglob
|
|
||||||
|
|
||||||
secrets=$(cat old-secrets/secrets.nix)
|
|
||||||
|
|
||||||
extractPassword() {
|
|
||||||
pwName="$1"
|
|
||||||
destFile="${2:-$pwName}"
|
|
||||||
echo "$secrets" | sed -nE "s/.*?$pwName = \"(.*?)\".*/\1/p" > "$destFile"
|
|
||||||
}
|
|
||||||
|
|
||||||
rename() {
|
|
||||||
old="old-secrets/$1"
|
|
||||||
if [[ -e $old ]]; then
|
|
||||||
cp "$old" "$2"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
extractPassword bitcoinrpcpassword bitcoin-rpcpassword
|
|
||||||
extractPassword lnd-wallet-password
|
|
||||||
extractPassword liquidrpcpassword liquid-rpcpassword
|
|
||||||
extractPassword spark-wallet-password
|
|
||||||
|
|
||||||
rename lnd.key lnd-key
|
|
||||||
rename lnd.cert lnd-cert
|
|
||||||
|
|
||||||
rm -r old-secrets
|
|
Loading…
Reference in New Issue
Block a user