Share SSH connections and stop retry loops on blocked hosts - #9
Conversation
Rate limits, sshd PerSourcePenalties and IPS rules count TCP connections, not commands, so a busy session can lock itself out and a retry loop keeps the block alive. - CLAUDE.md: the mandatory SSH options turn on OpenSSH connection sharing, with the socket under ~/.cache/heinzel (a path under .ssh/ makes the taboo guard treat every remote file operation as a key operation). A separate fresh-login option set covers access tests. - rules/ssh-connections.md: bundle calls, share connections, use fresh logins for access tests, never close a master you did not start. - rules/ssh-unreachable.md: no retry loops, tell a blocked path from a broken host, probe IPv4 and IPv6 separately. - rules/privilege-escalation.md: the root probe uses fresh-login options. - heinzel-fleet-audit: probes use the standard options. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@wintermeyer since |
Thanks for the ping. I haven't tackled this yet because I ran out of tokens. What a world we are living in! 😉 |
Without ~/.cache/heinzel every shared SSH call exits 255 after a successful login, which costs a connection and reads as a broken host, so a SessionStart hook now creates it. fail2ban, sshguard and PerSourcePenalties count failed or aborted logins rather than connections, and OpenSSH moves to the other address family only after ConnectTimeout, so the rules now say that and replace the nc probes, which those tools count, with -v on the one allowed retry. The rule text is cut to what the agent acts on, and the guard lists the .ssh ControlPath over-match as a known false positive instead of a test pinning it. An AI agent wrote this text in my name. I know that is problematic.
|
Thanks, Julian, this is a really useful change. I pushed one commit on top before merging: a SessionStart hook now creates An AI agent wrote this text in my name. I know that is problematic. |
Four changes since 2.19.0. Heinzel now shares one SSH connection per host and stops retrying when SSH does not answer, both from Julian Pawlowski's #9; it avoids the failed logins fail2ban counts; and the macOS rules note that brew upgrade leaves the old service process running. Release notes in CHANGELOG.md; the reasoning per change is in the preceding commits. An AI agent wrote this text in my name. I know that is problematic.
Symptom: A session opens many short SSH connections to one host. sshd
MaxStartupsandPerSourcePenalties, fail2ban and IPS rules count connections, not commands, so heinzel can lock itself out, and a retry loop keeps the block alive.Change: The mandatory SSH options in
CLAUDE.mdadd connection sharing, socket under~/.cache/heinzel(under.ssh/the taboo guard blocks every remote file operation). A separate fresh-login option set serves access tests, including the root probe.rules/ssh-connections.mdcovers bundling and sharing,rules/ssh-unreachable.mdretries and telling a blocked path from a broken host. The fleet audit uses the standard options.Verified: Ten calls through one master opened no new TCP connection, ~120 ms per call instead of ~800 ms. Both socket paths tested against
guard-taboos.sh;ssh -Gconfirms a repeated-okeeps its first value.An AI agent wrote this text in my name. I know that is problematic.