This is done with two configuration changes: one, to use ClientAlive settings in the SSH server to take action on connections without a responsive client, and secondly, to use `logind` configuration to specify that processes that belong to that session are to be terminated rather than re-parented as orphans. A downside is that running `ssh` with even a single `-v` (verbose) flag will spam annoying messages to the screen during the session. I have often used the lowest level of verbosity to supervise at what stage an establishing connection is hanging or slow at, now I cannot leave that flag on anymore. Verification is a bit of a pain. First, it's best to have two paths to the test computer, e.g. allocate two VMs, where one acts as a SSH jump host to a test VM, as well as connecting to the test VM directly from your laptop: that way you can cut network access to the jump host and observe the results. Secondly, it's important to know that signal propagation in SSH is different if a `pty` is allocated (e.g. for interactive mode): with a `pty`, SIGHUP is propagated, and most processes will decide to exit at that point. Without a `pty`, there is no signal. So, when testing this, it is better to do something like: ssh host sleep 3600 To start a session that is non-interactive, and waits. By omitting the changes in this patch, you should be able to see `sleep` hanging around after the SSH server has closed the forked SSH process because of a non-responsive client. You can use `pstree -s` to check its parentage. From the session with the jump host, start such a hanging command. Then, on your other connection, drop TCP packets to the jump host's address, by running `nft -f` on nftable rules like this, substituting the `saddr` for the jump host address: add table inet filter flush table inet filter table inet filter { chain input { type filter hook input priority filter; policy accept; ip6 saddr 2a01:4f8:2b01:d85:214a::2 tcp dport 22 drop } } By using commands like `w` and `loginctl list-sessions`, you should see the process disappear momentarily. If you need to re-set the test and allow the jump host to send traffic again, use `nft -f` again with: delete table inet filter;
69 lines
2.4 KiB
Ruby
69 lines
2.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../lib/util"
|
|
|
|
class Prog::BootstrapRhizome < Prog::Base
|
|
subject_is :sshable
|
|
|
|
def user
|
|
@user ||= frame.fetch("user", "root")
|
|
end
|
|
|
|
label def start
|
|
sshable.update(raw_private_key_1: SshKey.generate.keypair) if sshable.raw_private_key_1.nil?
|
|
hop_setup
|
|
end
|
|
|
|
# Taken from https://infosec.mozilla.org/guidelines/openssh
|
|
SSHD_CONFIG = <<SSHD_CONFIG
|
|
# Supported HostKey algorithms by order of preference.
|
|
HostKey /etc/ssh/ssh_host_ed25519_key
|
|
HostKey /etc/ssh/ssh_host_rsa_key
|
|
HostKey /etc/ssh/ssh_host_ecdsa_key
|
|
|
|
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
|
|
|
|
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
|
|
|
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
|
|
|
|
# Password based logins are disabled - only public key based logins are allowed.
|
|
AuthenticationMethods publickey
|
|
|
|
# LogLevel VERBOSE logs user's key fingerprint on login. Needed to have a clear audit track of which key was using to log in.
|
|
LogLevel VERBOSE
|
|
|
|
# Terminate sessions with clients that cannot return packets rapidly.
|
|
ClientAliveInterval 2
|
|
ClientAliveCountMax 4
|
|
SSHD_CONFIG
|
|
|
|
LOGIND_CONFIG = <<LOGIND
|
|
[Login]
|
|
KillOnlyUsers=rhizome
|
|
KillUserProcesses=yes
|
|
LOGIND
|
|
|
|
label def setup
|
|
pop "rhizome user bootstrapped and source installed" if retval&.dig("msg") == "installed rhizome"
|
|
|
|
key_data = sshable.keys.map(&:private_key)
|
|
Util.rootish_ssh(sshable.host, user, key_data, <<SH)
|
|
set -ueo pipefail
|
|
sudo apt update && sudo apt-get -y install ruby-bundler
|
|
sudo userdel -rf rhizome || true
|
|
sudo adduser --disabled-password --gecos '' rhizome
|
|
echo 'rhizome ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/98-rhizome
|
|
sudo install -d -o rhizome -g rhizome -m 0700 /home/rhizome/.ssh
|
|
sudo install -o rhizome -g rhizome -m 0600 /dev/null /home/rhizome/.ssh/authorized_keys
|
|
sudo mkdir -p /etc/systemd/logind.conf.d
|
|
echo #{LOGIND_CONFIG.shellescape} | sudo tee /etc/systemd/logind.conf.d/rhizome.conf > /dev/null
|
|
echo #{SSHD_CONFIG.shellescape} | sudo tee /etc/ssh/sshd_config.d/10-clover.conf > /dev/null
|
|
echo #{sshable.keys.map(&:public_key).join("\n").shellescape} | sudo tee /home/rhizome/.ssh/authorized_keys > /dev/null
|
|
sync
|
|
SH
|
|
|
|
push Prog::InstallRhizome, {"target_folder" => frame["target_folder"]}
|
|
end
|
|
end
|