mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
When pulse-sensor-proxy is installed, automatically remove old SSH keys that were stored in the container for security. Changes: **install-sensor-proxy.sh:** - Checks container for SSH private keys (id_rsa, id_ed25519, etc.) - Removes any found keys from container - Warns user that legacy keys were cleaned up - Explains proxy now handles SSH **Setup script (config_handlers.go):** - After successful proxy install, removes old SSH keys from all cluster nodes - Cleans up authorized_keys entries that match the old container-based key - Keeps only proxy-managed keys (pulse-sensor-proxy comment) This provides a clean migration path from the old direct-SSH method to the secure proxy architecture. Users upgrading from pre-v4.24 versions get automatic cleanup of insecure container-stored keys.
319 lines
9.4 KiB
Bash
Executable File
319 lines
9.4 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# install-sensor-proxy.sh - Installs pulse-sensor-proxy on Proxmox host for secure temperature monitoring
|
|
# This script is idempotent and can be safely re-run
|
|
|
|
set -euo pipefail
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
print_info() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
print_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
# Check if running on Proxmox host
|
|
if ! command -v pvecm >/dev/null 2>&1; then
|
|
print_error "This script must be run on a Proxmox VE host"
|
|
exit 1
|
|
fi
|
|
|
|
# Parse arguments
|
|
CTID=""
|
|
VERSION="latest"
|
|
LOCAL_BINARY=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--ctid)
|
|
CTID="$2"
|
|
shift 2
|
|
;;
|
|
--version)
|
|
VERSION="$2"
|
|
shift 2
|
|
;;
|
|
--local-binary)
|
|
LOCAL_BINARY="$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
print_error "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$CTID" ]]; then
|
|
print_error "Missing required argument: --ctid <container-id>"
|
|
echo "Usage: $0 --ctid <container-id> [--version <version>] [--local-binary <path>]"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify container exists
|
|
if ! pct status "$CTID" >/dev/null 2>&1; then
|
|
print_error "Container $CTID does not exist"
|
|
exit 1
|
|
fi
|
|
|
|
print_info "Installing pulse-sensor-proxy for container $CTID"
|
|
|
|
BINARY_PATH="/usr/local/bin/pulse-sensor-proxy"
|
|
SERVICE_PATH="/etc/systemd/system/pulse-sensor-proxy.service"
|
|
RUNTIME_DIR="/run/pulse-sensor-proxy"
|
|
SOCKET_PATH="/run/pulse-sensor-proxy/pulse-sensor-proxy.sock"
|
|
SSH_DIR="/var/lib/pulse-sensor-proxy/ssh"
|
|
|
|
# Create dedicated service account if it doesn't exist
|
|
if ! id -u pulse-sensor-proxy >/dev/null 2>&1; then
|
|
print_info "Creating pulse-sensor-proxy service account..."
|
|
useradd --system --user-group --no-create-home --shell /usr/sbin/nologin pulse-sensor-proxy
|
|
print_info "Service account created"
|
|
else
|
|
print_info "Service account pulse-sensor-proxy already exists"
|
|
fi
|
|
|
|
# Install binary - either from local file or download from GitHub
|
|
if [[ -n "$LOCAL_BINARY" ]]; then
|
|
# Use local binary for testing
|
|
print_info "Using local binary: $LOCAL_BINARY"
|
|
if [[ ! -f "$LOCAL_BINARY" ]]; then
|
|
print_error "Local binary not found: $LOCAL_BINARY"
|
|
exit 1
|
|
fi
|
|
cp "$LOCAL_BINARY" "$BINARY_PATH"
|
|
chmod +x "$BINARY_PATH"
|
|
print_info "Binary installed to $BINARY_PATH"
|
|
else
|
|
# Download from GitHub release
|
|
GITHUB_REPO="rcourtman/Pulse"
|
|
if [[ "$VERSION" == "latest" ]]; then
|
|
RELEASE_URL="https://api.github.com/repos/$GITHUB_REPO/releases/latest"
|
|
print_info "Fetching latest release info..."
|
|
RELEASE_DATA=$(curl -fsSL "$RELEASE_URL")
|
|
VERSION=$(echo "$RELEASE_DATA" | grep -o '"tag_name": "[^"]*"' | cut -d'"' -f4)
|
|
if [[ -z "$VERSION" ]]; then
|
|
print_error "Failed to determine latest version"
|
|
exit 1
|
|
fi
|
|
print_info "Latest version: $VERSION"
|
|
fi
|
|
|
|
# Detect architecture
|
|
ARCH=$(uname -m)
|
|
case $ARCH in
|
|
x86_64)
|
|
BINARY_NAME="pulse-sensor-proxy-linux-amd64"
|
|
;;
|
|
aarch64|arm64)
|
|
BINARY_NAME="pulse-sensor-proxy-linux-arm64"
|
|
;;
|
|
armv7l|armhf)
|
|
BINARY_NAME="pulse-sensor-proxy-linux-armv7"
|
|
;;
|
|
*)
|
|
print_error "Unsupported architecture: $ARCH"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
DOWNLOAD_URL="https://github.com/$GITHUB_REPO/releases/download/$VERSION/$BINARY_NAME"
|
|
|
|
# Download binary
|
|
print_info "Downloading $BINARY_NAME..."
|
|
if ! curl -fsSL "$DOWNLOAD_URL" -o "$BINARY_PATH.tmp"; then
|
|
print_error "Failed to download binary from $DOWNLOAD_URL"
|
|
exit 1
|
|
fi
|
|
|
|
# Make executable and move to final location
|
|
chmod +x "$BINARY_PATH.tmp"
|
|
mv "$BINARY_PATH.tmp" "$BINARY_PATH"
|
|
print_info "Binary installed to $BINARY_PATH"
|
|
fi
|
|
|
|
# Create directories with proper ownership (handles fresh installs and upgrades)
|
|
print_info "Setting up directories with proper ownership..."
|
|
install -d -o pulse-sensor-proxy -g pulse-sensor-proxy -m 0750 /var/lib/pulse-sensor-proxy
|
|
install -d -o pulse-sensor-proxy -g pulse-sensor-proxy -m 0700 "$SSH_DIR"
|
|
|
|
# Stop existing service if running (for upgrades)
|
|
if systemctl is-active --quiet pulse-sensor-proxy 2>/dev/null; then
|
|
print_info "Stopping existing service for upgrade..."
|
|
systemctl stop pulse-sensor-proxy
|
|
fi
|
|
|
|
# Install hardened systemd service
|
|
print_info "Installing hardened systemd service..."
|
|
cat > "$SERVICE_PATH" << 'EOF'
|
|
[Unit]
|
|
Description=Pulse Temperature Proxy
|
|
Documentation=https://github.com/rcourtman/Pulse
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=pulse-sensor-proxy
|
|
Group=pulse-sensor-proxy
|
|
WorkingDirectory=/var/lib/pulse-sensor-proxy
|
|
ExecStart=/usr/local/bin/pulse-sensor-proxy
|
|
Restart=on-failure
|
|
RestartSec=5s
|
|
|
|
# Runtime dirs/sockets
|
|
RuntimeDirectory=pulse-sensor-proxy
|
|
RuntimeDirectoryMode=0775
|
|
UMask=0007
|
|
|
|
# Core hardening
|
|
NoNewPrivileges=true
|
|
ProtectSystem=strict
|
|
ProtectHome=read-only
|
|
ReadWritePaths=/var/lib/pulse-sensor-proxy
|
|
ProtectKernelTunables=true
|
|
ProtectKernelModules=true
|
|
ProtectControlGroups=true
|
|
ProtectClock=true
|
|
PrivateTmp=true
|
|
PrivateDevices=true
|
|
ProtectProc=invisible
|
|
ProcSubset=pid
|
|
LockPersonality=true
|
|
RemoveIPC=true
|
|
RestrictSUIDSGID=true
|
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
|
RestrictNamespaces=true
|
|
SystemCallFilter=@system-service
|
|
SystemCallErrorNumber=EPERM
|
|
CapabilityBoundingSet=
|
|
AmbientCapabilities=
|
|
KeyringMode=private
|
|
LimitNOFILE=1024
|
|
|
|
# Logging
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
SyslogIdentifier=pulse-sensor-proxy
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
# Reload systemd and start service
|
|
print_info "Enabling and starting service..."
|
|
systemctl daemon-reload
|
|
systemctl enable pulse-sensor-proxy.service
|
|
systemctl restart pulse-sensor-proxy.service
|
|
|
|
# Wait for socket to appear
|
|
print_info "Waiting for socket..."
|
|
for i in {1..10}; do
|
|
if [[ -S "$SOCKET_PATH" ]]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if [[ ! -S "$SOCKET_PATH" ]]; then
|
|
print_error "Socket did not appear after 10 seconds"
|
|
print_info "Check service status: systemctl status pulse-sensor-proxy"
|
|
exit 1
|
|
fi
|
|
|
|
print_info "Socket ready at $SOCKET_PATH"
|
|
|
|
# Configure LXC bind mount - mount entire directory for socket stability
|
|
LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
|
|
BIND_ENTRY="lxc.mount.entry: /run/pulse-sensor-proxy run/pulse-sensor-proxy none bind,create=dir 0 0"
|
|
|
|
# Check if bind mount already exists
|
|
if grep -q "pulse-sensor-proxy" "$LXC_CONFIG"; then
|
|
print_info "Bind mount already configured in LXC config"
|
|
# Remove old socket-level bind if it exists
|
|
if grep -q "pulse-sensor-proxy.sock" "$LXC_CONFIG"; then
|
|
print_info "Upgrading from socket-level to directory-level bind mount..."
|
|
sed -i '/pulse-sensor-proxy\.sock/d' "$LXC_CONFIG"
|
|
echo "$BIND_ENTRY" >> "$LXC_CONFIG"
|
|
NEEDS_RESTART=true
|
|
fi
|
|
else
|
|
print_info "Adding bind mount to LXC config..."
|
|
echo "$BIND_ENTRY" >> "$LXC_CONFIG"
|
|
NEEDS_RESTART=true
|
|
fi
|
|
|
|
# Restart container to apply bind mount if needed
|
|
if [[ "${NEEDS_RESTART:-false}" == "true" ]]; then
|
|
print_info "Restarting container to apply bind mount..."
|
|
pct stop "$CTID" || true
|
|
sleep 2
|
|
pct start "$CTID"
|
|
sleep 5
|
|
fi
|
|
|
|
# Verify socket is accessible in container
|
|
print_info "Verifying socket accessibility..."
|
|
if pct exec "$CTID" -- test -S /run/pulse-sensor-proxy/pulse-sensor-proxy.sock; then
|
|
print_info "Socket is accessible in container"
|
|
else
|
|
print_warn "Socket is not yet accessible in container"
|
|
print_info "Container may need additional restart or configuration"
|
|
fi
|
|
|
|
# Test proxy status
|
|
print_info "Testing proxy status..."
|
|
if systemctl is-active --quiet pulse-sensor-proxy; then
|
|
print_info "${GREEN}✓${NC} pulse-sensor-proxy is running"
|
|
else
|
|
print_error "pulse-sensor-proxy is not running"
|
|
print_info "Check logs: journalctl -u pulse-sensor-proxy -n 50"
|
|
exit 1
|
|
fi
|
|
|
|
# Check for and remove legacy SSH keys from container
|
|
print_info "Checking for legacy SSH keys in container..."
|
|
LEGACY_KEYS_FOUND=false
|
|
for key_type in id_rsa id_dsa id_ecdsa id_ed25519; do
|
|
if pct exec "$CTID" -- test -f "/root/.ssh/$key_type" 2>/dev/null; then
|
|
LEGACY_KEYS_FOUND=true
|
|
print_warn "Found legacy SSH key: /root/.ssh/$key_type"
|
|
pct exec "$CTID" -- rm -f "/root/.ssh/$key_type" "/root/.ssh/${key_type}.pub"
|
|
print_info " Removed /root/.ssh/$key_type (proxy will handle SSH)"
|
|
fi
|
|
done
|
|
|
|
if [ "$LEGACY_KEYS_FOUND" = true ]; then
|
|
print_info ""
|
|
print_info "${YELLOW}Legacy SSH keys removed from container${NC}"
|
|
print_info "The proxy on the host now handles all SSH connections"
|
|
print_info "This improves security by keeping keys outside the container"
|
|
print_info ""
|
|
fi
|
|
|
|
print_info "${GREEN}Installation complete!${NC}"
|
|
print_info ""
|
|
print_info "Temperature monitoring will now use the secure host-side proxy"
|
|
print_info "SSH keys are stored on the Proxmox host, not in the container"
|
|
print_info ""
|
|
print_info "To configure temperature monitoring for cluster nodes:"
|
|
print_info " 1. Access Pulse UI in container $CTID"
|
|
print_info " 2. Go to Settings → Enable Temperature Monitoring"
|
|
print_info " 3. The proxy will automatically discover and configure cluster nodes"
|
|
print_info ""
|
|
print_info "To check proxy status:"
|
|
print_info " systemctl status pulse-sensor-proxy"
|
|
print_info " journalctl -u pulse-sensor-proxy -f"
|
|
|
|
exit 0
|