Merge #202: RPC Whitelist
5086fc3234
bitcoin: drive-by prune fix (nixbitcoin)21c0fb440d
rpcwhitelist: add feature test (nixbitcoin)1bf45a9547
bitcoind: add rpcwhitelist feature (nixbitcoin)5a978a2836
bitcoind: switch from rpcpassword to rpcauth (nixbitcoin) Pull request description: ACKs for top commit: jonasnick: ACK5086fc3234
Tree-SHA512: f456f3409b3bc22dc9ad1296fa00f7e8a442b4072cd4deda067bf2f951eb7d4302283b816ebf769abaa7017e26b19b734f66604cd435d99b810ce535735f7c08
This commit is contained in:
commit
9e453bab86
@ -5,6 +5,7 @@ with lib;
|
|||||||
let
|
let
|
||||||
cfg = config.services.bitcoind;
|
cfg = config.services.bitcoind;
|
||||||
inherit (config) nix-bitcoin-services;
|
inherit (config) nix-bitcoin-services;
|
||||||
|
secretsDir = config.nix-bitcoin.secretsDir;
|
||||||
|
|
||||||
configFile = pkgs.writeText "bitcoin.conf" ''
|
configFile = pkgs.writeText "bitcoin.conf" ''
|
||||||
# We're already logging via journald
|
# We're already logging via journald
|
||||||
@ -12,7 +13,7 @@ let
|
|||||||
|
|
||||||
${optionalString cfg.testnet "testnet=1"}
|
${optionalString cfg.testnet "testnet=1"}
|
||||||
${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"}
|
${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"}
|
||||||
"prune=${toString cfg.prune}
|
prune=${toString cfg.prune}
|
||||||
${optionalString (cfg.sysperms != null) "sysperms=${if cfg.sysperms then "1" else "0"}"}
|
${optionalString (cfg.sysperms != null) "sysperms=${if cfg.sysperms then "1" else "0"}"}
|
||||||
${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"}
|
${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"}
|
||||||
${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"}
|
${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"}
|
||||||
@ -27,14 +28,18 @@ let
|
|||||||
|
|
||||||
# RPC server options
|
# RPC server options
|
||||||
rpcport=${toString cfg.rpc.port}
|
rpcport=${toString cfg.rpc.port}
|
||||||
|
rpcwhitelistdefault=0
|
||||||
${concatMapStringsSep "\n"
|
${concatMapStringsSep "\n"
|
||||||
(rpcUser: "rpcauth=${rpcUser.name}:${rpcUser.passwordHMAC}")
|
(rpcUser: ''
|
||||||
|
rpcauth=${rpcUser.name}:${rpcUser.passwordHMAC}
|
||||||
|
${optionalString (rpcUser.rpcwhitelist != []) "rpcwhitelist=${rpcUser.name}:${lib.strings.concatStringsSep "," rpcUser.rpcwhitelist}"}
|
||||||
|
'')
|
||||||
(attrValues cfg.rpc.users)
|
(attrValues cfg.rpc.users)
|
||||||
}
|
}
|
||||||
${lib.concatMapStrings (rpcbind: "rpcbind=${rpcbind}\n") cfg.rpcbind}
|
${lib.concatMapStrings (rpcbind: "rpcbind=${rpcbind}\n") cfg.rpcbind}
|
||||||
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
|
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
|
||||||
${optionalString (cfg.rpcuser != null) "rpcuser=${cfg.rpcuser}"}
|
# Credentials for bitcoin-cli
|
||||||
${optionalString (cfg.rpcpassword != null) "rpcpassword=${cfg.rpcpassword}"}
|
rpcuser=${cfg.rpc.users.privileged.name}
|
||||||
|
|
||||||
# Wallet options
|
# Wallet options
|
||||||
${optionalString (cfg.addresstype != null) "addresstype=${cfg.addresstype}"}
|
${optionalString (cfg.addresstype != null) "addresstype=${cfg.addresstype}"}
|
||||||
@ -110,13 +115,21 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
passwordHMAC = mkOption {
|
passwordHMAC = mkOption {
|
||||||
type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}");
|
type = types.str;
|
||||||
example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
|
example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
|
||||||
description = ''
|
description = ''
|
||||||
Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the
|
Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the
|
||||||
format <SALT-HEX>$<HMAC-HEX>.
|
format <SALT-HEX>$<HMAC-HEX>.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
rpcwhitelist = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
List of allowed rpc calls for each user.
|
||||||
|
If empty list, rpcwhitelist is disabled for that user.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
name = mkDefault name;
|
name = mkDefault name;
|
||||||
@ -141,16 +154,6 @@ in {
|
|||||||
Allow JSON-RPC connections from specified source.
|
Allow JSON-RPC connections from specified source.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
rpcuser = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = "bitcoinrpc";
|
|
||||||
description = "Username for JSON-RPC connections";
|
|
||||||
};
|
|
||||||
rpcpassword = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Password for JSON-RPC connections";
|
|
||||||
};
|
|
||||||
testnet = mkOption {
|
testnet = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
@ -297,7 +300,10 @@ in {
|
|||||||
preStart = ''
|
preStart = ''
|
||||||
${optionalString cfg.dataDirReadableByGroup "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")
|
cfgpre=$(cat ${configFile}; printf "rpcpassword="; cat "${secretsDir}/bitcoin-rpcpassword-privileged")
|
||||||
|
cfg=$(echo "$cfgpre" | \
|
||||||
|
sed "s/bitcoin-HMAC-privileged/$(cat ${secretsDir}/bitcoin-HMAC-privileged)/g" | \
|
||||||
|
sed "s/bitcoin-HMAC-public/$(cat ${secretsDir}/bitcoin-HMAC-public)/g")
|
||||||
confFile='${cfg.dataDir}/bitcoin.conf'
|
confFile='${cfg.dataDir}/bitcoin.conf'
|
||||||
if [[ ! -e $confFile || $cfg != $(cat $confFile) ]]; then
|
if [[ ! -e $confFile || $cfg != $(cat $confFile) ]]; then
|
||||||
install -o '${cfg.user}' -g '${cfg.group}' -m 640 <(echo "$cfg") $confFile
|
install -o '${cfg.user}' -g '${cfg.group}' -m 640 <(echo "$cfg") $confFile
|
||||||
@ -355,9 +361,13 @@ in {
|
|||||||
users.groups.${cfg.group} = {};
|
users.groups.${cfg.group} = {};
|
||||||
users.groups.bitcoinrpc = {};
|
users.groups.bitcoinrpc = {};
|
||||||
|
|
||||||
nix-bitcoin.secrets.bitcoin-rpcpassword = {
|
nix-bitcoin.secrets.bitcoin-rpcpassword-privileged.user = "bitcoin";
|
||||||
|
nix-bitcoin.secrets.bitcoin-rpcpassword-public = {
|
||||||
user = "bitcoin";
|
user = "bitcoin";
|
||||||
group = "bitcoinrpc";
|
group = "bitcoinrpc";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nix-bitcoin.secrets.bitcoin-HMAC-privileged.user = "bitcoin";
|
||||||
|
nix-bitcoin.secrets.bitcoin-HMAC-public.user = "bitcoin";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ let
|
|||||||
always-use-proxy=${if cfg.always-use-proxy then "true" else "false"}
|
always-use-proxy=${if cfg.always-use-proxy then "true" else "false"}
|
||||||
${optionalString (cfg.bind-addr != null) "bind-addr=${cfg.bind-addr}"}
|
${optionalString (cfg.bind-addr != null) "bind-addr=${cfg.bind-addr}"}
|
||||||
${optionalString (cfg.bitcoin-rpcconnect != null) "bitcoin-rpcconnect=${cfg.bitcoin-rpcconnect}"}
|
${optionalString (cfg.bitcoin-rpcconnect != null) "bitcoin-rpcconnect=${cfg.bitcoin-rpcconnect}"}
|
||||||
bitcoin-rpcuser=${config.services.bitcoind.rpcuser}
|
bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name}
|
||||||
rpc-file-mode=0660
|
rpc-file-mode=0660
|
||||||
'';
|
'';
|
||||||
in {
|
in {
|
||||||
@ -112,7 +112,7 @@ in {
|
|||||||
# The RPC socket has to be removed otherwise we might have stale sockets
|
# The RPC socket has to be removed otherwise we might have stale sockets
|
||||||
rm -f ${cfg.dataDir}/bitcoin/lightning-rpc
|
rm -f ${cfg.dataDir}/bitcoin/lightning-rpc
|
||||||
chmod 600 ${cfg.dataDir}/config
|
chmod 600 ${cfg.dataDir}/config
|
||||||
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/config'
|
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)" >> '${cfg.dataDir}/config'
|
||||||
${optionalString cfg.announce-tor "echo announce-addr=$(cat /var/lib/onion-chef/clightning/clightning) >> '${cfg.dataDir}/config'"}
|
${optionalString cfg.announce-tor "echo announce-addr=$(cat /var/lib/onion-chef/clightning/clightning) >> '${cfg.dataDir}/config'"}
|
||||||
'';
|
'';
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
|
@ -74,7 +74,7 @@ in {
|
|||||||
requires = [ "bitcoind.service" ];
|
requires = [ "bitcoind.service" ];
|
||||||
after = [ "bitcoind.service" ];
|
after = [ "bitcoind.service" ];
|
||||||
preStart = ''
|
preStart = ''
|
||||||
echo "cookie = \"${config.services.bitcoind.rpcuser}:$(cat ${secretsDir}/bitcoin-rpcpassword)\"" \
|
echo "cookie = \"${config.services.bitcoind.rpc.users.public.name}:$(cat ${secretsDir}/bitcoin-rpcpassword-public)\"" \
|
||||||
> electrs.toml
|
> electrs.toml
|
||||||
'';
|
'';
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
|
@ -246,7 +246,7 @@ in {
|
|||||||
chmod 640 '${cfg.dataDir}/elements.conf'
|
chmod 640 '${cfg.dataDir}/elements.conf'
|
||||||
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
|
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
|
||||||
echo "rpcpassword=$(cat ${secretsDir}/liquid-rpcpassword)" >> '${cfg.dataDir}/elements.conf'
|
echo "rpcpassword=$(cat ${secretsDir}/liquid-rpcpassword)" >> '${cfg.dataDir}/elements.conf'
|
||||||
echo "mainchainrpcpassword=$(cat ${secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/elements.conf'
|
echo "mainchainrpcpassword=$(cat ${secretsDir}/bitcoin-rpcpassword-public)" >> '${cfg.dataDir}/elements.conf'
|
||||||
'';
|
'';
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
|
@ -25,7 +25,7 @@ let
|
|||||||
${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"}
|
${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"}
|
||||||
|
|
||||||
bitcoind.rpchost=${cfg.bitcoind-host}
|
bitcoind.rpchost=${cfg.bitcoind-host}
|
||||||
bitcoind.rpcuser=${config.services.bitcoind.rpcuser}
|
bitcoind.rpcuser=${config.services.bitcoind.rpc.users.public.name}
|
||||||
bitcoind.zmqpubrawblock=${config.services.bitcoind.zmqpubrawblock}
|
bitcoind.zmqpubrawblock=${config.services.bitcoind.zmqpubrawblock}
|
||||||
bitcoind.zmqpubrawtx=${config.services.bitcoind.zmqpubrawtx}
|
bitcoind.zmqpubrawtx=${config.services.bitcoind.zmqpubrawtx}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ in {
|
|||||||
after = [ "bitcoind.service" ] ++ onion-chef-service;
|
after = [ "bitcoind.service" ] ++ onion-chef-service;
|
||||||
preStart = ''
|
preStart = ''
|
||||||
install -m600 ${configFile} '${cfg.dataDir}/lnd.conf'
|
install -m600 ${configFile} '${cfg.dataDir}/lnd.conf'
|
||||||
echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/lnd.conf'
|
echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword-public)" >> '${cfg.dataDir}/lnd.conf'
|
||||||
${optionalString cfg.announce-tor "echo externalip=$(cat /var/lib/onion-chef/lnd/lnd) >> '${cfg.dataDir}/lnd.conf'"}
|
${optionalString cfg.announce-tor "echo externalip=$(cat /var/lib/onion-chef/lnd/lnd) >> '${cfg.dataDir}/lnd.conf'"}
|
||||||
'';
|
'';
|
||||||
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
serviceConfig = nix-bitcoin-services.defaultHardening // {
|
||||||
|
@ -73,6 +73,76 @@ in {
|
|||||||
discover = false;
|
discover = false;
|
||||||
addresstype = "bech32";
|
addresstype = "bech32";
|
||||||
dbCache = 1000;
|
dbCache = 1000;
|
||||||
|
rpc.users.privileged = {
|
||||||
|
name = "bitcoinrpc";
|
||||||
|
# Placeholder to be sed'd out by bitcoind preStart
|
||||||
|
passwordHMAC = "bitcoin-HMAC-privileged";
|
||||||
|
};
|
||||||
|
rpc.users.public = {
|
||||||
|
name = "publicrpc";
|
||||||
|
# Placeholder to be sed'd out by bitcoind preStart
|
||||||
|
passwordHMAC = "bitcoin-HMAC-public";
|
||||||
|
rpcwhitelist = [
|
||||||
|
"echo"
|
||||||
|
"getinfo"
|
||||||
|
# Blockchain
|
||||||
|
"getbestblockhash"
|
||||||
|
"getblock"
|
||||||
|
"getblockchaininfo"
|
||||||
|
"getblockcount"
|
||||||
|
"getblockfilter"
|
||||||
|
"getblockhash"
|
||||||
|
"getblockheader"
|
||||||
|
"getblockstats"
|
||||||
|
"getchaintips"
|
||||||
|
"getchaintxstats"
|
||||||
|
"getdifficulty"
|
||||||
|
"getmempoolancestors"
|
||||||
|
"getmempooldescendants"
|
||||||
|
"getmempoolentry"
|
||||||
|
"getmempoolinfo"
|
||||||
|
"getrawmempool"
|
||||||
|
"gettxout"
|
||||||
|
"gettxoutproof"
|
||||||
|
"gettxoutsetinfo"
|
||||||
|
"scantxoutset"
|
||||||
|
"verifytxoutproof"
|
||||||
|
# Mining
|
||||||
|
"getblocktemplate"
|
||||||
|
"getmininginfo"
|
||||||
|
"getnetworkhashps"
|
||||||
|
# Network
|
||||||
|
"getnetworkinfo"
|
||||||
|
# Rawtransactions
|
||||||
|
"analyzepsbt"
|
||||||
|
"combinepsbt"
|
||||||
|
"combinerawtransaction"
|
||||||
|
"converttopsbt"
|
||||||
|
"createpsbt"
|
||||||
|
"createrawtransaction"
|
||||||
|
"decodepsbt"
|
||||||
|
"decoderawtransaction"
|
||||||
|
"decodescript"
|
||||||
|
"finalizepsbt"
|
||||||
|
"fundrawtransaction"
|
||||||
|
"getrawtransaction"
|
||||||
|
"joinpsbts"
|
||||||
|
"sendrawtransaction"
|
||||||
|
"signrawtransactionwithkey"
|
||||||
|
"testmempoolaccept"
|
||||||
|
"utxoupdatepsbt"
|
||||||
|
# Util
|
||||||
|
"createmultisig"
|
||||||
|
"deriveaddresses"
|
||||||
|
"estimatesmartfee"
|
||||||
|
"getdescriptorinfo"
|
||||||
|
"signmessagewithprivkey"
|
||||||
|
"validateaddress"
|
||||||
|
"verifymessage"
|
||||||
|
# Zmq
|
||||||
|
"getzmqnotifications"
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
services.tor.hiddenServices.bitcoind = mkHiddenService { port = cfg.bitcoind.port; toHost = cfg.bitcoind.bind; };
|
services.tor.hiddenServices.bitcoind = mkHiddenService { port = cfg.bitcoind.port; toHost = cfg.bitcoind.bind; };
|
||||||
|
|
||||||
@ -96,7 +166,7 @@ in {
|
|||||||
rpcuser = "liquidrpc";
|
rpcuser = "liquidrpc";
|
||||||
prune = 1000;
|
prune = 1000;
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
mainchainrpcuser=${cfg.bitcoind.rpcuser}
|
mainchainrpcuser=${config.services.bitcoind.rpc.users.public.name}
|
||||||
mainchainrpcport=8332
|
mainchainrpcport=8332
|
||||||
'';
|
'';
|
||||||
validatepegin = true;
|
validatepegin = true;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
{ pkgs }: with pkgs;
|
{ pkgs }: with pkgs;
|
||||||
|
|
||||||
|
let
|
||||||
|
rpcauth = pkgs.writeScriptBin "rpcauth" (builtins.readFile ./rpcauth/rpcauth.py);
|
||||||
|
in
|
||||||
writeScript "generate-secrets" ''
|
writeScript "generate-secrets" ''
|
||||||
export PATH=${lib.makeBinPath [ coreutils apg openssl ]}
|
export PATH=${lib.makeBinPath [ coreutils apg openssl gnugrep rpcauth python35 ]}
|
||||||
. ${./generate-secrets.sh} ${./openssl.cnf}
|
. ${./generate-secrets.sh} ${./openssl.cnf}
|
||||||
''
|
''
|
||||||
|
@ -6,12 +6,15 @@ makePasswordSecret() {
|
|||||||
[[ -e $1 ]] || apg -m 20 -x 20 -M Ncl -n 1 > "$1"
|
[[ -e $1 ]] || apg -m 20 -x 20 -M Ncl -n 1 > "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
makePasswordSecret bitcoin-rpcpassword
|
makePasswordSecret bitcoin-rpcpassword-privileged
|
||||||
|
makePasswordSecret bitcoin-rpcpassword-public
|
||||||
makePasswordSecret lnd-wallet-password
|
makePasswordSecret lnd-wallet-password
|
||||||
makePasswordSecret liquid-rpcpassword
|
makePasswordSecret liquid-rpcpassword
|
||||||
makePasswordSecret lightning-charge-token
|
makePasswordSecret lightning-charge-token
|
||||||
makePasswordSecret spark-wallet-password
|
makePasswordSecret spark-wallet-password
|
||||||
|
|
||||||
|
[[ -e bitcoin-HMAC-privileged ]] || rpcauth privileged $(cat bitcoin-rpcpassword-privileged) | grep rpcauth | cut -d ':' -f 2 > bitcoin-HMAC-privileged
|
||||||
|
[[ -e bitcoin-HMAC-public ]] || rpcauth public $(cat bitcoin-rpcpassword-public) | grep rpcauth | cut -d ':' -f 2 > bitcoin-HMAC-public
|
||||||
[[ -e lightning-charge-env ]] || echo "API_TOKEN=$(cat lightning-charge-token)" > lightning-charge-env
|
[[ -e lightning-charge-env ]] || echo "API_TOKEN=$(cat lightning-charge-token)" > lightning-charge-env
|
||||||
[[ -e nanopos-env ]] || echo "CHARGE_TOKEN=$(cat lightning-charge-token)" > nanopos-env
|
[[ -e nanopos-env ]] || echo "CHARGE_TOKEN=$(cat lightning-charge-token)" > nanopos-env
|
||||||
[[ -e spark-wallet-login ]] || echo "login=spark-wallet:$(cat spark-wallet-password)" > spark-wallet-login
|
[[ -e spark-wallet-login ]] || echo "login=spark-wallet:$(cat spark-wallet-password)" > spark-wallet-login
|
||||||
|
46
pkgs/generate-secrets/rpcauth/rpcauth.py
Normal file
46
pkgs/generate-secrets/rpcauth/rpcauth.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from base64 import urlsafe_b64encode
|
||||||
|
from binascii import hexlify
|
||||||
|
from getpass import getpass
|
||||||
|
from os import urandom
|
||||||
|
|
||||||
|
import hmac
|
||||||
|
|
||||||
|
def generate_salt(size):
|
||||||
|
"""Create size byte hex salt"""
|
||||||
|
return hexlify(urandom(size)).decode()
|
||||||
|
|
||||||
|
def generate_password():
|
||||||
|
"""Create 32 byte b64 password"""
|
||||||
|
return urlsafe_b64encode(urandom(32)).decode('utf-8')
|
||||||
|
|
||||||
|
def password_to_hmac(salt, password):
|
||||||
|
m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), 'SHA256')
|
||||||
|
return m.hexdigest()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = ArgumentParser(description='Create login credentials for a JSON-RPC user')
|
||||||
|
parser.add_argument('username', help='the username for authentication')
|
||||||
|
parser.add_argument('password', help='leave empty to generate a random password or specify "-" to prompt for password', nargs='?')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not args.password:
|
||||||
|
args.password = generate_password()
|
||||||
|
elif args.password == '-':
|
||||||
|
args.password = getpass()
|
||||||
|
|
||||||
|
# Create 16 byte hex salt
|
||||||
|
salt = generate_salt(16)
|
||||||
|
password_hmac = password_to_hmac(salt, args.password)
|
||||||
|
|
||||||
|
print('String to be appended to bitcoin.conf:')
|
||||||
|
print('rpcauth={0}:{1}${2}'.format(args.username, salt, password_hmac))
|
||||||
|
print('Your password:\n{0}'.format(args.password))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -7,6 +7,15 @@ succeed('[[ $(stat -c "%U:%G %a" /secrets/dummy) = "root:root 440" ]]')
|
|||||||
assert_running("bitcoind")
|
assert_running("bitcoind")
|
||||||
machine.wait_until_succeeds("bitcoin-cli getnetworkinfo")
|
machine.wait_until_succeeds("bitcoin-cli getnetworkinfo")
|
||||||
assert_matches("su operator -c 'bitcoin-cli getnetworkinfo' | jq", '"version"')
|
assert_matches("su operator -c 'bitcoin-cli getnetworkinfo' | jq", '"version"')
|
||||||
|
# Test RPC Whitelist
|
||||||
|
machine.wait_until_succeeds("su operator -c 'bitcoin-cli help'")
|
||||||
|
# Restating rpcuser & rpcpassword overrides privileged credentials
|
||||||
|
machine.fail(
|
||||||
|
"bitcoin-cli -rpcuser=publicrpc -rpcpassword=$(cat /secrets/bitcoin-rpcpassword-public) help"
|
||||||
|
)
|
||||||
|
machine.wait_until_succeeds(
|
||||||
|
log_has_string("bitcoind", "RPC User publicrpc not allowed to call method help")
|
||||||
|
)
|
||||||
|
|
||||||
assert_running("electrs")
|
assert_running("electrs")
|
||||||
machine.wait_for_open_port(4224) # prometeus metrics provider
|
machine.wait_for_open_port(4224) # prometeus metrics provider
|
||||||
|
@ -19,6 +19,15 @@ succeed('[[ $(stat -c "%U:%G %a" /secrets/dummy) = "root:root 440" ]]')
|
|||||||
assert_running("bitcoind")
|
assert_running("bitcoind")
|
||||||
machine.wait_until_succeeds("bitcoin-cli getnetworkinfo")
|
machine.wait_until_succeeds("bitcoin-cli getnetworkinfo")
|
||||||
assert_matches("su operator -c 'bitcoin-cli getnetworkinfo' | jq", '"version"')
|
assert_matches("su operator -c 'bitcoin-cli getnetworkinfo' | jq", '"version"')
|
||||||
|
# Test RPC Whitelist
|
||||||
|
machine.wait_until_succeeds("su operator -c 'bitcoin-cli help'")
|
||||||
|
# Restating rpcuser & rpcpassword overrides privileged credentials
|
||||||
|
machine.fail(
|
||||||
|
"bitcoin-cli -rpcuser=publicrpc -rpcpassword=$(cat /secrets/bitcoin-rpcpassword-public) help"
|
||||||
|
)
|
||||||
|
machine.wait_until_succeeds(
|
||||||
|
log_has_string("bitcoind", "RPC User publicrpc not allowed to call method help")
|
||||||
|
)
|
||||||
|
|
||||||
assert_running("electrs")
|
assert_running("electrs")
|
||||||
machine.wait_until_succeeds(
|
machine.wait_until_succeeds(
|
||||||
|
Loading…
Reference in New Issue
Block a user