fix: clear agents that connected during unauthenticated setup window

When no auth is configured (fresh install), CheckAuth allows all requests.
This creates a race condition where existing agents from a previous setup
can report data before the wizard completes security configuration.

This fix clears all host agents and docker hosts when /api/security/quick-setup
is called, ensuring the wizard shows a clean state after security is configured.

Added:
- State.ClearAllHosts() - removes all host agents
- State.ClearAllDockerHosts() - removes all docker hosts
- Monitor.ClearUnauthenticatedAgents() - clears both and resets token bindings
- Call to ClearUnauthenticatedAgents() in handleQuickSecuritySetupFixed()
This commit is contained in:
rcourtman 2025-12-13 21:22:04 +00:00
parent 7ae0b5cafd
commit ac93fd42aa
3 changed files with 69 additions and 0 deletions

View file

@ -290,6 +290,18 @@ func handleQuickSecuritySetupFixed(r *Router) http.HandlerFunc {
}
log.Info().Msg("Runtime config updated with new security settings - active immediately")
// Clear any agents that connected during the brief unauthenticated setup window.
// This prevents stale/unauthorized agent data from appearing in the wizard.
if r.monitor != nil {
hostCleared, dockerCleared := r.monitor.ClearUnauthenticatedAgents()
if hostCleared > 0 || dockerCleared > 0 {
log.Info().
Int("hosts", hostCleared).
Int("dockerHosts", dockerCleared).
Msg("Cleared agents that connected before security was configured")
}
}
// Save system settings to system.json
systemSettings := config.DefaultSystemSettings()
systemSettings.ConnectionTimeout = 10 // Default seconds

View file

@ -1489,6 +1489,19 @@ func (s *State) RemoveDockerHost(hostID string) (DockerHost, bool) {
return DockerHost{}, false
}
// ClearAllDockerHosts removes all docker hosts from the state.
// This is used during initial security setup to clear any docker hosts that may have
// connected during the brief unauthenticated window before credentials were configured.
func (s *State) ClearAllDockerHosts() int {
s.mu.Lock()
defer s.mu.Unlock()
count := len(s.DockerHosts)
s.DockerHosts = nil
s.LastUpdate = time.Now()
return count
}
// SetDockerHostStatus updates the status of a docker host if present.
func (s *State) SetDockerHostStatus(hostID, status string) bool {
s.mu.Lock()
@ -1904,6 +1917,19 @@ func (s *State) RemoveHost(hostID string) (Host, bool) {
return Host{}, false
}
// ClearAllHosts removes all host agents from the state.
// This is used during initial security setup to clear any hosts that may have
// connected during the brief unauthenticated window before credentials were configured.
func (s *State) ClearAllHosts() int {
s.mu.Lock()
defer s.mu.Unlock()
count := len(s.Hosts)
s.Hosts = nil
s.LastUpdate = time.Now()
return count
}
// UpsertCephCluster inserts or updates a Ceph cluster in the state.
// Uses ID (typically the FSID) for matching.
func (s *State) UpsertCephCluster(cluster CephCluster) {

View file

@ -1395,6 +1395,37 @@ func (m *Monitor) RebuildTokenBindings() {
Msg("Rebuilt agent token bindings after API token reload")
}
// ClearUnauthenticatedAgents removes all host agents and docker hosts from the state.
// This should be called when security is first configured to clear any agents that
// connected during the brief unauthenticated window before credentials were set up.
// This prevents stale/unauthorized agent data from appearing in the UI.
func (m *Monitor) ClearUnauthenticatedAgents() (int, int) {
if m == nil || m.state == nil {
return 0, 0
}
// Clear all hosts
hostCount := m.state.ClearAllHosts()
// Clear all docker hosts
dockerCount := m.state.ClearAllDockerHosts()
// Clear any token bindings since the tokens used by the old agents are invalid
m.mu.Lock()
m.dockerTokenBindings = make(map[string]string)
m.hostTokenBindings = make(map[string]string)
m.mu.Unlock()
if hostCount > 0 || dockerCount > 0 {
log.Info().
Int("hostsCleared", hostCount).
Int("dockerHostsCleared", dockerCount).
Msg("Cleared unauthenticated agents after security setup")
}
return hostCount, dockerCount
}
// QueueDockerHostStop queues a stop command for the specified docker host.
func (m *Monitor) QueueDockerHostStop(hostID string) (models.DockerHostCommandStatus, error) {
return m.queueDockerStopCommand(hostID)