Pulse/scripts/install-temp-proxy.sh
rcourtman e7bc338891 feat: Implement secure temperature proxy for containerized deployments
Addresses #528

Introduces pulse-temp-proxy architecture to eliminate SSH key exposure in containers:

**Architecture:**
- pulse-temp-proxy runs on Proxmox host (outside LXC/Docker)
- SSH keys stored on host filesystem (/var/lib/pulse-temp-proxy/ssh/)
- Pulse communicates via unix socket (bind-mounted into container)
- Proxy handles cluster discovery, key rollout, and temperature fetching

**Components:**
- cmd/pulse-temp-proxy: Standalone Go binary with unix socket RPC server
- internal/tempproxy: Client library for Pulse backend
- scripts/install-temp-proxy.sh: Idempotent installer for existing deployments
- scripts/pulse-temp-proxy.service: Systemd service for proxy

**Integration:**
- Pulse automatically detects and uses proxy when socket exists
- Falls back to direct SSH for native installations
- Installer automatically configures proxy for new LXC deployments
- Existing LXC users can upgrade by running install-temp-proxy.sh

**Security improvements:**
- Container compromise no longer exposes SSH keys
- SSH keys never enter container filesystem
- Maintains forced command restrictions
- Transparent to users - no workflow changes

**Documentation:**
- Updated TEMPERATURE_MONITORING.md with new architecture
- Added verification steps and upgrade instructions
- Preserved legacy documentation for native installs
2025-10-12 21:35:35 +00:00

227 lines
5.9 KiB
Bash
Executable file

#!/bin/bash
# install-temp-proxy.sh - Installs pulse-temp-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"
while [[ $# -gt 0 ]]; do
case $1 in
--ctid)
CTID="$2"
shift 2
;;
--version)
VERSION="$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>]"
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-temp-proxy for container $CTID"
# Determine download URL
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-temp-proxy-linux-amd64"
;;
aarch64|arm64)
BINARY_NAME="pulse-temp-proxy-linux-arm64"
;;
armv7l|armhf)
BINARY_NAME="pulse-temp-proxy-linux-armv7"
;;
*)
print_error "Unsupported architecture: $ARCH"
exit 1
;;
esac
DOWNLOAD_URL="https://github.com/$GITHUB_REPO/releases/download/$VERSION/$BINARY_NAME"
BINARY_PATH="/usr/local/bin/pulse-temp-proxy"
SERVICE_PATH="/etc/systemd/system/pulse-temp-proxy.service"
SOCKET_PATH="/var/run/pulse-temp-proxy.sock"
SSH_DIR="/var/lib/pulse-temp-proxy/ssh"
# 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"
# Create SSH key directory
mkdir -p "$SSH_DIR"
chmod 700 "$SSH_DIR"
# Install systemd service
print_info "Installing systemd service..."
cat > "$SERVICE_PATH" << 'EOF'
[Unit]
Description=Pulse Temperature Proxy
Documentation=https://github.com/rcourtman/Pulse
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/pulse-temp-proxy
Restart=on-failure
RestartSec=5s
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/pulse-temp-proxy /var/run
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=pulse-temp-proxy
[Install]
WantedBy=multi-user.target
EOF
# Reload systemd and start service
print_info "Enabling and starting service..."
systemctl daemon-reload
systemctl enable pulse-temp-proxy.service
systemctl restart pulse-temp-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-temp-proxy"
exit 1
fi
print_info "Socket ready at $SOCKET_PATH"
# Configure LXC bind mount
LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
BIND_ENTRY="lxc.mount.entry: /var/run/pulse-temp-proxy.sock var/run/pulse-temp-proxy.sock none bind,create=file 0 0"
# Check if bind mount already exists
if grep -q "pulse-temp-proxy.sock" "$LXC_CONFIG"; then
print_info "Bind mount already configured in LXC config"
else
print_info "Adding bind mount to LXC config..."
echo "$BIND_ENTRY" >> "$LXC_CONFIG"
# Restart container to apply bind mount
print_info "Restarting container to apply bind mount..."
pct stop "$CTID" || true
sleep 2
pct start "$CTID"
sleep 3
fi
# Verify socket is accessible in container
print_info "Verifying socket accessibility..."
if pct exec "$CTID" -- test -S /var/run/pulse-temp-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-temp-proxy; then
print_info "${GREEN}${NC} pulse-temp-proxy is running"
else
print_error "pulse-temp-proxy is not running"
print_info "Check logs: journalctl -u pulse-temp-proxy -n 50"
exit 1
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-temp-proxy"
print_info " journalctl -u pulse-temp-proxy -f"
exit 0