From f1f9a97f6288f4a329922c947e9eeae7230f980e Mon Sep 17 00:00:00 2001 From: Roy van Baekel Date: Wed, 22 Jan 2025 18:58:40 +0100 Subject: [PATCH] Implement ssh --forward-agent | -x functionality --- bin/shell/osh.pl | 8 ++ .../configuration/bastion_conf.rst | 12 +++ doc/sphinx/presentation/features.rst | 1 + etc/bastion/bastion.conf.dist | 7 +- .../tests.d/346-testagentforward.sh | 79 +++++++++++++++++++ 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tests/functional/tests.d/346-testagentforward.sh diff --git a/bin/shell/osh.pl b/bin/shell/osh.pl index 73dd07f66..254c6de7d 100755 --- a/bin/shell/osh.pl +++ b/bin/shell/osh.pl @@ -373,6 +373,7 @@ sub main_exit { "interactive|i" => \my $interactive, "netconf" => \my $netconf, "wait" => \my $wait, + "forward-agent|x" => \my $sshAddKeysToAgent, "ssh-as=s" => \my $sshAs, "use-key=s" => \my $useKey, "kbd-interactive" => \my $userKbdInteractive, @@ -1411,6 +1412,8 @@ sub main_exit { # also set password if allowed in bastion config (to allow users to enter a remote password interactively) push @preferredAuths, 'password' if $config->{'passwordAllowed'}; + # If sshAddKeystoAgent is set, run 'ssh-agent' first and let it spawn 'ssh' + push @command, 'ssh-agent', '-t', '60' if ($config->{'sshAddKeysToAgentAllowed'} && $sshAddKeysToAgent); push @command, '/usr/bin/ssh', $ip, '-l', $user, '-p', $port; $fnret = get_details_from_access_array( @@ -1459,6 +1462,10 @@ sub main_exit { } } + # -x flag is set and allowed, as such set the -A flag (enable agent forwarding) and '-o AddKeysToAgent=yes' to automatically add the egress sshkey to the agent, so that it can be used + if ($config->{'sshAddKeysToAgentAllowed'} && $sshAddKeysToAgent) { + push @command, '-A', '-o', 'AddKeysToAgent=yes'; + } push @command, '-o', 'PreferredAuthentications=' . (join(',', @preferredAuths)); if ($config->{'sshClientHasOptionE'}) { @@ -2053,6 +2060,7 @@ sub long_help { --always-escape Bypass config and force the bugged behavior of old bastions for REMOTE_COMMAND escaping. Don't use. --never-escape Bypass config and force the new behavior of new bastions for REMOTE_COMMAND escaping. Don't use. --wait Ping the host before connecting to it (useful to ssh just after a reboot!) + --forward-agent, -x Enables ssh agent forwarding on the egress connection --long-help Print this [REMOTE_COMMAND] diff --git a/doc/sphinx/administration/configuration/bastion_conf.rst b/doc/sphinx/administration/configuration/bastion_conf.rst index 876afc811..1913e5603 100644 --- a/doc/sphinx/administration/configuration/bastion_conf.rst +++ b/doc/sphinx/administration/configuration/bastion_conf.rst @@ -140,6 +140,7 @@ These options are either discouraged (in which case this is explained in the des - `remoteCommandEscapeByDefault`_ - `sshClientDebugLevel`_ - `sshClientHasOptionE`_ +- `sshAddKeysToAgentAllowed`_ Option Reference ================ @@ -1064,3 +1065,14 @@ sshClientHasOptionE Set to ``true`` if your ssh client supports the ``-E`` option and you want to use it to log debug info on opened sessions. **Discouraged** because it has some annoying side effects (some ssh errors then go silent from the user perspective). +.. _sshAddKeysToAgentAllowed: + +sshAddKeysToAgentAllowed +************************ + +:Type: ``boolean`` + +:Default: ``false`` + +Set to ``true`` if you want to allow to spawn an ssh-agent and forward it over the egress session when specifically requested with the '--forward-agent' or '-x' flag, with the egress key added to the agent. Useful if you need the ssh-key for authentication on other systems (another jumpserver for example). + diff --git a/doc/sphinx/presentation/features.rst b/doc/sphinx/presentation/features.rst index 436c0d095..6c68e31aa 100644 --- a/doc/sphinx/presentation/features.rst +++ b/doc/sphinx/presentation/features.rst @@ -25,6 +25,7 @@ Features splitting the authentication and authorization phases while still enforcing local policies - Supports SSH password autologin on the egress side for legacy devices not supporting pubkey authentication, while still forcing proper pubkey authentication on the ingress side +- Supports ssh-agent forwarding with the egress ssh key added to the agent - Supports telnet password autologin on the egress side for ancient devices not supporting SSH, while still forcing proper SSH pubkey authentication on the ingress side - Supports HTTPS proxying with man-in-the-middle authentication and authorization handling, diff --git a/etc/bastion/bastion.conf.dist b/etc/bastion/bastion.conf.dist index a99f191ba..0ff53db70 100644 --- a/etc/bastion/bastion.conf.dist +++ b/etc/bastion/bastion.conf.dist @@ -492,5 +492,10 @@ # sshClientHasOptionE (boolean) # DESC: Set to ``true`` if your ssh client supports the ``-E`` option and you want to use it to log debug info on opened sessions. **Discouraged** because it has some annoying side effects (some ssh errors then go silent from the user perspective). # DEFAULT: false -"sshClientHasOptionE": false +"sshClientHasOptionE": false, +# +# sshAddKeysToAgentAllowed (boolean) +# DESC: Set to ``true`` if you want to allow to spawn an ssh-agent and forward it over the egress session when specifically requested with the '--forward-agent' or '-x' flag, with the egress key added to the agent. Useful if you need the ssh-key for authentication on other systems (another jumpserver for example). +# DEFAULT: false +"sshAddKeysToAgentAllowed": false } diff --git a/tests/functional/tests.d/346-testagentforward.sh b/tests/functional/tests.d/346-testagentforward.sh new file mode 100644 index 000000000..33e213e64 --- /dev/null +++ b/tests/functional/tests.d/346-testagentforward.sh @@ -0,0 +1,79 @@ +# vim: set filetype=sh ts=4 sw=4 sts=4 et: +# shellcheck shell=bash +# shellcheck disable=SC2086,SC2016,SC2046 +# below: convoluted way that forces shellcheck to source our caller +# shellcheck source=tests/functional/launch_tests_on_instance.sh +. "$(dirname "${BASH_SOURCE[0]}")"/dummy + +testsuite_agent_forwarding() +{ + #create account1 + success accountCreate $a0 --osh accountCreate --always-active --account $account1 --uid $uid1 --public-key "\"$(cat $account1key1file.pub)\"" + json .error_code OK .command accountCreate .value null + + # Add access to $remote_ip for $shellaccount + success mustwork $a0 -osh selfAddPersonalAccess -h $remote_ip -u $shellaccount -p 22 --kbd-interactive + nocontain "already" + json .command selfAddPersonalAccess .error_code OK .value.user $shellaccount .value.port 22 + + # Patch sshd to allow Agent Forwarding, else all other steps are useless to test +set -x + success sshd_config_backup $r0 "\"cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak\"" + success sshd_config_patch $r0 "\"sed -i 's/^AllowAgentForwarding no/AllowAgentForwarding yes/' /etc/ssh/sshd_config\"" + # during tests, under some OSes it takes some time for sshd to accept new connections again after the SIGHUP + [ "$COUNTONLY" != 1 ] && sleep 1 + success sshd_reload $r0 "\"pkill -SIGHUP -f '^(/usr/sbin/sshd\\\$|sshd.+listener)'\"" +set +x + + # Test if ssh-agent is spawned without requesting it; it shouldn't + run shellaccount_noagent $a0 $shellaccount@$remote_ip --kbd-interactive -- ssh-add -L + retvalshouldbe 2 + contain REGEX "$shellaccount@[a-zA-Z0-9._-]+:22" + contain "allowed ... log on" + nocontain "Permission denied" + contain "Could not open a connection to your authentication agent." + + # test if ssh-agent is spawned whilst requesting it but with the addkeystoagentallowed-config directive set to false + run shellaccount_with_fwd_cfg_disallowed_noagent $a0 $shellaccount@$remote_ip --kbd-interactive -- ssh-add -L + retvalshouldbe 2 + contain REGEX "$shellaccount@[a-zA-Z0-9._-]+:22" + contain "allowed ... log on" + nocontain "Permission denied" + contain "Could not open a connection to your authentication agent." + + # test if ssh-agent is spawned whilst requesting it, with the addkeystoagentallowed-config directive set to True + # Change config + configchg 's=^\\\\x22sshAddKeysToAgentAllowed\\\\x22.+=\\\\x22sshAddKeysToAgentAllowed\\\\x22:\\\\x20true=' + + # Run test with --forward-agent; agent should spawn + run shellaccount_with_fwd_cfg_longarg $a0 --forward-agent $shellaccount@$remote_ip -- ssh-add -L + retvalshouldbe 0 + contain REGEX "$shellaccount@[a-zA-Z0-9._-]+:22" + contain "allowed ... log on" + nocontain "Permission denied" + nocontain "Could not open a connection to your authentication agent." + + # Run test with -x; agent should spawn + run shellaccount_with_fwd_cfg_shortarg $a0 -x $shellaccount@$remote_ip -- ssh-add -L + retvalshouldbe 0 + contain REGEX "$shellaccount@[a-zA-Z0-9._-]+:22" + contain "allowed ... log on" + nocontain "Permission denied" + nocontain "Could not open a connection to your authentication agent." + + # Patch sshd to allow Agent Forwarding, else all other steps are useless to test + success sshd_config_backup $r0 "\"cp -a /etc/ssh/sshd_config.bak /etc/ssh/sshd_config\"" + success sshd_reload $r0 "\"pkill -SIGHUP -f '^(/usr/sbin/sshd\\\$|sshd.+listener)'\"" + + # Remove access for our testaccount first... + success removeaccess $a0 -osh selfDelPersonalAccess -h $remote_ip -u $shellaccount -p 22 + contain "Access to $shellaccount" + json .command selfDelPersonalAccess .error_code OK .value.port 22 + + # delete account1 + script cleanup $a0 --osh accountDelete --account $account1 "<<< \"Yes, do as I say and delete $account1, kthxbye\"" + retvalshouldbe 0 +} + +testsuite_agent_forwarding +unset -f testsuite_agent_forwarding