feat: add rsync support to --protocol

This commit is contained in:
Stéphane Lesimple 2024-08-12 11:37:06 +00:00 committed by Stéphane Lesimple
parent 858bb5157e
commit accd50eea7
31 changed files with 1033 additions and 820 deletions

View file

@ -15,16 +15,17 @@ my $remainingOptions = OVH::Bastion::Plugin::begin(
header => "add access to one server of a group to an account",
userAllowWildcards => 1,
options => {
"group=s" => \my $group,
"account=s" => \my $account,
"user-any" => \my $userAny,
"port-any" => \my $portAny,
"scpup" => \my $scpUp,
"scpdown" => \my $scpDown,
"sftp" => \my $sftp,
"rsync" => \my $rsync,
"ttl=s" => \my $ttl,
"comment=s" => \my $comment,
"group=s" => \my $group,
"protocol=s" => \my $protocol,
"account=s" => \my $account,
"ttl=s" => \my $ttl,
"comment=s" => \my $comment,
# undocumented/compatibility:
"user-any" => \my $userAny,
"port-any" => \my $portAny,
"scpup" => \my $scpUp,
"scpdown" => \my $scpDown,
"sftp" => \my $sftp,
},
helptext => <<'EOF',
Add a specific group server access to an account
@ -36,18 +37,22 @@ Usage: --osh SCRIPT_NAME --group GROUP --account ACCOUNT [OPTIONS]
to the USER/HOST/PORT tuple you'll specify with the options below.
--host HOST|IP|NET/CIDR Host(s) to add access to, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
--user USER Specify which remote user should be allowed to connect as.
--user USER|PATTERN|* Specify which remote user should be allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
--user-any Synonym of '--user *', allows connecting as any remote user.
--port PORT Remote port allowed to connect to
--port-any Allow access to any remote port
--scpup Allow SCP upload, you--bastion-->server (omit --user in this case)
--scpdown Allow SCP download, you<--bastion--server (omit --user in this case)
--sftp Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
--rsync Allow usage of rsync through the bastion
--ttl SECONDS|DURATION specify a number of seconds after which the access will automatically expire
--comment '"ANY TEXT"' add a comment alongside this access.
To allow any user, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port allowed to connect to
To allow any port, use '--port *' (you might need to escape '*' from your shell)
--protocol PROTO Specify that a special protocol should be allowed for this HOST:PORT tuple, note that you
must not specify --user in that case. However, for this protocol to be usable under a given
remote user, access to the USER@HOST:PORT tuple must also be allowed.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
--ttl SECONDS|DURATION Specify a number of seconds after which the access will automatically expire
--comment '"ANY TEXT"' Add a comment alongside this access. Quote it twice as shown if you're under a shell.
If omitted, we'll use the closest preexisting group access' comment as seen in groupListServers
This command adds, to an existing bastion account, access to the egress keys of a group,
@ -72,20 +77,21 @@ if (not $ip and $host) {
}
$fnret = OVH::Bastion::Plugin::ACL::check(
user => $user,
userAny => $userAny,
port => $port,
portAny => $portAny,
scpUp => $scpUp,
scpDown => $scpDown,
sftp => $sftp,
rsync => $rsync,
user => $user,
userAny => $userAny,
port => $port,
portAny => $portAny,
scpUp => $scpUp,
scpDown => $scpDown,
sftp => $sftp,
protocol => $protocol,
);
if (!$fnret) {
help();
osh_exit($fnret);
}
$user = $fnret->value->{'user'};
$port = $fnret->value->{'port'};
if (defined $ttl) {
$fnret = OVH::Bastion::is_valid_ttl(ttl => $ttl);
@ -93,15 +99,14 @@ if (defined $ttl) {
$ttl = $fnret->value->{'seconds'};
}
# act() will also call preconditions() which will check all the params
$fnret = OVH::Bastion::Plugin::groupSetRole::act(
account => $account,
group => $group,
action => 'add',
type => 'guest',
user => $user,
userAny => $userAny,
port => $port,
portAny => $portAny,
host => ($ip || $host),
ttl => $ttl,
comment => $comment,

View file

@ -15,34 +15,39 @@ my $remainingOptions = OVH::Bastion::Plugin::begin(
header => "remove access from one server of a group from an account",
userAllowWildcards => 1,
options => {
"group=s" => \my $group,
"account=s" => \my $account,
"user-any" => \my $userAny,
"port-any" => \my $portAny,
"scpup" => \my $scpUp,
"scpdown" => \my $scpDown,
"sftp" => \my $sftp,
"rsync" => \my $rsync,
"group=s" => \my $group,
"protocol=s" => \my $protocol,
"account=s" => \my $account,
# undocumented/compatibility:
"user-any" => \my $userAny,
"port-any" => \my $portAny,
"scpup" => \my $scpUp,
"scpdown" => \my $scpDown,
"sftp" => \my $sftp,
},
helptext => <<'EOF',
Remove a specific group server access from an account
Usage: --osh SCRIPT_NAME --group GROUP --account ACCOUNT [OPTIONS]
--group GROUP Specify which group to remove the guest access to ACCOUNT from
--account ACCOUNT Bastion account remove the guest access from
--group GROUP Specify which group to remove the guest access to ACCOUNT from
--host HOST|IP|NET/CIDR Host(s) to remove access from, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
--user USER Specify which remote user was allowed to connect as.
--user USER|PATTERN|* Specify which remote user was allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
--user-any Synonym of '--user *', allowed connecting as any remote user.
--port PORT Remote port that was allowed to connect to
--port-any Use when access was allowed to any remote port
--scpup Remove SCP upload right, you--bastion-->server (omit --user in this case)
--scpdown Remove SCP download right, you<--bastion--server (omit --user in this case)
--sftp Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
--rsync Remove usage of rsync through the bastion
If any user was allowed, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port that was allowed to connect to
If any user was allowed, use '--port *' (you might need to escape '*' from your shell)
--protocol PROTO Specify that a special protocol was allowed for this HOST:PORT tuple, note that you
must not specify --user in that case. However, for this protocol to be usable under a given
remote user, access to the USER@HOST:PORT tuple must also be allowed.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
This command removes, from an existing bastion account, access to a given server, using the
egress keys of the group. The list of such servers is given by ``groupListGuestAccesses``
@ -65,20 +70,21 @@ if (not $ip and $host) {
}
$fnret = OVH::Bastion::Plugin::ACL::check(
user => $user,
userAny => $userAny,
port => $port,
portAny => $portAny,
scpUp => $scpUp,
scpDown => $scpDown,
sftp => $sftp,
rsync => $rsync,
user => $user,
userAny => $userAny,
port => $port,
portAny => $portAny,
scpUp => $scpUp,
scpDown => $scpDown,
sftp => $sftp,
protocol => $protocol,
);
if (!$fnret) {
help();
osh_exit($fnret);
}
$user = $fnret->value->{'user'};
$port = $fnret->value->{'port'};
$fnret = OVH::Bastion::Plugin::groupSetRole::act(
account => $account,
@ -86,9 +92,7 @@ $fnret = OVH::Bastion::Plugin::groupSetRole::act(
action => 'del',
type => 'guest',
user => $user,
userAny => $userAny,
port => $port,
portAny => $portAny,
host => ($ip || $host),
sudo => 0,
silentoverride => 0,

149
bin/plugin/open/rsync Executable file
View file

@ -0,0 +1,149 @@
#! /usr/bin/env perl
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
use common::sense;
use File::Basename;
use lib dirname(__FILE__) . '/../../../lib/perl';
use OVH::Result;
use OVH::Bastion;
use OVH::Bastion::Plugin qw( :DEFAULT );
use OVH::Bastion::Plugin::otherProtocol;
# stdout is used by rsync, so ensure we output everything through stderr
local $ENV{'FORCE_STDERR'} = 1;
# don't output fancy stuff, this can get digested by rsync and we get garbage output
local $ENV{'PLUGIN_QUIET'} = 1;
# rsync will craft a command-line for our plugin like this one (to upload):
# -l REMOTE_USER REMOTE_HOST rsync --server -vlogDtpre.iLsfxC . REMOTE_DIR
# and like this (to download)
# -l REMOTE_USER REMOTE_HOST rsync --server --sender -vlogDtpre.iLsfxC . REMOTE_DIR
#
# we parse the REMOTE_USER thanks to "options" below, and the remaining of the command-line
# is left untouched thanks to allowUnknownOptions==1
my $remainingOptions = OVH::Bastion::Plugin::begin(
argv => \@ARGV,
header => undef,
allowUnknownOptions => 1,
options => {
"l=s" => \my $opt_user,
},
helptext => <<'EOF',
rsync passthrough using the bastion
Usage examples:
rsync -va --rsh "ssh -T BASTION_USER@BASTION_HOST -p BASTION_PORT -- --osh rsync --" /srcdir remoteuser@remotehost:/dest/
rsync -va --rsh "ssh -T BASTION_USER@BASTION_HOST -p BASTION_PORT -- --osh rsync --" remoteuser@remotehost:/srcdir /dest/
Note that you'll need to be specifically granted to use rsync on the remote server,
in addition to being granted normal SSH access to it.
EOF
);
# validate $opt_user and export it as $user
OVH::Bastion::Plugin::validate_tuple(user => $opt_user);
# validate host passed by rsync and export it as $host/$ip
if (ref $remainingOptions eq 'ARRAY' && @$remainingOptions) {
my $opt_host = shift(@$remainingOptions);
OVH::Bastion::Plugin::validate_tuple(host => $opt_host);
}
else {
osh_exit 'ERR_INVALID_COMMAND',
"No host found, this plugin should be called by rsync.\nUse \`--osh rsync --help\` for more information.";
}
if (ref $remainingOptions eq 'ARRAY' && @$remainingOptions && $remainingOptions->[0] eq 'rsync') {
; # ok, we'll pass all the remaining options as options to the remote server, which will start rsync
}
else {
osh_exit 'ERR_INVALID_COMMAND',
"This plugin should be called by rsync.\nUse \`--osh rsync --help\` for more information.";
}
#
# code
#
my $fnret;
if (not $host) {
help();
osh_exit;
}
if (not $ip) {
# note that the calling-side rsync will not passthrough this exit code, but most probably "1" instead.
osh_exit 'ERR_HOST_NOT_FOUND', "Sorry, couldn't resolve the host you specified ('$host'), aborting.";
}
$port ||= 22; # rsync uses 22 if not specified, so we need to test access to that port and not any port (aka undef)
$user ||= $self; # same for user
$fnret = OVH::Bastion::Plugin::otherProtocol::has_protocol_access(
account => $self,
user => $user,
ip => $ip,
port => $port,
protocol => 'rsync',
);
$fnret or osh_exit($fnret);
my $machine = $fnret->value->{'machine'};
my @keys = @{$fnret->value->{'keys'} || []};
my $mfaRequired = $fnret->value->{'mfaRequired'};
# if we have an mfaRequired here, we have a problem because as we're run by rsync on the client side,
# it's too late to ask for any interactive user input now, as we don't have access to the terminal:
# we can only bail out if MFA was required for this host/group.
if ($mfaRequired) {
# is this account exempt from MFA?
my $hasMfaPasswordBypass =
OVH::Bastion::is_user_in_group(account => $sysself, group => OVH::Bastion::MFA_PASSWORD_BYPASS_GROUP);
my $hasMfaTOTPBypass =
OVH::Bastion::is_user_in_group(account => $sysself, group => OVH::Bastion::MFA_TOTP_BYPASS_GROUP);
if ($mfaRequired eq 'password' && $hasMfaPasswordBypass) {
print STDERR "This host requires password MFA but your account has password MFA bypass, allowing...\n";
}
elsif ($mfaRequired eq 'totp' && $hasMfaTOTPBypass) {
print STDERR "This host requires TOTP MFA but your account has TOTP MFA bypass, allowing...\n";
}
elsif ($mfaRequired eq 'any' && $hasMfaPasswordBypass && $hasMfaTOTPBypass) {
print STDERR "This host requires MFA but your account has MFA bypass, allowing...\n";
}
else {
osh_exit('KO_MFA_REQUIRED', "MFA is required for this host, which is not supported by rsync.");
}
}
# now build the command
my @cmd = qw{ ssh -x -oForwardAgent=no -oPermitLocalCommand=no -oClearAllForwardings=yes };
push @cmd, ('-p', $port) if $port;
push @cmd, ('-l', $user) if $user;
foreach my $key (@keys) {
push @cmd, ('-i', $key);
}
push @cmd, "--", $ip, @$remainingOptions;
print STDERR ">>> Hello $self, running rsync through the bastion on $machine...\n";
$fnret = OVH::Bastion::execute(cmd => \@cmd, expects_stdin => 1, is_binary => 1);
if ($fnret->err ne 'OK') {
osh_exit 'ERR_TRANSFER_FAILED', "Error launching transfer: $fnret";
}
print STDERR sprintf(
">>> Done, %d bytes uploaded, %d bytes downloaded\n",
$fnret->value->{'bytesnb'}{'stdin'} + 0,
$fnret->value->{'bytesnb'}{'stdout'} + 0
);
if ($fnret->value->{'sysret'} != 0) {
print STDERR ">>> On bastion side, rsync exited with return code " . $fnret->value->{'sysret'} . ".\n";
}
# don't use osh_exit() to avoid getting a footer
exit OVH::Bastion::EXIT_OK;

View file

@ -0,0 +1,4 @@
{
"stealth_stdout": true,
"force_stderr": true
}

View file

@ -13,10 +13,10 @@ use OVH::Bastion;
use OVH::Bastion::Plugin qw( :DEFAULT );
use OVH::Bastion::Plugin::otherProtocol;
# stdout is used by scp, so ensure we output everything through stderr
# stdout is used by sftp, so ensure we output everything through stderr
local $ENV{'FORCE_STDERR'} = 1;
# don't output fancy stuff, this can get digested by scp and we get garbage output
# don't output fancy stuff, this can get digested by sftp and we get garbage output
local $ENV{'PLUGIN_QUIET'} = 1;
my $remainingOptions = OVH::Bastion::Plugin::begin(
@ -278,7 +278,7 @@ if (not $ip) {
osh_exit 'ERR_HOST_NOT_FOUND', "Sorry, couldn't resolve the host you specified ('$host'), aborting.";
}
$port ||= 22; # scp uses 22 if not specified, so we need to test access to that port and not any port (aka undef)
$port ||= 22; # sftp uses 22 if not specified, so we need to test access to that port and not any port (aka undef)
$user ||= $self; # same for user
$fnret = OVH::Bastion::Plugin::otherProtocol::has_protocol_access(

View file

@ -1025,7 +1025,7 @@ if ($osh_command) {
# do it themselves, and as they're accessing a remote asset, JIT MFA should apply to them too)
my $pluginJitMfa = OVH::Bastion::plugin_config(plugin => $osh_command, key => "jit_mfa")->value;
if ($pluginJitMfa) {
$fnret = do_plugin_jit_mfa(pluginJitMfa => $pluginJitMfa);
$fnret = do_plugin_jit_mfa();
# do_plugin_jit_mfa exits if needed, but just in case...
main_exit(OVH::Bastion::EXIT_MFA_FAILED, "jit_mfa_failed", $fnret->msg) if !$fnret;
}
@ -1800,10 +1800,13 @@ sub do_jit_mfa {
return R('OK_VALIDATED', value => {mfaInfo => \%mfaInfo});
}
# check whether this plugin wants us to trigger a JIT MFA check depending on the
# specified user/host/ip, if this is configured in one of the matching bastion groups
# we are a part of (plugins such as sftp or scp will require us to do this, as they can't
# do it themselves, and as they're accessing a remote asset, JIT MFA should apply to them too)
#
# this func may exit
sub do_plugin_jit_mfa {
my %params = @_;
my $pluginJitMfa = $params{'pluginJitMfa'}; ### XXX NOT USED
my $localfnret;
if (!$host) {

View file

@ -0,0 +1,31 @@
Transfer files from/to remote servers using rsync through the bastion
=====================================================================
.. note::
This plugin should not be called manually, but passed as the --rsh option to rsync.
Usage examples
--------------
To transfer all files from ``/srcdir`` to the ``remotehost``'s ``/dest/`` directory:
.. code-block: none
rsync -va --rsh "ssh -T BASTION_USER@BASTION_HOST -p BASTION_PORT -- --osh rsync --" /srcdir remoteuser@remotehost:/dest/
The ``-va`` options are just examples, you can use any option of ``rsync`` that you see fit.
To transfer all remote files from ``/srcdir`` to the local ``/dest`` directory:
.. code-block: none
rsync -va --rsh "ssh -T BASTION_USER@BASTION_HOST -p BASTION_PORT -- --osh rsync --" remoteuser@remotehost:/srcdir /dest/
Please note that you need to be granted for uploading or downloading files
with ``rsync`` to/from the remote host, in addition to having the right to SSH to it.
For a group, the right should be added with ``--protocol rsync`` of the :doc:`/plugins/group-aclkeeper/groupAddServer` command.
For a personal access, the right should be added with ``--protocol rsync`` of the :doc:`/plugins/restricted/selfAddPersonalAccess` command.
:doc:`/plugins/open/selfListEgressKeys`
You'll find more information and examples in :doc:`/using/sftp_scp_rsync`.

View file

@ -25,4 +25,4 @@ with scp to/from the remote host, in addition to having the right to SSH to it.
For a group, the right should be added with ``--scpup``/``--scpdown`` of the :doc:`/plugins/group-aclkeeper/groupAddServer` command.
For a personal access, the right should be added with ``--scpup``/``--scpdown`` of the :doc:`/plugins/restricted/selfAddPersonalAccess` command.
You'll find more information and examples in :doc:`/using/sftp_scp`.
You'll find more information and examples in :doc:`/using/sftp_scp_rsync`.

View file

@ -28,4 +28,4 @@ For a group, the right should be added with ``--sftp`` of the :doc:`/plugins/gro
For a personal access, the right should be added with ``--sftp`` of the :doc:`/plugins/restricted/selfAddPersonalAccess` command.
:doc:`/plugins/open/selfListEgressKeys`
You'll find more information and examples in :doc:`/using/sftp_scp`.
You'll find more information and examples in :doc:`/using/sftp_scp_rsync`.

View file

@ -66,7 +66,7 @@ The unavoidable and iconic FAQ is also available under the **PRESENTATION** sect
using/basics/index
using/piv
using/sftp_scp
using/sftp_scp_rsync
using/http_proxy
using/api
using/specific_ssh_clients_tutorials/index

View file

@ -9,7 +9,7 @@ Add an IP or IP block to a group's servers list
.. admonition:: usage
:class: cmdusage
--osh groupAddServer --group GROUP [OPTIONS]
--osh groupAddServer --group GROUP --host HOST --user USER|* --port PORT|* [OPTIONS]
.. program:: groupAddServer
@ -23,40 +23,23 @@ Add an IP or IP block to a group's servers list
Host(s) to add access to, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user should be allowed to connect as.
--user USER|PATTERN|* Specify which remote user should be allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
To allow any user, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port allowed to connect to
To allow any port, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allows connecting as any remote user.
.. option:: --port PORT
Remote port allowed to connect to
.. option:: --port-any
Allow access to any remote port
.. option:: --scpup
Allow SCP upload, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Allow SCP download, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Allow usage of rsync through the bastion
Specify that a special protocol should be allowed for this HOST:PORT tuple, note that you
must not specify --user in that case. However, for this protocol to be usable under a given
remote user, access to the USER@HOST:PORT tuple must also be allowed.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
.. option:: --force
Don't try the ssh connection, just add the host to the group blindly
@ -80,5 +63,10 @@ Add an IP or IP block to a group's servers list
Examples::
--osh groupAddServer --group grp1 --host 203.0.113.0/24 --user-any --port-any --force --comment '"a whole network"'
--osh groupAddServer --group grp2 --host srv1.example.org --user root --port 22
--osh groupAddServer --group grp1 --host 203.0.113.0/24 --user '*' --port '*' --force --ttl 1d12h --comment '"a whole network"'
--osh groupAddServer --group grp2 --host srv1.example.org --user data --port 22
--osh groupAddServer --group grp2 --host srv1.example.org --user file --port 22
Example to allow using sftp to srv1.example.org using remote user 'data' or 'file', in addition to the above commands::
--osh groupAddServer --group grp2 --host srv1.example.org --port 22 --protocol sftp

View file

@ -9,7 +9,7 @@ Remove an IP or IP block from a group's server list
.. admonition:: usage
:class: cmdusage
--osh groupDelServer --group GROUP --host HOST [OPTIONS]
--osh groupDelServer --group GROUP --host HOST --user USER --port PORT [OPTIONS]
.. program:: groupDelServer
@ -23,40 +23,22 @@ Remove an IP or IP block from a group's server list
Host(s) to remove access from, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user was allowed to connect as.
--user USER|PATTERN|* Specify which remote user was allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
If any user was allowed, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port that was allowed to connect to
If any port was allowed, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allowed connecting as any remote user.
.. option:: --port PORT
Remote port that was allowed to connect to
.. option:: --port-any
Use when access was allowed to any remote port
.. option:: --scpup
Remove SCP upload right, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Remove SCP download right, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Remove usage of rsync through the bastion
Specify that a special protocol allowance should be removed from this HOST:PORT tuple, note that you
must not specify --user in that case.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
This command adds, to an existing bastion account, access to a given server, using the
egress keys of the group. The list of eligible servers for a given group is given by ``groupListServers``

View file

@ -28,47 +28,30 @@ Add a specific group server access to an account
Host(s) to add access to, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user should be allowed to connect as.
--user USER|PATTERN|* Specify which remote user should be allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
To allow any user, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port allowed to connect to
To allow any port, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allows connecting as any remote user.
.. option:: --port PORT
Remote port allowed to connect to
.. option:: --port-any
Allow access to any remote port
.. option:: --scpup
Allow SCP upload, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Allow SCP download, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Allow usage of rsync through the bastion
Specify that a special protocol should be allowed for this HOST:PORT tuple, note that you
must not specify --user in that case. However, for this protocol to be usable under a given
remote user, access to the USER@HOST:PORT tuple must also be allowed.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
.. option:: --ttl SECONDS|DURATION
specify a number of seconds after which the access will automatically expire
Specify a number of seconds after which the access will automatically expire
.. option:: --comment '"ANY TEXT"'
add a comment alongside this access.
Add a comment alongside this access. Quote it twice as shown if you're under a shell.
If omitted, we'll use the closest preexisting group access' comment as seen in groupListServers

View file

@ -14,53 +14,36 @@ Remove a specific group server access from an account
.. program:: groupDelGuestAccess
.. option:: --group GROUP
Specify which group to remove the guest access to ACCOUNT from
.. option:: --account ACCOUNT
Bastion account remove the guest access from
.. option:: --group GROUP
Specify which group to remove the guest access to ACCOUNT from
.. option:: --host HOST|IP|NET/CIDR
Host(s) to remove access from, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user was allowed to connect as.
--user USER|PATTERN|* Specify which remote user was allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
If any user was allowed, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port that was allowed to connect to
If any user was allowed, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allowed connecting as any remote user.
.. option:: --port PORT
Remote port that was allowed to connect to
.. option:: --port-any
Use when access was allowed to any remote port
.. option:: --scpup
Remove SCP upload right, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Remove SCP download right, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Remove usage of rsync through the bastion
Specify that a special protocol was allowed for this HOST:PORT tuple, note that you
must not specify --user in that case. However, for this protocol to be usable under a given
remote user, access to the USER@HOST:PORT tuple must also be allowed.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
This command removes, from an existing bastion account, access to a given server, using the
egress keys of the group. The list of such servers is given by ``groupListGuestAccesses``

View file

@ -17,6 +17,7 @@ open plugins
mtr
nc
ping
rsync
scp
selfAddIngressKey
selfDelIngressKey

View file

@ -0,0 +1,35 @@
======
rsync
======
Transfer files from/to remote servers using rsync through the bastion
=====================================================================
.. note::
This plugin should not be called manually, but passed as the --rsh option to rsync.
Usage examples
--------------
To transfer all files from ``/srcdir`` to the ``remotehost``'s ``/dest/`` directory:
.. code-block: none
rsync -va --rsh "ssh -T BASTION_USER@BASTION_HOST -p BASTION_PORT -- --osh rsync --" /srcdir remoteuser@remotehost:/dest/
The ``-va`` options are just examples, you can use any option of ``rsync`` that you see fit.
To transfer all remote files from ``/srcdir`` to the local ``/dest`` directory:
.. code-block: none
rsync -va --rsh "ssh -T BASTION_USER@BASTION_HOST -p BASTION_PORT -- --osh rsync --" remoteuser@remotehost:/srcdir /dest/
Please note that you need to be granted for uploading or downloading files
with ``rsync`` to/from the remote host, in addition to having the right to SSH to it.
For a group, the right should be added with ``--protocol rsync`` of the :doc:`/plugins/group-aclkeeper/groupAddServer` command.
For a personal access, the right should be added with ``--protocol rsync`` of the :doc:`/plugins/restricted/selfAddPersonalAccess` command.
:doc:`/plugins/open/selfListEgressKeys`
You'll find more information and examples in :doc:`/using/sftp_scp_rsync`.

View file

@ -29,4 +29,4 @@ with scp to/from the remote host, in addition to having the right to SSH to it.
For a group, the right should be added with ``--scpup``/``--scpdown`` of the :doc:`/plugins/group-aclkeeper/groupAddServer` command.
For a personal access, the right should be added with ``--scpup``/``--scpdown`` of the :doc:`/plugins/restricted/selfAddPersonalAccess` command.
You'll find more information and examples in :doc:`/using/sftp_scp`.
You'll find more information and examples in :doc:`/using/sftp_scp_rsync`.

View file

@ -32,4 +32,4 @@ For a group, the right should be added with ``--sftp`` of the :doc:`/plugins/gro
For a personal access, the right should be added with ``--sftp`` of the :doc:`/plugins/restricted/selfAddPersonalAccess` command.
:doc:`/plugins/open/selfListEgressKeys`
You'll find more information and examples in :doc:`/using/sftp_scp`.
You'll find more information and examples in :doc:`/using/sftp_scp_rsync`.

View file

@ -9,7 +9,7 @@ Add a personal server access to an account
.. admonition:: usage
:class: cmdusage
--osh accountAddPersonalAccess --account ACCOUNT --host HOST [OPTIONS]
--osh accountAddPersonalAccess --account ACCOUNT --host HOST --user USER --port PORT [OPTIONS]
.. program:: accountAddPersonalAccess
@ -23,43 +23,26 @@ Add a personal server access to an account
Host(s) to add access to, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user should be allowed to connect as.
--user USER|PATTERN|* Specify which remote user should be allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
To allow any user, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port allowed to connect to
To allow any port, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allows connecting as any remote user.
.. option:: --port PORT
Remote port allowed to connect to
.. option:: --port-any
Allow access to any remote port
.. option:: --scpup
Allow SCP upload, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Allow SCP download, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Allow usage of rsync through the bastion
Specify that a special protocol should be allowed for this HOST:PORT tuple, note that you
must not specify --user in that case. However, for this protocol to be usable under a given
remote user, access to the USER@HOST:PORT tuple must also be allowed.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
.. option:: --force-key FINGERPRINT
Only use the key with the specified fingerprint to connect to the server (cf selfListEgressKeys)
Only use the key with the specified fingerprint to connect to the server (cf accountListEgressKeys)
.. option:: --force-password HASH

View file

@ -9,7 +9,7 @@ Remove a personal server access from an account
.. admonition:: usage
:class: cmdusage
--osh accountDelPersonalAccess --account ACCOUNT --host HOST [OPTIONS]
--osh accountDelPersonalAccess --account ACCOUNT --host HOST --user USER --port PORT [OPTIONS]
.. program:: accountDelPersonalAccess
@ -23,37 +23,19 @@ Remove a personal server access from an account
Host(s) to remove access from, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user was allowed to connect as.
--user USER|PATTERN|* Specify which remote user was allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
If any user was allowed, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port that was allowed to connect to
If any port was allowed, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allowed connecting as any remote user.
.. option:: --port PORT
Remote port that was allowed to connect to
.. option:: --port-any
Use when access was allowed to any remote port
.. option:: --scpup
Remove SCP upload right, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Remove SCP download right, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Remove usage of rsync through the bastion
Specify that a special protocol allowance should be removed from this HOST:PORT tuple, note that you
must not specify --user in that case.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion

View file

@ -9,7 +9,7 @@ Add a personal server access to your account
.. admonition:: usage
:class: cmdusage
--osh selfAddPersonalAccess --host HOST [OPTIONS]
--osh selfAddPersonalAccess --host HOST --user USER --port PORT [OPTIONS]
.. program:: selfAddPersonalAccess
@ -19,40 +19,23 @@ Add a personal server access to your account
Host(s) to add access to, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user should be allowed to connect as.
--user USER|PATTERN|* Specify which remote user should be allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
To allow any user, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port allowed to connect to
To allow any port, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allows connecting as any remote user.
.. option:: --port PORT
Remote port allowed to connect to
.. option:: --port-any
Allow access to any remote port
.. option:: --scpup
Allow SCP upload, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Allow SCP download, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Allow usage of rsync through the bastion
Specify that a special protocol should be allowed for this HOST:PORT tuple, note that you
must not specify --user in that case. However, for this protocol to be usable under a given
remote user, access to the USER@HOST:PORT tuple must also be allowed.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion
.. option:: --force
Add the access without checking that the public SSH key is properly installed remotely

View file

@ -9,7 +9,7 @@ Remove a personal server access from your account
.. admonition:: usage
:class: cmdusage
--osh selfDelPersonalAccess --host HOST [OPTIONS]
--osh selfDelPersonalAccess --host HOST --user USER --port PORT [OPTIONS]
.. program:: selfDelPersonalAccess
@ -19,37 +19,19 @@ Remove a personal server access from your account
Host(s) to remove access from, either a HOST which will be resolved to an IP immediately,
or an IP, or a whole network using the NET/CIDR notation
.. option:: --user USER
Specify which remote user was allowed to connect as.
--user USER|PATTERN|* Specify which remote user was allowed to connect as.
Globbing characters '*' and '?' are supported, so you can specify a pattern
that will be matched against the actual remote user name.
.. option:: --user-any
If any user was allowed, use '--user *' (you might need to escape '*' from your shell)
--port PORT|* Remote port that was allowed to connect to
If any port was allowed, use '--port *' (you might need to escape '*' from your shell)
.. option:: --protocol PROTO
Synonym of '--user *', allowed connecting as any remote user.
.. option:: --port PORT
Remote port that was allowed to connect to
.. option:: --port-any
Use when access was allowed to any remote port
.. option:: --scpup
Remove SCP upload right, you--bastion-->server (omit --user in this case)
.. option:: --scpdown
Remove SCP download right, you<--bastion--server (omit --user in this case)
.. option:: --sftp
Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case)
.. option:: --rsync
Remove usage of rsync through the bastion
Specify that a special protocol allowance should be removed from this HOST:PORT tuple, note that you
must not specify --user in that case.
PROTO must be one of:
scpup allow SCP upload, you--bastion-->server
scpdown allow SCP download, you<--bastion--server
sftp allow usage of the SFTP subsystem, through the bastion
rsync allow usage of rsync, through the bastion

View file

@ -1,21 +1,25 @@
==================
SFTP & SCP support
==================
=========================
SFTP, SCP & RSYNC support
=========================
.. contents::
Introduction
============
The Bastion's main goal is to secure ``ssh`` connections. However, one might also want to use ``sftp`` or ``scp`` through it.
The Bastion's main goal is to secure ``ssh`` connections.
However, one might also want to use ``sftp``, ``scp`` or ``rsync`` through it.
Its use is supported through the :doc:`/plugins/open/scp` and :doc:`/plugins/open/sftp` bastion plugins,
respectively, and documented as part of all the plugins.
Its use is supported through the :doc:`/plugins/open/scp`, :doc:`/plugins/open/sftp` and
:doc:`/plugins/open/rsync` bastion plugins, and documented as part of all the plugins.
This additional documentation section gives some examples and outlines some common configuration errors.
Prerequisites
=============
SFTP & SCP
----------
The use of SFTP or SCP through the bastion requires an SFTP or SCP program that supports the **-S** option,
and a shell to run the wrapper. This is the case on all operating systems using OpenSSH such as Linux or \*BSD.
@ -25,26 +29,34 @@ for Linux) environment, to have the OpenSSH version of ``scp`` or ``sftp`` and a
Note that it won't work with Windows GUI apps, because there's no way to specify a wrapper (through **-S**),
and no shell. For example, it won't work under WinSCP.
RSYNC
-----
The use of RSYNC through the bastion only requires rsync to be installed locally and remotely, as is the
case for usage without the bastion.
Basic usage
===========
Please check the :doc:`/plugins/open/scp` and :doc:`/plugins/open/sftp` documentation to see how to use these.
Please check the :doc:`/plugins/open/scp`, :doc:`/plugins/open/sftp` and :doc:`/plugins/open/rsync`
documentation to see how to use these.
Access model
============
.. note::
Currently, to be able to use SFTP or SCP with a remote server,
Currently, to be able to use SFTP, SCP or RSYNC with a remote server,
you first need to have a declared SSH access to it.
This might change in a future version.
Error message 1
---------------
This is briefly explained in the :doc:`/plugins/open/scp`/:doc:`/plugins/open/sftp` documentation,
but having access rights to SSH to a machine is not enough to have the right to SCP to or from it, or use SFTP on it.
If you have the following error, then this is your problem:
This is briefly explained in the :doc:`/plugins/open/scp`/doc:`/plugins/open/sftp`/:doc:`/plugins/open/rsync`
documentation, but having access rights to SSH to a machine is not enough to have the right to SCP to or from it,
or use SFTP/RSYNC on it.
If you have the following error, then this is the problem you're having:
::
@ -52,18 +64,18 @@ If you have the following error, then this is your problem:
The intersection between your rights for ssh and for scp needs to be at least one.
When this happens, it means that you have at least one declared SSH access to this machine (through one or
several groups, or through personal accesses). You also have at least one declared SCP/SFTP access to it.
several groups, or through personal accesses). You also have at least one declared SCP/SFTP/RSYNC access to it.
However **both accesses are declared through different means**, and more precisely different SSH keys. For example:
- You are a member of a group having this machine on one hand, and you have a declared SCP/SFTP access to this machine
- You are a member of a group having this machine on one hand, and you have a declared SCP/SFTP/RSYNC access to this machine
using a personal access on the other hand. For SSH, the group key would be used, but for SCP/SFTP, your personal key
would be used. However, for technical reasons (that might be lifted in a future version), your SSH and SCP/SFTP access
would be used. However, for technical reasons (that might be lifted in a future version), your SSH and SCP/SFTP/RSYNC access
must be declared with the same key, so in other words, using the same access mean (same group, or personal access).
- You are a member of group **A** having this machine, but SCP/SFTP access is declared in group **B**.
- You are a member of group **A** having this machine, but SCP/SFTP/RSYNC access is declared in group **B**.
In that case, as previously, as two different keys are used, this won't work.
To declare an SCP or SFTP access, in addition to a preexisting SSH access, you should use either:
To declare an SCP/SFTP/RSYNC access, in addition to a preexisting SSH access, you should use either:
- :doc:`/plugins/group-aclkeeper/groupAddServer`, if the SSH access is part of a group
@ -71,17 +83,21 @@ To declare an SCP or SFTP access, in addition to a preexisting SSH access, you s
if the SSH access is personal (tied to an account)
In both cases, where you would use the ``--user`` option to the command, to specify the remote user to use for
the SSH access being declared, you should replace it by either ``--scpdown``, ``--scpup`` or ``--sftp``,
to specify that you're about to add an SCP or SFTP access (not an SSH one), and which direction you want to allow.
For SCP ,you can allow both directions by using the command first with ``--scpdown``, then with ``--scpup``.
Note that for SFTP, you can't specify a direction, due to how the protocol works: you either have SFTP access (hence
being able to upload and download files), or you don't.
the SSH access being declared, you should replace it by either ``--protocol scpdown``, ``--protocol scpup``,
``--protocol sftp`` or ``--protocol rsync``,
to specify that you're about to add an SCP/SFTP/RSYNC access (and not a bare SSH one), and which direction you want
to allow in the case of SCP.
For SCP, you can allow both directions by using the command first with ``--protocol scpdown``,
then with ``--protocol scpup``.
Note that for SFTP and RYSNC, you can't specify a direction, due to how these protocols work: you either have
SFTP/RSYNC access (hence being able to upload and download files), or you don't.
For example, this is a valid command to add SFTP access to a machine which is part of a group:
::
bssh --osh groupAddServer --group mygroup --host scpserver.example.org --port 22 --sftp
bssh --osh groupAddServer --group mygroup --host scpserver.example.org --port 22 --protocol sftp
Error message 2
---------------

View file

@ -2,7 +2,7 @@ FROM debian:bookworm
LABEL maintainer="stephane.lesimple+bastion@ovhcloud.com"
# install prerequisites
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y jq netcat-traditional openssh-client procps bsdutils screen expect shellcheck libperl-critic-perl fping curl
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y jq netcat-traditional openssh-client procps bsdutils screen expect shellcheck libperl-critic-perl fping curl rsync
# add our code
COPY . /opt/bastion

View file

@ -25,7 +25,7 @@ sub check {
if ($scpUp or $scpDown or $sftp) {
return R('ERR_INCOMPATIBLE_PARAMETERS', msg => "Can't use --protocol with --scpup, --scpdown or --sftp");
}
if (!grep { $protocol eq $_ } qw{ scpup scpdown sftp rsync }) {
if (!grep { $protocol eq $_ } qw{ scpupload scpdownload sftp rsync }) {
return R('ERR_INVALID_PARAMETER',
msg => "The protocol '$protocol' is not supported, expected either scpup, scpdown, sftp or rsync");
}

View file

@ -8,12 +8,14 @@ use lib dirname(__FILE__) . '/../../../../../lib/perl';
use OVH::Result;
use OVH::Bastion;
# Called by the helper osh-groupSetRole, and also by act() below.
sub preconditions {
my %params = @_;
my ($self, $account, $group, $action, $type, $user, $userAny, $port, $portAny, $host, $ttl, $sudo, $silentoverride)
= @params{
qw{ self account group action type user userAny port portAny host ttl sudo silentoverride }
};
# common params:
my ($self, $account, $group, $action, $type, $sudo, $silentoverride) =
@params{qw{ self account group action type sudo silentoverride }};
# params only used for adding/removing guest accesses:
my ($user, $port, $host, $ttl) = @params{qw{ user port host ttl }};
my $fnret;
if (!$self || !$account || !$group || !$type || !$action) {
@ -34,15 +36,10 @@ sub preconditions {
$type = $1; ## no critic (ProhibitCaptureWithoutTest)
if ($type eq 'guest' && !$sudo) {
# Guest access require a host, user and port might be undef to say 'any', and a ttl can be provided too.
# In sudo mode, these are not used, because the osh-groupSetRole helper that calls us doesn't handle the guest
# access add by itself, the act() func of this package, directly called by the group(Del|Add)GuestAccess plugin, does.
# guest access need (user||user-any), host and (port||port-any)
# in sudo mode, these are not used, because the helper doesn't handle the guest access add by itself, the act() func of this package does
if (!($user xor $userAny)) {
return R('ERR_MISSING_PARAMETER', msg => "Require exactly one argument of user or user-any");
}
if (!($port xor $portAny)) {
return R('ERR_MISSING_PARAMETER', msg => "Require exactly one argument of port or port-any");
}
if (not $host) {
return R('ERR_MISSING_PARAMETER', msg => "Missing argument host for type guest");
}
@ -50,12 +47,12 @@ sub preconditions {
$fnret = OVH::Bastion::is_valid_port(port => $port);
$fnret or return $fnret;
}
if ($user and $user !~ /^[a-zA-Z0-9!._-]+$/) {
return R('ERR_INVALID_PARAMETER', msg => "Invalid remote user ($user) specified");
if ($user) {
$fnret = OVH::Bastion::is_valid_remote_user(user => $user, allowWildcards => 1);
$fnret or return $fnret;
}
if ($action eq 'add') {
# policy check for guest accesses: if group forces ttl, the account creation must comply
$fnret = OVH::Bastion::group_config(group => $group, key => "guest_ttl_limit");
@ -160,6 +157,10 @@ sub preconditions {
);
}
# We handle the proper helper calls (osh-groupSetRole, osh-groupAddSymlinkToAccount, osh-accountAddGroupServer) to modify the roles as asked.
# Called by all the plugins that modify account roles on groups, and also by the groupCreate helper.
# This sub also calls itself in the case of group member add,
# if the account had guest group accesses before, so as to remove them.
sub act {
my %params = @_;
my $fnret = preconditions(%params);
@ -171,8 +172,6 @@ sub act {
@values{qw{ group shortGroup account type realm remoteaccount sysaccount }};
my ($action, $self, $user, $host, $port, $ttl, $comment) = @params{qw{ action self user host port ttl comment }};
undef $user if $params{'userAny'};
undef $port if $params{'portAny'};
my @command;
osh_debug(
@ -216,9 +215,7 @@ sub act {
action => 'del',
type => 'guest',
user => $access->{'user'},
userAny => (defined $access->{'user'} ? 0 : 1),
port => $access->{'port'},
portAny => (defined $access->{'port'} ? 0 : 1),
host => $access->{'ip'},
self => $self,
);

View file

@ -13,6 +13,7 @@ use OVH::Bastion;
# and also that, using the same access way (the same egress ssh keys), that they are granted
# for this host:port using another protocol than ssh (scp, sftp, rsync)
# this requirement will be lifted once we add the "protocol type" to the whole access tuple data model
# while we're at it, return whether we found that this access requires MFA
sub has_protocol_access {
my %params = @_;
my $account = $params{'account'};
@ -67,13 +68,17 @@ sub has_protocol_access {
msg => "Sorry, you have ssh access to $machine, but you need to be granted specifically for $protocol");
}
# get the keys we would try too
# get the keys we would try, along with an eventual mfaRequired flag
my $mfaRequired;
foreach my $access (@{$fnret->value || []}) {
foreach my $key (@{$access->{'sortedKeys'} || []}) {
my $keyfile = $access->{'keys'}{$key}{'fullpath'};
$keys{$keyfile}++ if -r $keyfile;
osh_debug("Checking access 2/2 keyfile: $keyfile");
}
if ($access->{'mfaRequired'} && $access->{'mfaRequired'} ne 'none') {
$mfaRequired = $access->{'mfaRequired'};
}
}
# only use the key if it has been seen in both allow_deny() calls, this is to avoid
@ -94,7 +99,7 @@ sub has_protocol_access {
. " The intersection between your rights for ssh and for $protocol needs to be at least one.");
}
return R('OK', value => {keys => \@validKeys, machine => $machine});
return R('OK', value => {keys => \@validKeys, machine => $machine, mfaRequired => $mfaRequired});
}
1;

View file

@ -5,6 +5,9 @@
# shellcheck disable=SC2046
set -eu
# ensure a sparse '*' somewhere doesn't end up in us expanding it silently
set -f
basedir=$(readlink -f "$(dirname "$0")"/../..)
# shellcheck source=lib/shell/functions.inc
. "$basedir"/lib/shell/functions.inc
@ -424,7 +427,7 @@ run()
# put an invalid value in this file, should be overwritten. we also use it as a lock file.
echo -1 > $outdir/$basename.retval
# run the test
flock "$outdir/$basename.retval" $screen "$outdir/$basename.log" -D -m -fn -ln bash -c "$* ; echo \$? > $outdir/$basename.retval ; sleep $sleepafter"
flock "$outdir/$basename.retval" $screen "$outdir/$basename.log" -D -m -fn -ln bash -c "set -f; $* ; echo \$? > $outdir/$basename.retval ; sleep $sleepafter"
flock "$outdir/$basename.retval" true
unset sleepafter
@ -682,7 +685,8 @@ runtests()
grant accountRevokeCommand
for module in "$(dirname $0)"/tests.d/???-*.sh
# shellcheck disable=SC2044
for module in $(find "$(dirname $0)/tests.d/" -mindepth 1 -maxdepth 1 -type f -name '???-*.sh' | sort)
do
module="$(readlink -f "$module")"
modulename="$(basename "$module" .sh)"

View file

@ -134,7 +134,7 @@ testsuite_selfaccesses()
json .error_code ERR_INVALID_PARAMETER
contain "IPv4 is /30 by this"
success selfAddPersonalAccess_constraints_ok $a0 --osh selfAddPersonalAccess --host 127.0.0.9 --user $account0 --port-any --ttl 1 --force
success selfAddPersonalAccess_constraints_ok $a0 --osh selfAddPersonalAccess --host 127.0.0.9 --user $account0 --port '*' --ttl 1 --force
success selfAddPersonalAccess_delconfig $r0 "rm -f $opt_remote_etc_bastion/plugin.selfAddPersonalAccess.conf"
@ -150,7 +150,7 @@ testsuite_selfaccesses()
json .error_code ERR_INVALID_PARAMETER
contain "IPv4 is /30 by this"
success accountAddPersonalAccess_constaints_ok $a0 --osh accountAddPersonalAccess --host 127.0.0.9 --user $account1 --port-any --ttl 1 --account $account1
success accountAddPersonalAccess_constaints_ok $a0 --osh accountAddPersonalAccess --host 127.0.0.9 --user $account1 --port '*' --ttl 1 --account $account1
success accountAddPersonalAccess_delconfig $r0 "rm -f $opt_remote_etc_bastion/plugin.accountAddPersonalAccess.conf"
@ -442,7 +442,7 @@ testsuite_selfaccesses()
nocontain "already"
json .command selfAddPersonalAccess .error_code ERR_MISSING_PARAMETER .value null
plgfail userportnoforce $a0 -osh selfAddPersonalAccess -h 127.0.0.4 --user-any --port 22
plgfail userportnoforce $a0 -osh selfAddPersonalAccess -h 127.0.0.4 --user '*' --port 22
nocontain "already"
contain REGEX "Couldn't connect to $account0@127.0.0.4 \\(ssh returned error (255|124)\\)"
json .command selfAddPersonalAccess .error_code ERR_CONNECTION_FAILED .value null
@ -485,7 +485,7 @@ testsuite_selfaccesses()
contain "Access to 127.0.0.4 "
json .command selfDelPersonalAccess .error_code OK .value.ip 127.0.0.4 .value.port null .value.user null
success nousernoport_dupe $a0 -osh selfDelPersonalAccess -h 127.0.0.4 --user-any --port-any
success nousernoport_dupe $a0 -osh selfDelPersonalAccess -h 127.0.0.4 --user '*' --port '*'
nocontain "no longer has a personal access"
json .command selfDelPersonalAccess .error_code OK_NO_CHANGE .value null

View file

@ -0,0 +1,538 @@
# 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_mfa_scp_sftp()
{
# these are the old pre-3.14.15 helper versions, we want to check for descendant compatibility
cat >/tmp/scphelper <<'EOF'
#! /bin/sh
while ! [ "$1" = "--" ] ; do
if [ "$1" = "-l" ] ; then
remoteuser="--user $2"
shift 2
elif [ "$1" = "-p" ] ; then
remoteport="--port $2"
shift 2
elif [ "$1" = "-s" ]; then
# caller is a newer scp that tries to use the sftp subsystem
# instead of plain old scp, warn because it won't work
echo "scpwrapper: WARNING: your scp version is recent, you need to add '-O' to your scp command-line, exiting." >&2
exit 1
else
sshcmdline="$sshcmdline $1"
shift
fi
done
host="$2"
scpcmd=`echo "$3" | sed -e 's/#/##/g;s/ /#/g'`
EOF
echo "exec ssh -p $remote_port $account0@$remote_ip -T \$sshcmdline -- \$remoteuser \$remoteport --host \$host --osh scp --scp-cmd \"\$scpcmd\"" >> /tmp/scphelper
chmod +x /tmp/scphelper
cat >/tmp/sftphelper <<'EOF'
#! /usr/bin/env bash
shopt -s nocasematch
while ! [ "$1" = "--" ] ; do
# user
if [ "$1" = "-l" ] ; then
remoteuser="--user $2"
shift 2
elif [[ $1 =~ ^-oUser[=\ ]([^\ ]+)$ ]] ; then
remoteuser="--user ${BASH_REMATCH[1]}"
shift
elif [ "$1" = "-o" ] && [[ $2 =~ ^user=([0-9]+)$ ]] ; then
remoteuser="--user ${BASH_REMATCH[1]}"
shift 2
# port
elif [ "$1" = "-p" ] ; then
remoteport="--port $2"
shift 2
elif [[ $1 =~ ^-oPort[=\ ]([0-9]+)$ ]] ; then
remoteport="--port ${BASH_REMATCH[1]}"
shift
elif [ "$1" = "-o" ] && [[ $2 =~ ^port=([0-9]+)$ ]] ; then
remoteport="--port ${BASH_REMATCH[1]}"
shift 2
# other '-oFoo Bar'
elif [[ $1 =~ ^-o([^\ ]+)\ (.+)$ ]] ; then
sshcmdline="$sshcmdline -o${BASH_REMATCH[1]}=${BASH_REMATCH[2]}"
shift
# don't forward -s
elif [ "$1" = "-s" ]; then
shift
# other stuff passed directly to ssh
else
sshcmdline="$sshcmdline $1"
shift
fi
done
# after '--', remaining args are always host then 'sftp'
host="$2"
subsystem="$3"
if [ "$subsystem" != sftp ]; then
echo "Unknown subsystem requested '$subsystem', expected 'sftp'" >&2
exit 1
fi
# if host is in the form remoteuser@remotehost, split it
if [[ $host =~ @ ]]; then
remoteuser="--user ${host%@*}"
host=${host#*@}
fi
EOF
echo "exec ssh -p $remote_port $account0@$remote_ip -T \$sshcmdline -- \$remoteuser \$remoteport --host \$host --osh sftp" >> /tmp/sftphelper
chmod +x /tmp/sftphelper
## get both helpers first
for proto in scp sftp; do
success $proto $a0 --osh $proto
if [ "$COUNTONLY" != 1 ]; then
get_json | $jq '.value.script' | base64 -d | gunzip -c > /tmp/${proto}wrapper
perl -i -pe 'print "BASTION_SCP_DEBUG=1\nBASTION_SFTP_DEBUG=1\n" if ++$line==2' "/tmp/${proto}wrapper"
chmod +x /tmp/${proto}wrapper
fi
done
unset proto
# scp
## detect recent scp
local scp_options=""
if [ "$COUNTONLY" != 1 ]; then
if scp -O -S /bin/true a: b 2>/dev/null; then
echo "scp: will use new version params"
scp_options="-O"
else
echo "scp: will use old version params"
fi
fi
grant selfAddPersonalAccess
grant selfDelPersonalAccess
### test personal ssh access, must fail without protocol access, must work with protocol access
# scp
success personal_scp_add_ssh_access $a0 --osh selfAddPersonalAccess -h 127.0.0.2 -u $shellaccount -p 22 --kbd-interactive
success personal_scp_add_scpup_access $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --scpup --port 22
sleepafter 2
run personal_scp_download_oldhelper_mustfail scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "Sorry, you have ssh access to"
run personal_scp_download_newwrapper_mustfail env BASTION_SCP_DEBUG=1 /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "Sorry, you have ssh access to"
success personal_scp_add_scpdown_access $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --scpdown --port 22
sleepafter 2
run personal_scp_download_oldhelper_badfile scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "through the bastion from"
contain "Error launching transfer"
contain "No such file or directory"
nocontain "Permission denied"
run personal_scp_download_newwrapper_badfile /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "through the bastion from"
contain "Error launching transfer"
contain "No such file or directory"
nocontain "Permission denied"
run invalidhostname_scp_oldhelper scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@_invalid._invalid:uptest /tmp/downloaded
retvalshouldbe 1
contain REGEX "Sorry, couldn't resolve the host you specified|I was unable to resolve host"
run invalidhostname_scp_newwrapper /tmp/scpwrapper -i $account0key1file $shellaccount@_invalid._invalid:uptest /tmp/downloaded
retvalshouldbe 1
contain REGEX "Sorry, couldn't resolve the host you specified|I was unable to resolve host"
success personal_scp_upload_oldhelper_ok scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:uptest
contain "through the bastion to"
contain "Done,"
success personal_scp_upload_newwrapper_ok /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:uptest
contain "through the bastion to"
contain "Done,"
success personal_scp_download_oldhelper_ok scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
contain "through the bastion from"
contain "Done,"
success personal_scp_download_newwrapper_ok /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
contain "through the bastion from"
contain "Done,"
success personal_scp_del_scpup_access $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --scpup --port 22
success personal_scp_del_scpdown_access $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --scpdown --port 22
# sftp
if [ "$COUNTONLY" != 1 ]; then
printf "ls\nexit\n" >"/tmp/sftpcommands"
fi
run personal_sftp_use_oldhelper_mustfail sftp -F $mytmpdir/ssh_config -S /tmp/sftphelper -i $account0key1file $shellaccount@127.0.0.2
retvalshouldbe 255
contain "Sorry, you have ssh access to"
run personal_sftp_use_newwrapper_mustfail /tmp/sftpwrapper -i $account0key1file $shellaccount@127.0.0.2
retvalshouldbe 255
contain "Sorry, you have ssh access to"
success personal_sftp_add_sftp_access $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --sftp --port 22
success personal_sftp_use_oldhelper_ok sftp -F $mytmpdir/ssh_config -b /tmp/sftpcommands -S /tmp/sftphelper -i $account0key1file $shellaccount@127.0.0.2
contain 'sftp> ls'
contain 'uptest'
contain 'sftp> exit'
contain '>>> Done,'
success personal_sftp_use_newwrapper_ok /tmp/sftpwrapper -b /tmp/sftpcommands -i $account0key1file $shellaccount@127.0.0.2
contain 'sftp> ls'
contain 'uptest'
contain 'sftp> exit'
contain '>>> Done,'
success personal_sftp_del_sftp_access $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --sftp --port 22
# rsync
run personal_rsync_use_mustfail rsync --rsh \"$a0 --osh rsync --\" /etc/passwd $shellaccount@127.0.0.2:/tmp/
retvalshouldbe 2
contain "Sorry, you have ssh access to"
success personal_rsync_add_rsync_access $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --protocol rsync --port 22
success personal_rsync_upload_ok rsync --rsh \"$a0 --osh rsync --\" /etc/passwd $shellaccount@127.0.0.2:rsync_file
nocontain "rsync:"
nocontain "rsync error:"
contain ">>> Hello"
contain ">>> Done,"
success personal_rsync_download_ok rsync --rsh \"$a0 --osh rsync --\" $shellaccount@127.0.0.2:rsync_file /tmp/downloaded
nocontain "rsync:"
nocontain "rsync error:"
contain ">>> Hello"
contain ">>> Done,"
success personal_rsync_del_rsync_access $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --protocol rsync --port 22
### test personal ssh access with group protocol access, must fail, and works only if group ssh access is added too
grant groupCreate
# create group1
success groupCreate $a0 --osh groupCreate --group $group1 --owner $account0 --algo ed25519 --size 256
json .error_code OK .command groupCreate
local g1key
g1key="$(get_json | jq '.value.public_key.line')"
revoke groupCreate
# push group1 egress key to $shellaccount@localhost
success personalssh_groupprotocol_add_key_to_shellaccount $r0 "echo '$g1key' \>\> ~$shellaccount/.ssh/authorized_keys"
# add server to group1
success personalssh_groupprotocol_add_server_to_group $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --user $shellaccount --port 22
# scp
run personalssh_groupprotocol_scp_download_mustfail /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:passwd /tmp/
retvalshouldbe 1
contain 'MFA_TOKEN=notrequired'
contain 'need to be granted specifically for scpdownload'
nocontain '>>> Done'
run personalssh_groupprotocol_scp_upload_mustfail /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
retvalshouldbe 1
contain 'MFA_TOKEN=notrequired'
contain 'need to be granted specifically for scpupload'
nocontain '>>> Done'
success groupssh_groupprotocol_scp_add_scpup_access $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --scpup --port 22
success groupssh_groupprotocol_scp_upload_ok /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
contain 'MFA_TOKEN=notrequired'
contain 'transferring your file through the bastion'
contain '>>> Done'
run personalssh_groupprotocol_scp_download_mustfail /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:passwd /tmp/
retvalshouldbe 1
contain 'MFA_TOKEN=notrequired'
contain 'need to be granted specifically for scpdownload'
nocontain '>>> Done'
success groupssh_groupprotocol_scp_del_scpup_access $a0 --osh groupDelServer --group $group1 --host 127.0.0.2 --scpup --port 22
# sftp
run personalssh_groupprotocol_sftp_download_mustfail /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
retvalshouldbe 255
contain 'MFA_TOKEN=notrequired'
contain 'need to be granted specifically for sftp'
nocontain '>>> Done'
success groupssh_groupprotocol_sftp_add_sftp_access $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --protocol sftp --port 22
success groupssh_groupprotocol_sftp_use_ok /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
contain 'MFA_TOKEN=notrequired'
contain 'Fetching /etc/passwd'
contain '>>> Done'
success groupssh_groupprotocol_sftp_del_sftp_access $a0 --osh groupDelServer --group $group1 --host 127.0.0.2 --protocol sftp --port 22
# rsync
run personalssh_groupprotocol_rsync_download_mustfail rsync --rsh \"$a0 --osh rsync --\" $shellaccount@127.0.0.2:/etc/passwd /tmp/
retvalshouldbe 2
contain 'need to be granted specifically for rsync'
nocontain '>>> Done'
success groupssh_groupprotocol_rsync_add_rsync_access $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --protocol rsync --port 22
success groupssh_groupprotocol_rsync_use_ok rsync --rsh \"$a0 --osh rsync --\" $shellaccount@127.0.0.2:/etc/passwd /tmp/
contain '>>> Hello'
contain '>>> Done,'
success groupssh_groupprotocol_rsync_del_rsync_access $a0 --osh groupDelServer --group $group1 --host 127.0.0.2 --protocol rsync --port 22
## set --personal-egress-mfa-required on this account, and add matching ssh/proto personal access: scp/sftp must request MFA, rsync must be denied
grant accountModify
success personal_egress_mfa $a0 --osh accountModify --account $account0 --personal-egress-mfa-required password
success personal_access_add_scpup $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --port 22 --protocol scpupload
success personal_access_add_sftp $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --port 22 --protocol sftp
success personal_access_add_rsync $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --port 22 --protocol rsync
# scp
run account_mfa_scp_upload_mfa_fail /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# sftp
run account_mfa_sftp_use_mfa_fail /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# rsync
run account_mfa_rsync_use_mfa_fail rsync --rsh \"$a0 --osh rsync --\" $shellaccount@127.0.0.2:/etc/passwd /tmp/
retvalshouldbe 2
contain 'MFA is required for this host, which is not supported by rsync'
contain 'rsync error:'
# reset --personal-egress-mfa-required on this account and remove protocol personal accesses
success personal_egress_nomfa $a0 --osh accountModify --account $account0 --personal-egress-mfa-required none
revoke accountModify
success personal_access_del_scpup $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --port 22 --protocol scpupload
success personal_access_del_sftp $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --port 22 --protocol sftp
success personal_access_del_rsync $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --port 22 --protocol rsync
## set MFA required on group (and add back group protocol access), MFA should be asked by scp/sftp, and rsync should abort
success group_need_mfa $a0 --osh groupModify --group $group1 --mfa-required password
success account_mfa_scp_add_scpup_access $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --protocol scpupload --port 22
success account_mfa_sftp_add_sftp_access $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --protocol sftp --port 22
success account_mfa_rsync_add_rsync_access $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --protocol rsync --port 22
# scp
run group_mfa_scp_upload_mfa_fail /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# sftp
run group_mfa_sftp_upload_mfa_fail /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# rsync
run group_mfa_rsync_use_mfa_fail rsync --rsh \"$a0 --osh rsync --\" $shellaccount@127.0.0.2:/etc/passwd /tmp/
retvalshouldbe 2
nocontain 'MFA_TOKEN='
contain 'MFA is required for this host, which is not supported by rsync'
contain 'rsync error:'
## keep MFA required on group, but setup MFA on our account, so we can test the MFA process
# setup MFA on our account, step1
run personal_mfa_setup_step1of2 $a0f --osh selfMFASetupPassword --yes
retvalshouldbe 124
contain 'enter this:'
local a0_password_tmp
a0_password_tmp=$(get_stdout | grep -Eo 'enter this: [a-zA-Z0-9_-]+' | sed -e 's/enter this: //')
# setup our password, step2
local a0_password='ohz8Ciujuboh'
script personal_mfa_setup_step2of2 "echo 'set timeout $default_timeout;
spawn $a0 --osh selfMFASetupPassword --yes;
expect \":\" { sleep 0.2; send \"$a0_password_tmp\\n\"; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
retvalshouldbe 0
unset a0_password_tmp
nocontain 'enter this:'
nocontain 'unchanged'
nocontain 'sorry'
json .command selfMFASetupPassword .error_code OK
# scp
script group_mfa_scp_upload_mfa_ok "echo 'set timeout $default_timeout;
spawn /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2: ;
expect \"is required (password)\" { sleep 0.1; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
nocontain 'MFA_TOKEN=notrequired'
if [ "${capabilities[mfa]}" = 1 ] || [ "${capabilities[mfa-password]}" = 1 ]; then
retvalshouldbe 0
contain 'MFA_TOKEN=v1,'
else
retvalshouldbe 1
contain 'this bastion is missing'
fi
# sftp
script group_mfa_sftp_use_mfa_ok "echo 'set timeout $default_timeout;
spawn /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd ;
expect \"is required (password)\" { sleep 0.1; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
nocontain 'MFA_TOKEN=notrequired'
if [ "${capabilities[mfa]}" = 1 ] || [ "${capabilities[mfa-password]}" = 1 ]; then
retvalshouldbe 0
contain 'MFA_TOKEN=v1,'
else
retvalshouldbe 1
contain 'this bastion is missing'
fi
# rsync
run group_mfa_rsync_use_mfa_unsupported rsync --rsh \"$a0 --osh rsync --\" $shellaccount@127.0.0.2:/etc/passwd /tmp/
retvalshouldbe 2
nocontain 'MFA_TOKEN='
contain 'MFA is required for this host, which is not supported by rsync'
contain 'rsync error:'
# provide invalid tokens manually
for proto in scp sftp; do
run ${proto}_upload_bad_token_format $a0 --osh ${proto} --host 127.0.0.2 --port 22 --user $shellaccount --mfa-token invalid
retvalshouldbe 125
json .error_code KO_MFA_FAILED_INVALID_FORMAT
local invalid_token
invalid_token="v1,$(perl -e 'CORE::say time()-3600'),9f25d680b1bae2ef73abc3c62926ddb9c88f8ea1f4120b1125cc09720c74268b"
run ${proto}_upload_bad_token_expired $a0 --osh ${proto} --host 127.0.0.2 --port 22 --user $shellaccount --mfa-token "$invalid_token"
retvalshouldbe 125
json .error_code KO_MFA_FAILED_EXPIRED_TOKEN
invalid_token="v1,$(perl -e 'CORE::say time()+3600'),9f25d680b1bae2ef73abc3c62926ddb9c88f8ea1f4120b1125cc09720c74268b"
run ${proto}_upload_bad_token_future $a0 --osh ${proto} --host 127.0.0.2 --port 22 --user $shellaccount --mfa-token "$invalid_token"
retvalshouldbe 125
json .error_code KO_MFA_FAILED_FUTURE_TOKEN
done
# remove MFA from account
if [ "${capabilities[mfa]}" = 1 ] || [ "${capabilities[mfa-password]}" = 1 ]; then
script personal_mfa_reset_password "echo 'set timeout $default_timeout;
spawn $a0 --osh selfMFAResetPassword;
expect \"additional authentication factor is required (password)\" { sleep 0.1; };
expect \"word:\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
retvalshouldbe 0
json .error_code OK .command selfMFAResetPassword
else
grant accountMFAResetPassword
success personal_mfa_reset_password $a0 --osh accountMFAResetPassword --account $account0
fi
## set account as exempt from MFA, and see whether scp/sftp/rsync (that still require MFA as per the group) do work
grant accountModify
success personal_mfa_set_exempt $a0 --osh accountModify --account $account0 --mfa-password-required bypass
success scp_upload_mfa_exempt_oldhelper_ok /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
nocontain 'MFA_TOKEN=v1'
contain 'MFA_TOKEN=notrequired'
contain 'skipping as your account is exempt from MFA'
script sftp_upload_mfa_exempt_oldhelper_ok /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
nocontain 'MFA_TOKEN=v1'
contain 'MFA_TOKEN=notrequired'
contain 'skipping as your account is exempt from MFA'
sleepafter 2
success scp_upload_mfa_exempt_oldwrapper_ok scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:uptest
contain 'skipping as your account is exempt from MFA'
contain "through the bastion to"
contain "Done,"
success sftp_use_mfa_exempt_oldwrapper_ok sftp -F $mytmpdir/ssh_config -b /tmp/sftpcommands -S /tmp/sftphelper -i $account0key1file $shellaccount@127.0.0.2
contain 'skipping as your account is exempt from MFA'
contain 'sftp> ls'
contain 'uptest'
contain 'sftp> exit'
contain '>>> Done,'
run rsync_use_mfa_exempt_ok rsync --rsh \"$a0 --osh rsync --\" $shellaccount@127.0.0.2:/etc/passwd /tmp/
nocontain "rsync:"
nocontain "rsync error:"
contain "requires password MFA but your account has password MFA bypass, allowing"
contain ">>> Hello"
contain ">>> Done,"
# reset account setup
success personal_mfa_reset_policy $a0 --osh accountModify --account $account0 --mfa-password-required no
revoke accountModify
# delete group1
success groupDestroy $a0 --osh groupDestroy --group $group1 --no-confirm
revoke selfAddPersonalAccess
revoke selfDelPersonalAccess
}
testsuite_mfa_scp_sftp
unset -f testsuite_mfa_scp_sftp

View file

@ -1,445 +0,0 @@
# 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_mfa_scp_sftp()
{
# these are the old pre-3.14.15 helper versions, we want to check for descendant compatibility
cat >/tmp/scphelper <<'EOF'
#! /bin/sh
while ! [ "$1" = "--" ] ; do
if [ "$1" = "-l" ] ; then
remoteuser="--user $2"
shift 2
elif [ "$1" = "-p" ] ; then
remoteport="--port $2"
shift 2
elif [ "$1" = "-s" ]; then
# caller is a newer scp that tries to use the sftp subsystem
# instead of plain old scp, warn because it won't work
echo "scpwrapper: WARNING: your scp version is recent, you need to add '-O' to your scp command-line, exiting." >&2
exit 1
else
sshcmdline="$sshcmdline $1"
shift
fi
done
host="$2"
scpcmd=`echo "$3" | sed -e 's/#/##/g;s/ /#/g'`
EOF
echo "exec ssh -p $remote_port $account0@$remote_ip -T \$sshcmdline -- \$remoteuser \$remoteport --host \$host --osh scp --scp-cmd \"\$scpcmd\"" >> /tmp/scphelper
chmod +x /tmp/scphelper
cat >/tmp/sftphelper <<'EOF'
#! /usr/bin/env bash
shopt -s nocasematch
while ! [ "$1" = "--" ] ; do
# user
if [ "$1" = "-l" ] ; then
remoteuser="--user $2"
shift 2
elif [[ $1 =~ ^-oUser[=\ ]([^\ ]+)$ ]] ; then
remoteuser="--user ${BASH_REMATCH[1]}"
shift
elif [ "$1" = "-o" ] && [[ $2 =~ ^user=([0-9]+)$ ]] ; then
remoteuser="--user ${BASH_REMATCH[1]}"
shift 2
# port
elif [ "$1" = "-p" ] ; then
remoteport="--port $2"
shift 2
elif [[ $1 =~ ^-oPort[=\ ]([0-9]+)$ ]] ; then
remoteport="--port ${BASH_REMATCH[1]}"
shift
elif [ "$1" = "-o" ] && [[ $2 =~ ^port=([0-9]+)$ ]] ; then
remoteport="--port ${BASH_REMATCH[1]}"
shift 2
# other '-oFoo Bar'
elif [[ $1 =~ ^-o([^\ ]+)\ (.+)$ ]] ; then
sshcmdline="$sshcmdline -o${BASH_REMATCH[1]}=${BASH_REMATCH[2]}"
shift
# don't forward -s
elif [ "$1" = "-s" ]; then
shift
# other stuff passed directly to ssh
else
sshcmdline="$sshcmdline $1"
shift
fi
done
# after '--', remaining args are always host then 'sftp'
host="$2"
subsystem="$3"
if [ "$subsystem" != sftp ]; then
echo "Unknown subsystem requested '$subsystem', expected 'sftp'" >&2
exit 1
fi
# if host is in the form remoteuser@remotehost, split it
if [[ $host =~ @ ]]; then
remoteuser="--user ${host%@*}"
host=${host#*@}
fi
EOF
echo "exec ssh -p $remote_port $account0@$remote_ip -T \$sshcmdline -- \$remoteuser \$remoteport --host \$host --osh sftp" >> /tmp/sftphelper
chmod +x /tmp/sftphelper
## get both helpers first
for proto in scp sftp; do
success $proto $a0 --osh $proto
if [ "$COUNTONLY" != 1 ]; then
get_json | $jq '.value.script' | base64 -d | gunzip -c > /tmp/${proto}wrapper
perl -i -pe 'print "BASTION_SCP_DEBUG=1\nBASTION_SFTP_DEBUG=1\n" if ++$line==2' "/tmp/${proto}wrapper"
chmod +x /tmp/${proto}wrapper
fi
done
unset proto
# scp
## detect recent scp
local scp_options=""
if [ "$COUNTONLY" != 1 ]; then
if scp -O -S /bin/true a: b 2>/dev/null; then
echo "scp: will use new version params"
scp_options="-O"
else
echo "scp: will use old version params"
fi
fi
grant selfAddPersonalAccess
grant selfDelPersonalAccess
success a0_add_ssh_access $a0 --osh selfAddPersonalAccess -h 127.0.0.2 -u $shellaccount -p 22 --kbd-interactive
success a0_add_scp_up $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --scpup --port 22
sleepafter 2
run scp_downloadfailnoright_old scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "Sorry, but even"
run scp_downloadfailnoright_new env BASTION_SCP_DEBUG=1 /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "Sorry, but even"
success a0_add_scp_down $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --scpdown --port 22
sleepafter 2
run scp_downloadfailnofile_old scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "through the bastion from"
contain "Error launching transfer"
contain "No such file or directory"
nocontain "Permission denied"
run scp_downloadfailnofile_new /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
retvalshouldbe 1
contain "through the bastion from"
contain "Error launching transfer"
contain "No such file or directory"
nocontain "Permission denied"
run scp_invalidhostname_old scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@_invalid._invalid:uptest /tmp/downloaded
retvalshouldbe 1
contain REGEX "Sorry, couldn't resolve the host you specified|I was unable to resolve host"
run scp_invalidhostname_new /tmp/scpwrapper -i $account0key1file $shellaccount@_invalid._invalid:uptest /tmp/downloaded
retvalshouldbe 1
contain REGEX "Sorry, couldn't resolve the host you specified|I was unable to resolve host"
success scp_upload_old scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:uptest
contain "through the bastion to"
contain "Done,"
success scp_upload_new /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:uptest
contain "through the bastion to"
contain "Done,"
success scp_download_old scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
contain "through the bastion from"
contain "Done,"
success scp_download_new /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:uptest /tmp/downloaded
contain "through the bastion from"
contain "Done,"
success forscpremove1 $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --scpup --port 22
success forscpremove2 $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --scpdown --port 22
# sftp
run sftp_no_access_old sftp -F $mytmpdir/ssh_config -S /tmp/sftphelper -i $account0key1file $shellaccount@127.0.0.2
retvalshouldbe 255
contain "Sorry, but even"
run sftp_no_access_new /tmp/sftpwrapper -i $account0key1file $shellaccount@127.0.0.2
retvalshouldbe 255
contain "Sorry, but even"
success forsftp $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --sftp --port 22
if [ "$COUNTONLY" != 1 ]; then
cat >"/tmp/sftpcommands" <<'EOF'
ls
exit
EOF
fi
success sftp_access_old sftp -F $mytmpdir/ssh_config -b /tmp/sftpcommands -S /tmp/sftphelper -i $account0key1file $shellaccount@127.0.0.2
contain 'sftp> ls'
contain 'uptest'
contain 'sftp> exit'
contain '>>> Done,'
success sftp_access_new /tmp/sftpwrapper -b /tmp/sftpcommands -i $account0key1file $shellaccount@127.0.0.2
contain 'sftp> ls'
contain 'uptest'
contain 'sftp> exit'
contain '>>> Done,'
success forsftpremove $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --sftp --port 22
grant groupCreate
# create group1
success groupCreate $a0 --osh groupCreate --group $group1 --owner $account0 --algo ed25519 --size 256
json .error_code OK .command groupCreate
local g1key
g1key="$(get_json | jq '.value.public_key.line')"
revoke groupCreate
# push group1 egress key to $shellaccount@localhost
success add_grp1_key_to_shellaccount $r0 "echo '$g1key' \>\> ~$shellaccount/.ssh/authorized_keys"
# add server to group1
success groupAddServer $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --user $shellaccount --port 22
# scp: upload something (denied, not granted)
run scp_upload_denied /tmp/scpwrapper -i $account0key1file $shellaccount@127.0.0.2:passwd /tmp/
retvalshouldbe 1
contain 'MFA_TOKEN=notrequired'
contain 'you still need to be granted specifically for scp'
nocontain '>>> Done'
# allow scpup
success allow_scpup $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --scpup --port 22
# scp: upload something
success scp_upload /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
contain 'MFA_TOKEN=notrequired'
contain 'transferring your file through the bastion'
contain '>>> Done'
# sftp: download something (denied, not granted)
run sftp_download_denied /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
retvalshouldbe 255
contain 'MFA_TOKEN=notrequired'
contain 'you still need to be granted specifically for sftp'
nocontain '>>> Done'
# allow sftp
success allow_sftp $a0 --osh groupAddServer --group $group1 --host 127.0.0.2 --sftp --port 22
# sftp: download something
success sftp_download /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
contain 'MFA_TOKEN=notrequired'
contain 'Fetching /etc/passwd'
contain '>>> Done'
# set --personal-egress-mfa-required on this account
grant accountModify
success personal_egress_mfa $a0 --osh accountModify --account $account0 --personal-egress-mfa-required password
# add personal access
grant selfAddPersonalAccess
success a0_add_personal_access_ssh $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --user $shellaccount --port 22 --force
success a0_add_personal_access_scpup $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --scpup --port 22
success a0_add_personal_access_sftp $a0 --osh selfAddPersonalAccess --host 127.0.0.2 --sftp --port 22
revoke selfAddPersonalAccess
# scp: upload something after personal mfa, wont work
run scp_upload_personal_mfa_fail /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# sftp: download something after personal mfa, wont work
run sftp_upload_personal_mfa_fail /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# reset --personal-egress-mfa-required on this account
success personal_egress_nomfa $a0 --osh accountModify --account $account0 --personal-egress-mfa-required none
revoke accountModify
# del personal access
grant selfDelPersonalAccess
success a0_del_personal_access_ssh $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --user $shellaccount --port 22
success a0_del_personal_access_scpup $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --scpup --port 22
success a0_del_personal_access_sftp $a0 --osh selfDelPersonalAccess --host 127.0.0.2 --sftp --port 22
revoke selfDelPersonalAccess
# now set MFA required on group
success group_need_mfa $a0 --osh groupModify --group $group1 --mfa-required password
# scp: upload something after mfa, wont work
run scp_upload_mfa_fail /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# sftp: download something after mfa, wont work
run sftp_upload_mfa_fail /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
retvalshouldbe 1
nocontain 'MFA_TOKEN=notrequired'
contain 'entering MFA phase'
contain 'you need to setup the Multi-Factor Authentication for this plugin'
# setup MFA on our account, step1
run a0_setup_pass_step1of2 $a0f --osh selfMFASetupPassword --yes
retvalshouldbe 124
contain 'enter this:'
local a0_password_tmp
a0_password_tmp=$(get_stdout | grep -Eo 'enter this: [a-zA-Z0-9_-]+' | sed -e 's/enter this: //')
# setup our password, step2
local a0_password='ohz8Ciujuboh'
script a0_setup_pass_step2of2 "echo 'set timeout $default_timeout;
spawn $a0 --osh selfMFASetupPassword --yes;
expect \":\" { sleep 0.2; send \"$a0_password_tmp\\n\"; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
retvalshouldbe 0
unset a0_password_tmp
nocontain 'enter this:'
nocontain 'unchanged'
nocontain 'sorry'
json .command selfMFASetupPassword .error_code OK
# scp: upload something after mfa, should work
script scp_upload_mfa_ok "echo 'set timeout $default_timeout;
spawn /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2: ;
expect \"is required (password)\" { sleep 0.1; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
nocontain 'MFA_TOKEN=notrequired'
if [ "${capabilities[mfa]}" = 1 ] || [ "${capabilities[mfa-password]}" = 1 ]; then
retvalshouldbe 0
contain 'MFA_TOKEN=v1,'
else
retvalshouldbe 1
contain 'this bastion is missing'
fi
# sftp: upload something after mfa, should work
script sftp_upload_mfa_ok "echo 'set timeout $default_timeout;
spawn /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd ;
expect \"is required (password)\" { sleep 0.1; };
expect \":\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
nocontain 'MFA_TOKEN=notrequired'
if [ "${capabilities[mfa]}" = 1 ] || [ "${capabilities[mfa-password]}" = 1 ]; then
retvalshouldbe 0
contain 'MFA_TOKEN=v1,'
else
retvalshouldbe 1
contain 'this bastion is missing'
fi
# provide invalid tokens manually
run scp_upload_bad_token_format $a0 --osh scp --host 127.0.0.2 --port 22 --user $shellaccount --mfa-token invalid
retvalshouldbe 125
json .error_code KO_MFA_FAILED_INVALID_FORMAT
local invalid_token
invalid_token="v1,$(perl -e 'CORE::say time()-3600'),9f25d680b1bae2ef73abc3c62926ddb9c88f8ea1f4120b1125cc09720c74268b"
run scp_upload_bad_token_expired $a0 --osh scp --host 127.0.0.2 --port 22 --user $shellaccount --mfa-token "$invalid_token"
retvalshouldbe 125
json .error_code KO_MFA_FAILED_EXPIRED_TOKEN
invalid_token="v1,$(perl -e 'CORE::say time()+3600'),9f25d680b1bae2ef73abc3c62926ddb9c88f8ea1f4120b1125cc09720c74268b"
run scp_upload_bad_token_future $a0 --osh scp --host 127.0.0.2 --port 22 --user $shellaccount --mfa-token "$invalid_token"
retvalshouldbe 125
json .error_code KO_MFA_FAILED_FUTURE_TOKEN
# remove MFA from account
if [ "${capabilities[mfa]}" = 1 ] || [ "${capabilities[mfa-password]}" = 1 ]; then
script a0_reset_password "echo 'set timeout $default_timeout;
spawn $a0 --osh selfMFAResetPassword;
expect \"additional authentication factor is required (password)\" { sleep 0.1; };
expect \"word:\" { sleep 0.2; send \"$a0_password\\n\"; };
expect eof;
lassign [wait] pid spawnid value value;
exit \$value' | timeout --foreground $default_timeout expect -f -"
retvalshouldbe 0
json .error_code OK .command selfMFAResetPassword
else
grant accountMFAResetPassword
success a0_reset_password $a0 --osh accountMFAResetPassword --account $account0
fi
# set account as exempt from MFA
grant accountModify
success a0_mfa_bypass $a0 --osh accountModify --account $account0 --mfa-password-required bypass
# scp: upload something after exempt from mfa
success scp_upload_mfa_exempt_ok /tmp/scpwrapper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:
nocontain 'MFA_TOKEN=v1'
contain 'MFA_TOKEN=notrequired'
contain 'skipping as your account is exempt from MFA'
# sftp: upload something after except from mfa
script sftp_upload_mfa_exempt_ok /tmp/sftpwrapper -i $account0key1file sftp://$shellaccount@127.0.0.2//etc/passwd
nocontain 'MFA_TOKEN=v1'
contain 'MFA_TOKEN=notrequired'
contain 'skipping as your account is exempt from MFA'
# same but with old helpers
sleepafter 2
success scp_upload_mfa_exempt_old_ok scp $scp_options -F $mytmpdir/ssh_config -S /tmp/scphelper -i $account0key1file /etc/passwd $shellaccount@127.0.0.2:uptest
contain 'skipping as your account is exempt from MFA'
contain "through the bastion to"
contain "Done,"
success sftp_list_mfa_exempt_old_ok sftp -F $mytmpdir/ssh_config -b /tmp/sftpcommands -S /tmp/sftphelper -i $account0key1file $shellaccount@127.0.0.2
contain 'skipping as your account is exempt from MFA'
contain 'sftp> ls'
contain 'uptest'
contain 'sftp> exit'
contain '>>> Done,'
# reset account setup
success a0_mfa_default $a0 --osh accountModify --account $account0 --mfa-password-required no
revoke accountModify
# delete group1
success groupDestroy $a0 --osh groupDestroy --group $group1 --no-confirm
revoke selfAddPersonalAccess
revoke selfDelPersonalAccess
}
testsuite_mfa_scp_sftp
unset -f testsuite_mfa_scp_sftp