fix: rpcauth credentials, reboot survival, system Tor for all containers

- Bitcoin RPC: switch to rpcauth (salted hash in bitcoin.conf, no plaintext
  in config or CLI). Password stable across reboots/restarts/deploys.
- Remove daily-reboot-test.sh cron on both servers
- Enable podman-restart.service for container auto-start after reboot
- System Tor: SocksPort 0.0.0.0:9050 with SocksPolicy for container access
- LND: tor.socks=host.containers.internal:9050 (system Tor, not container)
- Bitcoin: -proxy=host.containers.internal:9050 for Tor outbound
- bitcoin_rpc.rs: reads from secrets file, cached, stable credentials
- package.rs: dynamic rpc_user/rpc_pass, rpcauth hash generation
- network.rs: fix missing send_to_peer args (mesh encryption update)
- first-boot-containers.sh: rpcauth generation, system Tor config
- deploy-to-target.sh: rpcauth credentials, LND config migration
- Mesh: encrypted channel message support (ChaCha20-Poly1305 updates)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-20 11:56:20 +00:00
parent b4d204d1d6
commit b31148a8b7
8 changed files with 278 additions and 60 deletions

View File

@@ -121,6 +121,8 @@ impl RpcHandler {
to_onion,
my_pubkey,
&req_msg.to_string(),
None,
None,
).await?;
// Also add them as a pending peer locally

View File

