diff --git a/bin/shell/osh.pl b/bin/shell/osh.pl index 73dd07f..254c6de 100755 --- a/bin/shell/osh.pl +++ b/bin/shell/osh.pl @@ -373,6 +373,7 @@ my $remainingOptions; "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 @@ else { # 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 @@ else { } } + # -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 @@ Usage (osh cmd): $bastionName --osh [OSH_COMMAND] [OSH_OPTIONS] --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 876afc8..1913e56 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 436c0d0..6c68e31 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 a99f191..0ff53db 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/lib/perl/OVH/Bastion/configuration.inc b/lib/perl/OVH/Bastion/configuration.inc index bfdb75f..34ed976 100644 --- a/lib/perl/OVH/Bastion/configuration.inc +++ b/lib/perl/OVH/Bastion/configuration.inc @@ -275,7 +275,7 @@ sub load_configuration { qw{ interactiveModeAllowed readOnlySlaveMode sshClientHasOptionE ingressKeysFromAllowOverride moshAllowed debug keyboardInteractiveAllowed passwordAllowed telnetAllowed remoteCommandEscapeByDefault - accountExternalValidationDenyOnFailure ingressRequirePIV IPv6Allowed + accountExternalValidationDenyOnFailure ingressRequirePIV IPv6Allowed sshAddKeysToAgentAllowed } ], } diff --git a/tests/functional/tests.d/346-testagentforward.sh b/tests/functional/tests.d/346-testagentforward.sh new file mode 100644 index 0000000..fdb41d8 --- /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 + success sshd_config_backup $r0 "\"cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak\"" + success sshd_config_patch $r0 "\"command -v freebsd-version >/dev/null && sed -I '' 's=^AllowAgentForwarding no=AllowAgentForwarding yes=' /etc/ssh/sshd_config || sed -i 's=^AllowAgentForwarding no=AllowAgentForwarding yes=' /etc/ssh/sshd_config\"" + # pkill doesn't work well under FreeBSD, so do it ourselves for all OSes + success sshd_reload $r0 "\"ps -U 0 -o pid,command | grep -E '/usr/sbin/sshd\\\$|sshd:.+liste[n]er' | awk '{print \\\$1}' | xargs -r kill -SIGHUP\"" + # during tests, under some OSes it takes some time for sshd to accept new connections again after the SIGHUP + [ "$COUNTONLY" != 1 ] && sleep 1 + + # 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\"" + # pkill doesn't work well under FreeBSD, so do it ourselves for all OSes + success sshd_reload $r0 "\"ps -U 0 -o pid,command | grep -E '/usr/sbin/sshd\\\$|sshd:.+liste[n]er' | awk '{print \\\$1}' | xargs -r kill -SIGHUP\"" + + # 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