From dfe960deb400a1e35b586ea4333ab7930c3ea5e6 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 6 Nov 2025 09:57:53 +0000 Subject: [PATCH] Fix container SSH detection and improve troubleshooting for issue #617 Related to #617 This fixes a misconfiguration scenario where Docker containers could attempt direct SSH connections (producing [preauth] log spam) instead of using the sensor proxy. Changes: - Fix container detection to check PULSE_DOCKER=true in addition to system.InContainer() heuristics (both temperature.go and config_handlers.go) - Upgrade temperature collection log from Error to Warn with actionable guidance about mounting the proxy socket - Add Info log when dev mode override is active so operators understand the security posture - Add troubleshooting section to docs for SSH [preauth] logs from containers The container detection was inconsistent - monitor.go checked both flags but temperature.go and config_handlers.go only checked InContainer(). Now all locations consistently check PULSE_DOCKER || InContainer(). --- docs/TEMPERATURE_MONITORING.md | 22 ++++++++++++++++++++++ internal/api/config_handlers.go | 6 ++++-- internal/monitoring/temperature.go | 15 ++++++++++++--- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/docs/TEMPERATURE_MONITORING.md b/docs/TEMPERATURE_MONITORING.md index c1bfb84..9e97868 100644 --- a/docs/TEMPERATURE_MONITORING.md +++ b/docs/TEMPERATURE_MONITORING.md @@ -359,6 +359,28 @@ You should see JSON output with temperature data. ## Troubleshooting +### SSH Connection Attempts from Container ([preauth] Logs) + +**Symptom:** Proxmox host logs (`/var/log/auth.log`) show repeated SSH connection attempts from your Pulse container: +``` +Connection closed by authenticating user root port [preauth] +``` + +**This indicates a misconfiguration.** Containerized Pulse should communicate via the sensor proxy, not direct SSH. + +**Common causes:** +- Dev mode enabled (`PULSE_DEV_ALLOW_CONTAINER_SSH=true` environment variable) +- Sensor proxy not installed or socket not accessible +- Legacy SSH keys from pre-v4.24.0 installations + +**Fix:** +- **Docker:** Follow [Quick Start for Docker Deployments](#quick-start-for-docker-deployments) to install the proxy and add the bind mount +- **LXC:** Run the setup script on your Proxmox host (see [Setup (Automatic)](#setup-automatic)) +- **Dev mode:** Remove `PULSE_DEV_ALLOW_CONTAINER_SSH=true` from your environment/docker-compose +- **Verify:** Check Pulse logs for `Temperature proxy detected - using secure host-side bridge` + +Once the proxy is properly configured, these log entries will stop immediately. See [Container Security Considerations](#container-security-considerations) for why direct container SSH is blocked. + ### No Temperature Data Shown **Check SSH access**: diff --git a/internal/api/config_handlers.go b/internal/api/config_handlers.go index c1a6bd4..2c94434 100644 --- a/internal/api/config_handlers.go +++ b/internal/api/config_handlers.go @@ -5878,7 +5878,9 @@ func (h *ConfigHandlers) getOrGenerateSSHKeys() SSHKeyPair { // CRITICAL SECURITY CHECK: Never generate SSH keys in containers (unless dev mode) // Container compromise = SSH key compromise = root access to Proxmox devModeAllowSSH := os.Getenv("PULSE_DEV_ALLOW_CONTAINER_SSH") == "true" - if system.InContainer() && !devModeAllowSSH { + isContainer := os.Getenv("PULSE_DOCKER") == "true" || system.InContainer() + + if isContainer && !devModeAllowSSH { log.Error().Msg("SECURITY BLOCK: SSH key generation disabled in containerized deployments") log.Error().Msg("For temperature monitoring in containers, deploy pulse-sensor-proxy on the Proxmox host") log.Error().Msg("See: https://github.com/rcourtman/Pulse/blob/main/SECURITY.md#critical-security-notice-for-container-deployments") @@ -5886,7 +5888,7 @@ func (h *ConfigHandlers) getOrGenerateSSHKeys() SSHKeyPair { return SSHKeyPair{} } - if devModeAllowSSH && system.InContainer() { + if devModeAllowSSH && isContainer { log.Warn().Msg("⚠️ DEV MODE: SSH key generation ENABLED in container - FOR TESTING ONLY") log.Warn().Msg("⚠️ This grants root SSH access from container - NEVER use in production!") } diff --git a/internal/monitoring/temperature.go b/internal/monitoring/temperature.go index 8b79da9..241d178 100644 --- a/internal/monitoring/temperature.go +++ b/internal/monitoring/temperature.go @@ -114,10 +114,19 @@ func (tc *TemperatureCollector) CollectTemperature(ctx context.Context, nodeHost // SECURITY: Block SSH fallback when running in containers (unless dev mode) // Container compromise = SSH key compromise = root access to infrastructure devModeAllowSSH := os.Getenv("PULSE_DEV_ALLOW_CONTAINER_SSH") == "true" - if system.InContainer() && !devModeAllowSSH { - log.Error(). + isContainer := os.Getenv("PULSE_DOCKER") == "true" || system.InContainer() + + if isContainer && devModeAllowSSH { + // Log when dev override is active so operators understand the security posture + log.Info(). Str("node", nodeName). - Msg("SECURITY BLOCK: SSH temperature collection disabled in containers - deploy pulse-sensor-proxy") + Msg("Temperature collection using direct SSH (dev mode override active - not for production)") + } + + if isContainer && !devModeAllowSSH { + log.Warn(). + Str("node", nodeName). + Msg("Temperature collection disabled: containerized Pulse requires pulse-sensor-proxy. Mount /run/pulse-sensor-proxy or set PULSE_DEV_ALLOW_CONTAINER_SSH=true for development only") return &models.Temperature{Available: false}, nil }