@@ -193,15 +193,15 @@ impl RpcHandler {
"--restart=unless-stopped", // Auto-restart policy
];
// Read Bitcoin RPC password from secrets for container configs
let rpc_pass = crate::bitcoin_rpc::bitcoin_rpc_password().await;
// Read Bitcoin RPC credentials from cookie file for container configs
let (rpc_user, rpc_pass) = crate::bitcoin_rpc::bitcoin_rpc_credentials().await;
// App-specific configuration (should come from manifest)
let (mut ports, mut volumes, env_vars, custom_command, mut custom_args) = {
let mut allocator = self.port_allocator.lock().map_err(|e| {
anyhow::anyhow!("Port allocator lock poisoned: {}", e)
})?;
get_app_config(package_id, &self.config.host_ip, &mut allocator, &rpc_pass)
get_app_config(package_id, &self.config.host_ip, &mut allocator, &rpc_user, &rpc_pass)
};
// Fedimint Gateway: auto-detect LND and switch to lnd mode
@@ -224,7 +224,7 @@ impl RpcHandler {
"$2y$10$t9YjjxkiktrlYvjajB/zgOMDnSNVg4HqrbDqh47u7Jf42whNdxNqC".to_string(),
"--network".to_string(), "bitcoin".to_string(),
"--bitcoind-url".to_string(), format!("http://{}:8332", self.config.host_ip),
"--bitcoind-username".to_string(), "archipelago".to_string(),
"--bitcoind-username".to_string(), rpc_user.clone(),
"--bitcoind-password".to_string(), rpc_pass.clone(),
"lnd".to_string(),
"--lnd-rpc-host".to_string(), format!("{}:10009", self.config.host_ip),
@@ -304,24 +304,34 @@ impl RpcHandler {
}
}
// Pre-install: Create bitcoin.conf for Bitcoin nodes with RPC + txindex
// Pre-install: Create bitcoin.conf with rpcauth (salted hash, no plaintext)
if matches!(package_id, "bitcoin" | "bitcoin-core" | "bitcoin-knots") {
let bitcoin_dir = "/var/lib/archipelago/bitcoin";
let conf_path = format!("{}/bitcoin.conf", bitcoin_dir);
// Generate rpcauth hash: HMAC-SHA256(salt, password)
use hmac::{Hmac, Mac};
use sha2::Sha256;
let salt_bytes: [u8; 16] = rand::random();
let salt_hex = hex::encode(salt_bytes);
let mut mac = Hmac::<Sha256>::new_from_slice(salt_hex.as_bytes())
.expect("HMAC accepts any key length");
mac.update(rpc_pass.as_bytes());
let hash_hex = hex::encode(mac.finalize().into_bytes());
let rpcauth_line = format!("rpcauth={}:{}${}", rpc_user, salt_hex, hash_hex);
let bitcoin_conf = format!("\
# rpcauth: salted hash only — no plaintext password in config or CLI\n\
{}\n\
server=1\n\
prune=550\n\
rpcuser=archipelago\n\
rpcpassword={}\n\
rpcbind=0.0.0.0\n\
rpcallowip=127.0.0.1/32\n\
rpcallowip=10.88.0.0/16\n\
rpcallowip=0.0.0.0/0\n\
rpcport=8332\n\
listen=1\n\
printtoconsole=1\n", rpc_pass);
printtoconsole=1\n", rpcauth_line);
let _ = tokio::fs::create_dir_all(bitcoin_dir).await;
let _ = tokio::fs::write(&conf_path, bitcoin_conf).await;
info!("Created bitcoin.conf at {} with RPC + txindex enabled", conf_path);
info!("Created bitcoin.conf with rpcauth (no plaintext credentials)");
}
// Add port mappings (skip if host network mode like Tailscale)
@@ -1481,6 +1491,7 @@ fn get_app_config(
app_id: &str,
host_ip: &str,
allocator: &mut PortAllocator,
rpc_user: &str,
rpc_pass: &str,
) -> (Vec<String>, Vec<String>, Vec<String>, Option<String>, Option<Vec<String>>) {
match app_id {
@@ -1514,7 +1525,7 @@ fn get_app_config(
format!("BTCPAY_HOST={}:23000", host_ip),
"BTCPAY_CHAINS=btc".to_string(),
format!("BTCPAY_BTCRPCURL=http://{}:8332", host_ip),
"BTCPAY_BTCRPCUSER=archipelago".to_string(),
format!("BTCPAY_BTCRPCUSER={}", rpc_user),
format!("BTCPAY_BTCRPCPASSWORD={}", rpc_pass),
"BTCPAY_POSTGRES=User ID=btcpay;Password=btcpaypass;Host=archy-btcpay-db;Port=5432;Database=btcpay;Include Error Detail=true".to_string(),
],
@@ -1538,7 +1549,7 @@ fn get_app_config(
"ELECTRUM_TLS_ENABLED=false".to_string(),
format!("CORE_RPC_HOST={}", host_ip),
"CORE_RPC_PORT=8332".to_string(),
"CORE_RPC_USERNAME=archipelago".to_string(),
format!("CORE_RPC_USERNAME={}", rpc_user),
format!("CORE_RPC_PASSWORD={}", rpc_pass),
"DATABASE_ENABLED=true".to_string(),
"DATABASE_HOST=archy-mempool-db".to_string(),
@@ -1556,7 +1567,7 @@ fn get_app_config(
vec!["50001:50001".to_string()],
vec!["/var/lib/archipelago/electrumx:/data".to_string()],
vec![
format!("DAEMON_URL=http://archipelago:{}@{}:8332/", rpc_pass, bitcoin_host),
format!("DAEMON_URL=http://{}:{}@{}:8332/", rpc_user, rpc_pass, bitcoin_host),
"COIN=Bitcoin".to_string(),
"DB_DIRECTORY=/data".to_string(),
"SERVICES=tcp://:50001,rpc://0.0.0.0:8000".to_string(),
@@ -1720,7 +1731,7 @@ fn get_app_config(
vec!["/var/lib/archipelago/fedimint:/data".to_string()],
vec![
"FM_DATA_DIR=/data".to_string(),
"FM_BITCOIND_USERNAME=archipelago".to_string(),
format!("FM_BITCOIND_USERNAME={}", rpc_user),
format!("FM_BITCOIND_PASSWORD={}", rpc_pass),
"FM_BITCOIN_NETWORK=bitcoin".to_string(),
"FM_BIND_P2P=0.0.0.0:8173".to_string(),
@@ -1746,7 +1757,7 @@ fn get_app_config(
"$2y$10$t9YjjxkiktrlYvjajB/zgOMDnSNVg4HqrbDqh47u7Jf42whNdxNqC".to_string(),
"--network".to_string(), "bitcoin".to_string(),
"--bitcoind-url".to_string(), format!("http://{}:8332", host_ip),
"--bitcoind-username".to_string(), "archipelago".to_string(),
"--bitcoind-username".to_string(), rpc_user.to_string(),
"--bitcoind-password".to_string(), rpc_pass.to_string(),
"ldk".to_string(),
"--ldk-lightning-port".to_string(), "9737".to_string(),