refactor(deploy): rename system user lamassu → bitspire
System-level half of the lamassu → bitspire rebrand the rest of dev already did at the path / service / package layers. Touches user/group declarations, every systemd `User=` block, the udev rules filename, all chown calls in flake.nix + live.nix, the displayManager autoLogin user, the trusted-users nix entry, provision-atm.sh's ATM_USER, plus README + CLAUDE.md doc references. In-place migration for the Sintra dev unit (which auto-pulls dev at 04:00) lives in `system.activationScripts.bitspire-user-migration` and: - copies `/home/lamassu/.ssh/authorized_keys` → `/home/bitspire/` once, so SSH access survives the rename - recursively chowns `/var/lib/bitspire` to the new bitspire UID on every boot — cheap no-op once done, but covers the case where the data dir was written by the now-removed lamassu UID - leaves `/home/lamassu/` in place as evidence; operator can `rm -rf` after confirming bitspire login works Recovery path if the migration breaks SSH access: root key is still in configuration.nix:142-144 (padreug@gizmo), so ssh root@<host> works. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1655b1db04
commit
264cc47e0c
9 changed files with 61 additions and 32 deletions
|
|
@ -189,7 +189,7 @@ UP Board enumerates its eMMC controller via ACPI, not PCI. `upboard.nix` force-l
|
|||
|
||||
## Security priorities
|
||||
|
||||
1. **Private keys** — Never log nsec. The ATM's `VITE_ATM_PRIVATE_KEY` lives in `/var/lib/bitspire/.env` with mode 0600, owned by `lamassu:lamassu`.
|
||||
1. **Private keys** — Never log nsec. The ATM's `VITE_ATM_PRIVATE_KEY` lives in `/var/lib/bitspire/.env` with mode 0600, owned by `bitspire:bitspire`.
|
||||
2. **Payments** — Validate the bolt11 amount on cash-out before exposing the QR. Decode `payment_hash` from the bolt11 (cheap, avoids a roundtrip) and use it as the `subscribe_payments` filter.
|
||||
3. **Replay** — LNURL-withdraw links use `uses:1` and are deleted on session abort.
|
||||
4. **Encryption** — All RPC content is NIP-44 v2. NIP-04 is forbidden.
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ NixOS module + tooling for deploying bitSpire to ATM hardware (Sintra, tejo, dou
|
|||
```
|
||||
deploy/nixos/
|
||||
├── bitspire-atm.nix # NixOS module: services.bitspire option tree + systemd unit + udev rules
|
||||
├── configuration.nix # Base system (NixOS 24.05, locale, kernel, packages, lamassu user)
|
||||
├── configuration.nix # Base system (NixOS 24.05, locale, kernel, packages, bitspire user)
|
||||
├── live.nix # Live USB variant (squashfs + tmpfs root) — used by mkLiveConfig
|
||||
├── hardware/
|
||||
│ ├── douro.nix # Dell OptiPlex 9030 AIO (stock Douro motherboard; SATA SSD, eGalax touch)
|
||||
│ ├── batm3.nix # GeneralBytes BATM3 chassis with a Dell OptiPlex 9030 AIO grafted in (custom mod; WireGuard wired in)
|
||||
│ └── upboard.nix # Aaeon UP Board (Sintra + tejo; eMMC root via sdhci-acpi + mmc_block)
|
||||
├── udev/
|
||||
│ └── 99-lamassu-hardware.rules # additional udev rules (loaded via configuration.nix)
|
||||
│ └── 99-bitspire-hardware.rules # additional udev rules (loaded via configuration.nix)
|
||||
├── provision-atm.sh # Push LNbits credentials to a deployed ATM via SSH
|
||||
├── atm-transactions.sh # Operator query tool — reads /var/lib/bitspire/state.db
|
||||
├── flash-douro-usb.sh # Helper for flashing a douro live USB
|
||||
|
|
@ -128,7 +128,7 @@ ATM_PRIVATE_KEY=$(openssl rand -hex 32) \
|
|||
bash deploy/nixos/provision-atm.sh <sintra-lan-ip> 22
|
||||
```
|
||||
|
||||
The script SSHes to `lamassu@<sintra-lan-ip>:22`, writes `/var/lib/bitspire/.env`, and restarts `bitspire.service`. After a few seconds the kiosk should connect to LNbits over nostr-transport and show the live UI.
|
||||
The script SSHes to `bitspire@<sintra-lan-ip>:22`, writes `/var/lib/bitspire/.env`, and restarts `bitspire.service`. After a few seconds the kiosk should connect to LNbits over nostr-transport and show the live UI.
|
||||
|
||||
> **Save the generated `ATM_PRIVATE_KEY`.** LNbits identifies this ATM by its public key; if you regenerate the key on a re-provision, LNbits will auto-create a fresh wallet and the old wallet's balance becomes inaccessible.
|
||||
|
||||
|
|
@ -153,11 +153,11 @@ Production ATMs on `main` continue to read `main`'s flake (no `?ref=` pin → re
|
|||
|
||||
| Path | Owner | Purpose |
|
||||
|------|-------|---------|
|
||||
| `/var/lib/bitspire/` | lamassu:lamassu, 0750 | Service data directory |
|
||||
| `/var/lib/bitspire/.env` | lamassu:lamassu, 0600 | Runtime config — `VITE_RELAY_URL`, `VITE_LNBITS_SERVER_PUBKEY`, `VITE_LNBITS_HTTP_URL`, `VITE_ATM_PRIVATE_KEY`, … |
|
||||
| `/var/lib/bitspire/state.db` | lamassu:lamassu | SQLite — cassette inventory, cashbox state, transaction history |
|
||||
| `/var/lib/bitspire/logs/` | lamassu:lamassu, 0750 | Service logs (if app writes them) |
|
||||
| `/opt/bitspire/` | lamassu:lamassu | Optional override drop for app assets (mostly unused — app comes from `/nix/store`) |
|
||||
| `/var/lib/bitspire/` | bitspire:bitspire, 0750 | Service data directory |
|
||||
| `/var/lib/bitspire/.env` | bitspire:bitspire, 0600 | Runtime config — `VITE_RELAY_URL`, `VITE_LNBITS_SERVER_PUBKEY`, `VITE_LNBITS_HTTP_URL`, `VITE_ATM_PRIVATE_KEY`, … |
|
||||
| `/var/lib/bitspire/state.db` | bitspire:bitspire | SQLite — cassette inventory, cashbox state, transaction history |
|
||||
| `/var/lib/bitspire/logs/` | bitspire:bitspire, 0750 | Service logs (if app writes them) |
|
||||
| `/opt/bitspire/` | bitspire:bitspire | Optional override drop for app assets (mostly unused — app comes from `/nix/store`) |
|
||||
| `/etc/bitspire/config.env` | root:root | Static config emitted by the NixOS module (RELAY_URL, LNBITS_HTTP_URL — informational; the renderer reads `/var/lib/bitspire/.env` instead) |
|
||||
|
||||
## Common operations
|
||||
|
|
@ -180,7 +180,7 @@ From the dev box:
|
|||
|
||||
```bash
|
||||
nixos-rebuild switch --flake .#sintra-installed \
|
||||
--target-host lamassu@<sintra-lan-ip> --use-remote-sudo
|
||||
--target-host bitspire@<sintra-lan-ip> --use-remote-sudo
|
||||
```
|
||||
|
||||
Locally builds the new closure (binary-cache where possible), copies it to the ATM over SSH, activates the new generation. A kernel-or-initrd change still requires a reboot to take effect — `sudo systemctl reboot` over SSH afterwards.
|
||||
|
|
@ -259,7 +259,7 @@ Most of these are set automatically by the `mkInstalledConfig` helper in the roo
|
|||
|
||||
## Security notes
|
||||
|
||||
- **`lamassu` user has `wheel`/passwordless-sudo** to allow remote `nixos-rebuild switch` via `--use-remote-sudo`. This is acceptable for a kiosk on a network you control. Remove `security.sudo.wheelNeedsPassword = false` if you want to require a password.
|
||||
- **SSH password auth is enabled by default** to allow initial provisioning. Once you've baked your dev box's pubkey into `/home/lamassu/.ssh/authorized_keys`, you can disable password auth: `services.openssh.settings.PasswordAuthentication = false`.
|
||||
- **`/var/lib/bitspire/.env` contains the ATM's nostr private key.** It's mode 0600, owned by `lamassu:lamassu`. Don't `scp` it off the device; if you need to rotate the key, generate fresh and re-provision.
|
||||
- **`bitspire` user has `wheel`/passwordless-sudo** to allow remote `nixos-rebuild switch` via `--use-remote-sudo`. This is acceptable for a kiosk on a network you control. Remove `security.sudo.wheelNeedsPassword = false` if you want to require a password.
|
||||
- **SSH password auth is enabled by default** to allow initial provisioning. Once you've baked your dev box's pubkey into `/home/bitspire/.ssh/authorized_keys`, you can disable password auth: `services.openssh.settings.PasswordAuthentication = false`.
|
||||
- **`/var/lib/bitspire/.env` contains the ATM's nostr private key.** It's mode 0600, owned by `bitspire:bitspire`. Don't `scp` it off the device; if you need to rotate the key, generate fresh and re-provision.
|
||||
- **No firewall is configured by default.** The ATM is meant to be on an operator-controlled network. If you expose it to a wider network, add a `networking.firewall` rule set restricting inbound to SSH from the operator's IPs only.
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ in
|
|||
config = mkIf cfg.enable {
|
||||
# Create data directory
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${cfg.dataDir} 0750 lamassu lamassu -"
|
||||
"d ${cfg.dataDir}/logs 0750 lamassu lamassu -"
|
||||
"d ${cfg.dataDir} 0750 bitspire bitspire -"
|
||||
"d ${cfg.dataDir}/logs 0750 bitspire bitspire -"
|
||||
];
|
||||
|
||||
# Environment file for ATM configuration
|
||||
|
|
@ -156,8 +156,8 @@ in
|
|||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "lamassu";
|
||||
Group = "lamassu";
|
||||
User = "bitspire";
|
||||
Group = "bitspire";
|
||||
WorkingDirectory = cfg.appDir;
|
||||
|
||||
# Environment
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Lamassu ATM NixOS Configuration
|
||||
# bitSpire ATM NixOS Configuration
|
||||
# Base system configuration for ATM kiosk
|
||||
|
||||
{ config, lib, pkgs, pkgs-unstable, ... }:
|
||||
|
|
@ -43,11 +43,12 @@
|
|||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
# Users
|
||||
users.groups.lamassu = { };
|
||||
users.users.lamassu = {
|
||||
users.groups.bitspire = { };
|
||||
users.users.bitspire = {
|
||||
isNormalUser = true;
|
||||
group = "lamassu";
|
||||
description = "Lamassu ATM";
|
||||
group = "bitspire";
|
||||
description = "bitSpire ATM";
|
||||
home = "/home/bitspire";
|
||||
extraGroups = [
|
||||
"wheel" # For admin access
|
||||
"video" # GPU access
|
||||
|
|
@ -57,7 +58,7 @@
|
|||
"networkmanager" # Network config
|
||||
];
|
||||
# No password - kiosk mode
|
||||
initialPassword = "lamassu";
|
||||
initialPassword = "bitspire"; # pragma: allowlist secret
|
||||
};
|
||||
|
||||
# Kiosk display configuration
|
||||
|
|
@ -85,7 +86,7 @@
|
|||
# Display manager - auto-login (top-level since NixOS 24.11+)
|
||||
services.displayManager.autoLogin = {
|
||||
enable = true;
|
||||
user = "lamassu";
|
||||
user = "bitspire";
|
||||
};
|
||||
|
||||
# Audio (for transaction sounds)
|
||||
|
|
@ -146,6 +147,7 @@
|
|||
# Auto-updates (optional - disabled by default for stability)
|
||||
# system.autoUpgrade.enable = false;
|
||||
|
||||
# pragma: allowlist secret
|
||||
# Ensure WireGuard private key directory exists with correct permissions
|
||||
system.activationScripts.wireguard-key = ''
|
||||
mkdir -p /var/lib/wireguard
|
||||
|
|
@ -155,6 +157,33 @@
|
|||
fi
|
||||
'';
|
||||
|
||||
# In-place rename migration: lamassu user → bitspire user.
|
||||
# Runs after `users` activation so the bitspire user exists with its UID.
|
||||
# Idempotent: re-running on an already-migrated system is a chown no-op.
|
||||
# Leaves /home/lamassu in place as evidence — operator can `rm -rf` after
|
||||
# confirming bitspire works.
|
||||
system.activationScripts.bitspire-user-migration = {
|
||||
deps = [ "users" ];
|
||||
text = ''
|
||||
# SSH key migration: copy authorized_keys to /home/bitspire if missing,
|
||||
# so the dev box can still SSH in as bitspire after the rename.
|
||||
if [ -f /home/lamassu/.ssh/authorized_keys ] \
|
||||
&& [ ! -f /home/bitspire/.ssh/authorized_keys ]; then
|
||||
mkdir -p /home/bitspire/.ssh
|
||||
cp /home/lamassu/.ssh/authorized_keys /home/bitspire/.ssh/authorized_keys
|
||||
chown -R bitspire:bitspire /home/bitspire/.ssh
|
||||
chmod 700 /home/bitspire/.ssh
|
||||
chmod 600 /home/bitspire/.ssh/authorized_keys
|
||||
fi
|
||||
|
||||
# Data dir ownership: state.db / .env / branding/ may still be owned by
|
||||
# the now-removed lamassu UID. Reset every boot — cheap no-op once done.
|
||||
if [ -d /var/lib/bitspire ]; then
|
||||
chown -R bitspire:bitspire /var/lib/bitspire
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# Journal configuration
|
||||
services.journald = {
|
||||
extraConfig = ''
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@
|
|||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = "lamassu";
|
||||
User = "bitspire";
|
||||
Environment = "DISPLAY=:0";
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 3";
|
||||
ExecStart = "${pkgs.xorg.xinput}/bin/xinput set-prop 'eGalax Inc. USB TouchController' 'Coordinate Transformation Matrix' 0 -1.268 1.147 -1.224 0 1.118 0 0 1";
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ in
|
|||
if [ ! -f /var/lib/bitspire/.env ]; then
|
||||
cp ${envTemplate} /var/lib/bitspire/.env
|
||||
chmod 600 /var/lib/bitspire/.env
|
||||
chown lamassu:lamassu /var/lib/bitspire/.env
|
||||
chown bitspire:bitspire /var/lib/bitspire/.env
|
||||
fi
|
||||
'';
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ in
|
|||
before = [ "bitspire.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "lamassu";
|
||||
User = "bitspire";
|
||||
Environment = "DISPLAY=:0";
|
||||
ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.xorg.xrandr}/bin/xrandr --output eDP-1 --off; sleep 1; ${pkgs.xorg.xrandr}/bin/xrandr --output eDP-1 --auto'";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ set -euo pipefail
|
|||
|
||||
ATM_HOST="${1:-localhost}"
|
||||
ATM_SSH_PORT="${2:-2222}"
|
||||
ATM_USER="lamassu"
|
||||
ATM_USER="bitspire"
|
||||
|
||||
# Machine model + fiat. Model is operator-set; fiat defaults per-model to
|
||||
# match the flake's fiatCodeForModel table (sintra=EUR, douro/tejo=GTQ,
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
# Passwordless sudo for remote nixos-rebuild switch
|
||||
security.sudo.wheelNeedsPassword = false;
|
||||
|
||||
# Allow lamassu user to use nix commands + pull from aiolabs binary cache.
|
||||
# Allow bitspire user to use nix commands + pull from aiolabs binary cache.
|
||||
# max-jobs = 1: prefer substitution from the cache, but allow ONE
|
||||
# local build slot for tiny activation-time stitch derivations
|
||||
# (boot.json, system-units, X-Restart-Triggers, etc.) that are
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
# the upgrade fails loudly instead of silently wedging the box
|
||||
# for an hour. Time-bounds the max-jobs=1 escape hatch.
|
||||
timeout = 60;
|
||||
trusted-users = [ "root" "lamassu" ];
|
||||
trusted-users = [ "root" "bitspire" ];
|
||||
substituters = [ "https://cache.nixos.org" "https://aiolabs.cachix.org" ];
|
||||
trusted-public-keys = [
|
||||
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
||||
|
|
@ -205,7 +205,7 @@
|
|||
DISPLAY=:0
|
||||
''} /var/lib/bitspire/.env
|
||||
chmod 600 /var/lib/bitspire/.env
|
||||
chown lamassu:lamassu /var/lib/bitspire/.env
|
||||
chown bitspire:bitspire /var/lib/bitspire/.env
|
||||
fi
|
||||
'';
|
||||
|
||||
|
|
@ -234,7 +234,7 @@
|
|||
before = [ "bitspire.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "lamassu";
|
||||
User = "bitspire";
|
||||
Environment = "DISPLAY=:0";
|
||||
ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.xorg.xrandr}/bin/xrandr --output eDP-1 --off; sleep 1; ${pkgs.xorg.xrandr}/bin/xrandr --output eDP-1 --auto'";
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue