mirror of
https://github.com/ovh/the-bastion.git
synced 2024-09-20 23:15:58 +08:00
feat: groupModify: add --idle-lock-timeout and --idle-kill-timeout for group-specific timeouts
This commit is contained in:
parent
6fb528ccf1
commit
46a01a546a
|
@ -41,7 +41,8 @@ if echo "$DISTRO_LIKE" | grep -q -w debian; then
|
||||||
if [ "$(uname -m)" = armv7l ]; then
|
if [ "$(uname -m)" = armv7l ]; then
|
||||||
wanted_list="$wanted_list wget"
|
wanted_list="$wanted_list wget"
|
||||||
fi
|
fi
|
||||||
[ "$opt_dev" = 1 ] && wanted_list="$wanted_list libperl-critic-perl perltidy shellcheck openssl"
|
[ "$opt_dev" = 1 ] && wanted_list="$wanted_list libperl-critic-perl libtest-deep-perl perltidy shellcheck openssl wget"
|
||||||
|
|
||||||
if { [ "$LINUX_DISTRO" = debian ] && [ "$DISTRO_VERSION_MAJOR" -lt 9 ]; } ||
|
if { [ "$LINUX_DISTRO" = debian ] && [ "$DISTRO_VERSION_MAJOR" -lt 9 ]; } ||
|
||||||
{ [ "$LINUX_DISTRO" = ubuntu ] && [ "$DISTRO_VERSION_MAJOR" -le 16 ]; }; then
|
{ [ "$LINUX_DISTRO" = ubuntu ] && [ "$DISTRO_VERSION_MAJOR" -le 16 ]; }; then
|
||||||
wanted_list="$wanted_list openssh-blacklist openssh-blacklist-extra"
|
wanted_list="$wanted_list openssh-blacklist openssh-blacklist-extra"
|
||||||
|
@ -70,7 +71,7 @@ elif echo "$DISTRO_LIKE" | grep -q -w rhel; then
|
||||||
expect openssh-server netcat bash perl-CGI perl-Test-Simple passwd \
|
expect openssh-server netcat bash perl-CGI perl-Test-Simple passwd \
|
||||||
cracklib-dicts perl-Time-Piece perl-Time-HiRes diffutils \
|
cracklib-dicts perl-Time-Piece perl-Time-HiRes diffutils \
|
||||||
perl-Sys-Syslog pamtester google-authenticator qrencode-libs \
|
perl-Sys-Syslog pamtester google-authenticator qrencode-libs \
|
||||||
perl-LWP-Protocol-https findutils tar"
|
perl-LWP-Protocol-https perl-Test-Deep findutils tar"
|
||||||
if [ "$DISTRO_VERSION_MAJOR" = 7 ]; then
|
if [ "$DISTRO_VERSION_MAJOR" = 7 ]; then
|
||||||
wanted_list="$wanted_list fortune-mod coreutils util-linux"
|
wanted_list="$wanted_list fortune-mod coreutils util-linux"
|
||||||
else
|
else
|
||||||
|
@ -78,6 +79,7 @@ elif echo "$DISTRO_LIKE" | grep -q -w rhel; then
|
||||||
fi
|
fi
|
||||||
[ "$opt_syslogng" = 1 ] && wanted_list="$wanted_list syslog-ng"
|
[ "$opt_syslogng" = 1 ] && wanted_list="$wanted_list syslog-ng"
|
||||||
|
|
||||||
|
|
||||||
if [ "$opt_install" = 1 ]; then
|
if [ "$opt_install" = 1 ]; then
|
||||||
if [ "$DISTRO_VERSION_MAJOR" = 8 ]; then
|
if [ "$DISTRO_VERSION_MAJOR" = 8 ]; then
|
||||||
# in December 2020, they added "-Linux" to their repo name, so trying both combinations
|
# in December 2020, they added "-Linux" to their repo name, so trying both combinations
|
||||||
|
@ -115,7 +117,7 @@ elif echo "$DISTRO_LIKE" | grep -q -w suse; then
|
||||||
perl-Net-Server cryptsetup mosh expect openssh \
|
perl-Net-Server cryptsetup mosh expect openssh \
|
||||||
coreutils netcat-openbsd bash perl-CGI iputils \
|
coreutils netcat-openbsd bash perl-CGI iputils \
|
||||||
perl-Time-HiRes perl-Unix-Syslog hostname perl-LWP-Protocol-https \
|
perl-Time-HiRes perl-Unix-Syslog hostname perl-LWP-Protocol-https \
|
||||||
google-authenticator-libpam tar"
|
google-authenticator-libpam tar perl-Test-Deep"
|
||||||
[ "$opt_syslogng" = 1 ] && wanted_list="$wanted_list syslog-ng"
|
[ "$opt_syslogng" = 1 ] && wanted_list="$wanted_list syslog-ng"
|
||||||
|
|
||||||
if [ "$opt_install" = 1 ]; then
|
if [ "$opt_install" = 1 ]; then
|
||||||
|
@ -129,7 +131,8 @@ elif echo "$DISTRO_LIKE" | grep -q -w suse; then
|
||||||
elif [ "$OS_FAMILY" = FreeBSD ]; then
|
elif [ "$OS_FAMILY" = FreeBSD ]; then
|
||||||
wanted_list="base64 coreutils rsync bash sudo pamtester p5-JSON p5-JSON-XS gnupg \
|
wanted_list="base64 coreutils rsync bash sudo pamtester p5-JSON p5-JSON-XS gnupg \
|
||||||
p5-common-sense p5-DateTime p5-Net-IP p5-DBD-SQLite p5-Net-Netmask lsof \
|
p5-common-sense p5-DateTime p5-Net-IP p5-DBD-SQLite p5-Net-Netmask lsof \
|
||||||
p5-Term-ReadKey expect fping p5-Net-Server p5-CGI p5-LWP-Protocol-https"
|
p5-Term-ReadKey expect fping p5-Net-Server p5-CGI p5-LWP-Protocol-https \
|
||||||
|
p5-Test-Deep"
|
||||||
install_cmd="pkg add"
|
install_cmd="pkg add"
|
||||||
installed=""
|
installed=""
|
||||||
for i in $wanted_list
|
for i in $wanted_list
|
||||||
|
|
|
@ -18,13 +18,15 @@ use OVH::Result;
|
||||||
# Fetch command options
|
# Fetch command options
|
||||||
my $fnret;
|
my $fnret;
|
||||||
my ($result, @optwarns);
|
my ($result, @optwarns);
|
||||||
my ($group, $mfaRequired, $ttl);
|
my ($group, $mfaRequired, $ttl, $idleLockTimeout, $idleKillTimeout);
|
||||||
eval {
|
eval {
|
||||||
local $SIG{__WARN__} = sub { push @optwarns, shift };
|
local $SIG{__WARN__} = sub { push @optwarns, shift };
|
||||||
$result = GetOptions(
|
$result = GetOptions(
|
||||||
"group=s" => sub { $group //= $_[1] },
|
"group=s" => sub { $group //= $_[1] },
|
||||||
"mfa-required=s" => \$mfaRequired,
|
"mfa-required=s" => \$mfaRequired,
|
||||||
"guest-ttl-limit=i" => \$ttl,
|
"guest-ttl-limit=i" => \$ttl,
|
||||||
|
"idle-lock-timeout=i" => \$idleLockTimeout,
|
||||||
|
"idle-kill-timeout=i" => \$idleKillTimeout,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
if ($@) { die $@ }
|
if ($@) { die $@ }
|
||||||
|
@ -40,8 +42,9 @@ if (!$group) {
|
||||||
HEXIT('ERR_MISSING_PARAMETER', msg => "Missing argument 'group'");
|
HEXIT('ERR_MISSING_PARAMETER', msg => "Missing argument 'group'");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$mfaRequired && !defined $ttl) {
|
if (!$mfaRequired && !defined $ttl && !defined $idleLockTimeout && !defined $idleKillTimeout) {
|
||||||
HEXIT('ERR_MISSING_PARAMETER', msg => "Missing argument 'mfa-required' or 'guest-ttl-limit'");
|
HEXIT('ERR_MISSING_PARAMETER',
|
||||||
|
msg => "Missing argument 'mfa-required', 'guest-ttl-limit', 'idle-lock-timeout' or 'idle-kill-timeout'");
|
||||||
}
|
}
|
||||||
|
|
||||||
#<HEADER
|
#<HEADER
|
||||||
|
@ -88,6 +91,69 @@ if (defined $mfaRequired) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my %idleTimeout = (
|
||||||
|
lock => {
|
||||||
|
name => "idle lock timeout",
|
||||||
|
key => \%{OVH::Bastion::OPT_GROUP_IDLE_LOCK_TIMEOUT()},
|
||||||
|
value => $idleLockTimeout,
|
||||||
|
},
|
||||||
|
kill => {
|
||||||
|
name => "idle kill timeout",
|
||||||
|
key => \%{OVH::Bastion::OPT_GROUP_IDLE_KILL_TIMEOUT()},
|
||||||
|
value => $idleKillTimeout,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach my $item (keys %idleTimeout) {
|
||||||
|
next if !defined $idleTimeout{$item}{'value'};
|
||||||
|
|
||||||
|
osh_info "Modifying " . $idleTimeout{$item}{'name'} . " policy of group...";
|
||||||
|
if ($idleTimeout{$item}{'value'} >= 0) {
|
||||||
|
$fnret = OVH::Bastion::group_config(
|
||||||
|
group => $group,
|
||||||
|
%{$idleTimeout{$item}{'key'}}, value => $idleTimeout{$item}{'value'}
|
||||||
|
);
|
||||||
|
if ($fnret) {
|
||||||
|
if ($idleTimeout{$item}{'value'} == 0) {
|
||||||
|
osh_info "... done, this group's " . $idleTimeout{$item}{'name'} . " policy is now set to: disabled";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
osh_info "... done, this group is now configured to use a "
|
||||||
|
. $idleTimeout{$item}{'name'}
|
||||||
|
. " policy of "
|
||||||
|
. OVH::Bastion::duration2human(seconds => $idleTimeout{$item}{'value'})->value->{'human'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
osh_warn "... error while setting the group-specific "
|
||||||
|
. $idleTimeout{$item}{'name'}
|
||||||
|
. " policy ("
|
||||||
|
. $fnret->msg . ")";
|
||||||
|
warn_syslog "Error setting the group-specific "
|
||||||
|
. $idleTimeout{$item}{'name'}
|
||||||
|
. " policy of $group ("
|
||||||
|
. $fnret->msg . ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$fnret = OVH::Bastion::group_config(group => $group, %{$idleTimeout{$item}{'key'}}, delete => 1);
|
||||||
|
if ($fnret) {
|
||||||
|
osh_info "... done, this group will now use the global " . $idleTimeout{$item}{'name'} . " policy";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
osh_warn "... error while removing the group-specific "
|
||||||
|
. $idleTimeout{$item}{'name'}
|
||||||
|
. " policy ("
|
||||||
|
. $fnret->msg . ")";
|
||||||
|
warn_syslog "Error removing the group-specific "
|
||||||
|
. $idleTimeout{$item}{'name'}
|
||||||
|
. " policy of $group ("
|
||||||
|
. $fnret->msg . ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result{$idleTimeout{$item}{'key'}} = $fnret;
|
||||||
|
}
|
||||||
|
|
||||||
if (defined $ttl) {
|
if (defined $ttl) {
|
||||||
osh_info "Modifying guest TTL limit policy of group...";
|
osh_info "Modifying guest TTL limit policy of group...";
|
||||||
if ($ttl > 0) {
|
if ($ttl > 0) {
|
||||||
|
|
|
@ -14,6 +14,8 @@ my $remainingOptions = OVH::Bastion::Plugin::begin(
|
||||||
options => {
|
options => {
|
||||||
"group=s" => \my $group,
|
"group=s" => \my $group,
|
||||||
"mfa-required=s" => \my $mfaRequired,
|
"mfa-required=s" => \my $mfaRequired,
|
||||||
|
"idle-lock-timeout=s" => \my $idleLockTimeout,
|
||||||
|
"idle-kill-timeout=s" => \my $idleKillTimeout,
|
||||||
"guest-ttl-limit=s" => \my $ttl,
|
"guest-ttl-limit=s" => \my $ttl,
|
||||||
},
|
},
|
||||||
helptext => <<'EOF',
|
helptext => <<'EOF',
|
||||||
|
@ -23,8 +25,20 @@ Usage: --osh SCRIPT_NAME --group GROUP [--mfa-required password|totp|any|none] [
|
||||||
|
|
||||||
--group GROUP Name of the group to modify
|
--group GROUP Name of the group to modify
|
||||||
--mfa-required password|totp|any|none Enforce UNIX password requirement, or TOTP requirement, or any MFA requirement, when connecting to a server of the group
|
--mfa-required password|totp|any|none Enforce UNIX password requirement, or TOTP requirement, or any MFA requirement, when connecting to a server of the group
|
||||||
|
--idle-lock-timeout DURATION|0|-1 Overrides the global setting (`idleLockTimeout`), to the specified duration. If set to 0, disables `idleLockTimeout` for
|
||||||
|
this group. If set to -1, remove this group override and use the global setting instead.
|
||||||
|
--idle-kill-timeout DURATION|0|-1 Overrides the global setting (`idleKillTimeout`), to the specified duration. If set to 0, disables `idleKillTimeout` for
|
||||||
|
this group. If set to -1, remove this group override and use the global setting instead.
|
||||||
--guest-ttl-limit DURATION This group will enforce TTL setting, on guest access creation, to be set, and not to a higher value than DURATION,
|
--guest-ttl-limit DURATION This group will enforce TTL setting, on guest access creation, to be set, and not to a higher value than DURATION,
|
||||||
set to zero to allow guest accesses creation without any TTL set (default)
|
set to zero to allow guest accesses creation without any TTL set (default)
|
||||||
|
|
||||||
|
Note that `--idle-lock-timeout` and `--idle-kill-timeout` will NOT be applied for catch-all groups (having 0.0.0.0/0 in their server list).
|
||||||
|
|
||||||
|
If a server is in exactly one group an account is a member of, then its values of `--idle-lock-timeout` and `--idle-kill-timeout`, if set,
|
||||||
|
will prevail over the global setting. The global setting can be seen with `--osh info`.
|
||||||
|
|
||||||
|
Otherwise, the most restrictive setting (i.e. the one with the lower strictly positive duration) between
|
||||||
|
all the considered groups and the global setting, will be used.
|
||||||
EOF
|
EOF
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -34,14 +48,22 @@ if (!$group) {
|
||||||
help();
|
help();
|
||||||
osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'group'";
|
osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'group'";
|
||||||
}
|
}
|
||||||
if (!$mfaRequired && !defined $ttl) {
|
if (!$mfaRequired && !defined $ttl && !defined $idleLockTimeout && !defined $idleKillTimeout) {
|
||||||
help();
|
help();
|
||||||
osh_exit 'ERR_MISSING_PARAMETER', "Nothing to modify";
|
osh_exit 'ERR_MISSING_PARAMETER', "Nothing to modify";
|
||||||
}
|
}
|
||||||
if (defined $ttl) {
|
foreach my $item (\$ttl, \$idleLockTimeout, \$idleKillTimeout) {
|
||||||
$fnret = OVH::Bastion::is_valid_ttl(ttl => $ttl);
|
if (defined $$item && $$item != -1) {
|
||||||
|
$fnret = OVH::Bastion::is_valid_ttl(ttl => $$item);
|
||||||
$fnret or osh_exit $fnret;
|
$fnret or osh_exit $fnret;
|
||||||
$ttl = $fnret->value->{'seconds'};
|
$$item = $fnret->value->{'seconds'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ttl doesn't allow -1 as a valid value, check that
|
||||||
|
if ($ttl == -1) {
|
||||||
|
osh_exit 'ERR_INVALID_PARAMETER',
|
||||||
|
"Invalid TTL (-1), expected an amount of seconds, or a duration string such as '2d8h15m'";
|
||||||
}
|
}
|
||||||
|
|
||||||
$fnret = OVH::Bastion::is_valid_group_and_existing(group => $group, groupType => 'key');
|
$fnret = OVH::Bastion::is_valid_group_and_existing(group => $group, groupType => 'key');
|
||||||
|
@ -66,5 +88,7 @@ push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-groupModify';
|
||||||
push @command, '--group', $group;
|
push @command, '--group', $group;
|
||||||
push @command, '--mfa-required', $mfaRequired if $mfaRequired;
|
push @command, '--mfa-required', $mfaRequired if $mfaRequired;
|
||||||
push @command, '--guest-ttl-limit', $ttl if defined $ttl;
|
push @command, '--guest-ttl-limit', $ttl if defined $ttl;
|
||||||
|
push @command, '--idle-lock-timeout', $idleLockTimeout if defined $idleLockTimeout;
|
||||||
|
push @command, '--idle-kill-timeout', $idleKillTimeout if defined $idleKillTimeout;
|
||||||
|
|
||||||
osh_exit OVH::Bastion::helper(cmd => \@command);
|
osh_exit OVH::Bastion::helper(cmd => \@command);
|
||||||
|
|
|
@ -176,11 +176,25 @@ if ( OVH::Bastion::is_group_owner(group => $shortGroup, account => $self, supe
|
||||||
}
|
}
|
||||||
|
|
||||||
$fnret = OVH::Bastion::group_config(group => $group, key => 'guest_ttl_limit');
|
$fnret = OVH::Bastion::group_config(group => $group, key => 'guest_ttl_limit');
|
||||||
if ($fnret) {
|
if ($fnret && defined $fnret->value && $fnret->value =~ /^\d+$/) {
|
||||||
osh_warn "Guest TTL enforced: guest accesses must have a TTL with a maximum duration of "
|
osh_warn "Guest TTL enforced: guest accesses must have a TTL with a maximum duration of "
|
||||||
. OVH::Bastion::duration2human(seconds => $fnret->value)->value->{'duration'};
|
. OVH::Bastion::duration2human(seconds => $fnret->value)->value->{'duration'};
|
||||||
$result_hash->{'guest_ttl_limit'} = $fnret->value;
|
$result_hash->{'guest_ttl_limit'} = $fnret->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$fnret = OVH::Bastion::group_config(group => $group, %{OVH::Bastion::OPT_GROUP_IDLE_KILL_TIMEOUT()});
|
||||||
|
if ($fnret && defined $fnret->value && $fnret->value =~ /^-?\d+$/) {
|
||||||
|
osh_warn "Specific idle kill timeout: idle sessions on servers of this group will be cut after "
|
||||||
|
. OVH::Bastion::duration2human(seconds => $fnret->value)->value->{'duration'};
|
||||||
|
$result_hash->{'idle_kill_timeout'} = $fnret->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fnret = OVH::Bastion::group_config(group => $group, => %{OVH::Bastion::OPT_GROUP_IDLE_LOCK_TIMEOUT()});
|
||||||
|
if ($fnret && defined $fnret->value && $fnret->value =~ /^-?\d+$/) {
|
||||||
|
osh_warn "Specific idle lock timeout: idle sessions on servers of this group will be locked after "
|
||||||
|
. OVH::Bastion::duration2human(seconds => $fnret->value)->value->{'duration'};
|
||||||
|
$result_hash->{'idle_lock_timeout'} = $fnret->value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
osh_info "You should ask him/her/them if you think you need access for your work tasks.";
|
osh_info "You should ask him/her/them if you think you need access for your work tasks.";
|
||||||
|
|
|
@ -1172,7 +1172,7 @@ if ($osh_debug) {
|
||||||
}
|
}
|
||||||
|
|
||||||
# build ttyrec command that'll prefix the real command
|
# build ttyrec command that'll prefix the real command
|
||||||
my $ttyrec_fnret = OVH::Bastion::build_ttyrec_cmdline(
|
my $ttyrec_fnret = OVH::Bastion::build_ttyrec_cmdline_part1of2(
|
||||||
ip => $ip,
|
ip => $ip,
|
||||||
port => $port,
|
port => $port,
|
||||||
user => $user,
|
user => $user,
|
||||||
|
@ -1310,6 +1310,60 @@ else {
|
||||||
|
|
||||||
push @command, '/usr/bin/ssh', $ip, '-l', $user, '-p', $port;
|
push @command, '/usr/bin/ssh', $ip, '-l', $user, '-p', $port;
|
||||||
|
|
||||||
|
# before listing the accesses and the keys they use, first compute the correct
|
||||||
|
# idle-kill-timeout and idle-lock-timeout value, as these can be overriden for group accesses,
|
||||||
|
# see the help of groupModify command for details on the algorithm's logic, it is also commented below
|
||||||
|
# First, we init the vars with the global setting.
|
||||||
|
my %idleTimeout = (
|
||||||
|
kill => OVH::Bastion::config("idleKillTimeout")->value,
|
||||||
|
lock => OVH::Bastion::config("idleLockTimeout")->value,
|
||||||
|
);
|
||||||
|
|
||||||
|
# Then, gather all the timeouts overrides that may be defined for the matching groups
|
||||||
|
my %idleTimeoutsOverride = (kill => [], lock => []);
|
||||||
|
foreach my $access (@accessList) {
|
||||||
|
next if ($access->{'type'} !~ /^group/);
|
||||||
|
push @{$idleTimeoutsOverride{'kill'}}, $access->{'idleKillTimeout'}
|
||||||
|
if (defined $access->{'idleKillTimeout'} && $access->{'size'} != 2**32);
|
||||||
|
push @{$idleTimeoutsOverride{'lock'}}, $access->{'idleLockTimeout'}
|
||||||
|
if (defined $access->{'idleLockTimeout'} && $access->{'size'} != 2**32);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Now, decide what to apply for each timeout setting
|
||||||
|
foreach my $timeout (qw{ kill lock }) {
|
||||||
|
if (@{$idleTimeoutsOverride{$timeout}} == 0) {
|
||||||
|
|
||||||
|
# zero override, we'll use the global setting,
|
||||||
|
# $idleTimeout{$timeout} is already inited to the global setting
|
||||||
|
osh_debug("idle_timeout: no override for $timeout, using global setting");
|
||||||
|
}
|
||||||
|
elsif (@{$idleTimeoutsOverride{$timeout}} == 1) {
|
||||||
|
|
||||||
|
# exactly one match, use it
|
||||||
|
$idleTimeout{$timeout} = $idleTimeoutsOverride{$timeout}[0];
|
||||||
|
osh_debug("idle_timeout: exactly one override for $timeout, using it");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
osh_debug("idle_timeout: more than one override for $timeout, using the most restrictive one");
|
||||||
|
|
||||||
|
# more than one match, so we add the global setting to the pile
|
||||||
|
push @{$idleTimeoutsOverride{$timeout}}, $idleTimeout{$timeout};
|
||||||
|
|
||||||
|
# and choose the most restrictive one (lowest positive integer)
|
||||||
|
$idleTimeout{$timeout} = (sort { $a <=> $b } grep { $_ > 0 } @{$idleTimeoutsOverride{$timeout}})[0];
|
||||||
|
}
|
||||||
|
osh_debug("idle_timeout: finally using " . $idleTimeout{$timeout} . " for $timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
# adjust the ttyrec cmdline with these parameters
|
||||||
|
$ttyrec_fnret = OVH::Bastion::build_ttyrec_cmdline_part2of2(
|
||||||
|
input => $ttyrec_fnret->value,
|
||||||
|
idleLockTimeout => $idleTimeout{'lock'},
|
||||||
|
idleKillTimeout => $idleTimeout{'kill'}
|
||||||
|
);
|
||||||
|
main_exit(OVH::Bastion::EXIT_TTYREC_CMDLINE_FAILED, "ttyrec_failed", $ttyrec_fnret->msg) if !$ttyrec_fnret;
|
||||||
|
@ttyrec = @{$ttyrec_fnret->value->{'cmd'}};
|
||||||
|
|
||||||
my @keysToTry;
|
my @keysToTry;
|
||||||
print " will try the following accesses you have: \n" unless $quiet;
|
print " will try the following accesses you have: \n" unless $quiet;
|
||||||
foreach my $access (@accessList) {
|
foreach my $access (@accessList) {
|
||||||
|
|
|
@ -119,6 +119,9 @@ use constant {
|
||||||
OPT_ACCOUNT_OSH_ONLY => 'osh_only',
|
OPT_ACCOUNT_OSH_ONLY => 'osh_only',
|
||||||
|
|
||||||
OPT_ACCOUNT_MAX_INACTIVE_DAYS => {key => 'max_inactive_days', public => 1},
|
OPT_ACCOUNT_MAX_INACTIVE_DAYS => {key => 'max_inactive_days', public => 1},
|
||||||
|
|
||||||
|
OPT_GROUP_IDLE_LOCK_TIMEOUT => {key => 'idle_lock_timeout'},
|
||||||
|
OPT_GROUP_IDLE_KILL_TIMEOUT => {key => 'idle_kill_timeout'},
|
||||||
};
|
};
|
||||||
|
|
||||||
###########
|
###########
|
||||||
|
@ -991,6 +994,19 @@ sub get_passfile {
|
||||||
|
|
||||||
sub build_ttyrec_cmdline {
|
sub build_ttyrec_cmdline {
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
|
my $fnret = build_ttyrec_cmdline_part1of2(%params);
|
||||||
|
$fnret or return $fnret;
|
||||||
|
|
||||||
|
# for this simple version, use global timeout values
|
||||||
|
return build_ttyrec_cmdline_part2of2(
|
||||||
|
input => $fnret->value,
|
||||||
|
idleLockTimeout => OVH::Bastion::config("idleLockTimeout")->value,
|
||||||
|
idleKillTimeout => OVH::Bastion::config("idleKillTimeout")->value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub build_ttyrec_cmdline_part1of2 {
|
||||||
|
my %params = @_;
|
||||||
|
|
||||||
if (!$params{'home'}) {
|
if (!$params{'home'}) {
|
||||||
return R('ERR_MISSING_PARAMETER', msg => "Missing home parameter");
|
return R('ERR_MISSING_PARAMETER', msg => "Missing home parameter");
|
||||||
|
@ -1041,11 +1057,6 @@ sub build_ttyrec_cmdline {
|
||||||
}
|
}
|
||||||
|
|
||||||
# forge ttyrec command
|
# forge ttyrec command
|
||||||
my $idleKillTimeout = OVH::Bastion::config('idleKillTimeout')->value;
|
|
||||||
my $idleLockTimeout = OVH::Bastion::config('idleLockTimeout')->value;
|
|
||||||
my $warnBeforeLockSeconds = OVH::Bastion::config('warnBeforeLockSeconds')->value;
|
|
||||||
my $warnBeforeKillSeconds = OVH::Bastion::config('warnBeforeKillSeconds')->value;
|
|
||||||
|
|
||||||
my @ttyrec = ('ttyrec', '-f', $saveFile, '-F', $saveFileFormat);
|
my @ttyrec = ('ttyrec', '-f', $saveFile, '-F', $saveFileFormat);
|
||||||
push @ttyrec, '-v' if $params{'debug'};
|
push @ttyrec, '-v' if $params{'debug'};
|
||||||
push @ttyrec, '-T', 'always' if $params{'tty'};
|
push @ttyrec, '-T', 'always' if $params{'tty'};
|
||||||
|
@ -1060,19 +1071,45 @@ sub build_ttyrec_cmdline {
|
||||||
osh_debug("Account is immune to idle, not adding ttyrec commandline parameters");
|
osh_debug("Account is immune to idle, not adding ttyrec commandline parameters");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
push @ttyrec, '-k', $idleKillTimeout if $idleKillTimeout;
|
my $warnBeforeLockSeconds = OVH::Bastion::config('warnBeforeLockSeconds')->value;
|
||||||
push @ttyrec, '-t', $idleLockTimeout if $idleLockTimeout;
|
my $warnBeforeKillSeconds = OVH::Bastion::config('warnBeforeKillSeconds')->value;
|
||||||
push @ttyrec, '-s', "To unlock, use '--osh unlock' from another console" if $idleLockTimeout;
|
|
||||||
push @ttyrec, '--warn-before-lock', $warnBeforeLockSeconds if $warnBeforeLockSeconds;
|
push @ttyrec, '--warn-before-lock', $warnBeforeLockSeconds if $warnBeforeLockSeconds;
|
||||||
push @ttyrec, '--warn-before-kill', $warnBeforeKillSeconds if $warnBeforeKillSeconds;
|
push @ttyrec, '--warn-before-kill', $warnBeforeKillSeconds if $warnBeforeKillSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $ttyrecAdditionalParameters = OVH::Bastion::config('ttyrecAdditionalParameters')->value;
|
|
||||||
push @ttyrec, @$ttyrecAdditionalParameters if @$ttyrecAdditionalParameters;
|
|
||||||
|
|
||||||
return R('OK', value => {saveFile => $saveFile, cmd => \@ttyrec});
|
return R('OK', value => {saveFile => $saveFile, cmd => \@ttyrec});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# call this after build_ttyrec_cmdline_part1of2, don't forget to
|
||||||
|
# pass part1of2's value output to part2of2's 'input' parameter
|
||||||
|
sub build_ttyrec_cmdline_part2of2 {
|
||||||
|
my %params = @_;
|
||||||
|
|
||||||
|
my $input = $params{'input'};
|
||||||
|
if (!$input) {
|
||||||
|
return R('ERR_MISSING_PARAMETER', msg => "Missing 'input' parameter in build_ttyrec_cmdline_part2of2");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$input->{'cmd'}) {
|
||||||
|
return R('ERR_MISSING_PARAMETER', msg => "Missing 'input->cmd' parameter in build_ttyrec_cmdline_part2of2");
|
||||||
|
}
|
||||||
|
|
||||||
|
my @cmd = @{$input->{'cmd'}};
|
||||||
|
|
||||||
|
my $idleLockTimeout = $params{'idleLockTimeout'};
|
||||||
|
my $idleKillTimeout = $params{'idleKillTimeout'};
|
||||||
|
|
||||||
|
push @cmd, '-k', $idleKillTimeout if $idleKillTimeout;
|
||||||
|
push @cmd, '-t', $idleLockTimeout if $idleLockTimeout;
|
||||||
|
push @cmd, '-s', "To unlock, use '--osh unlock' from another console" if $idleLockTimeout;
|
||||||
|
|
||||||
|
my $ttyrecAdditionalParameters = OVH::Bastion::config('ttyrecAdditionalParameters')->value;
|
||||||
|
push @cmd, @$ttyrecAdditionalParameters if @$ttyrecAdditionalParameters;
|
||||||
|
|
||||||
|
$input->{'cmd'} = \@cmd;
|
||||||
|
return R('OK', value => $input);
|
||||||
|
}
|
||||||
|
|
||||||
sub do_pamtester {
|
sub do_pamtester {
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
my $sysself = $params{'sysself'};
|
my $sysself = $params{'sysself'};
|
||||||
|
|
|
@ -842,36 +842,42 @@ sub is_access_granted {
|
||||||
# 3/3 fill up keys and other metadata info (mfa, idle lock/kill timeout) if asked to
|
# 3/3 fill up keys and other metadata info (mfa, idle lock/kill timeout) if asked to
|
||||||
if ($details) {
|
if ($details) {
|
||||||
foreach my $access (@grants) {
|
foreach my $access (@grants) {
|
||||||
undef $fnret;
|
my %data;
|
||||||
my $mfaFnret;
|
|
||||||
if ($access->{'type'} =~ /^group/ and $access->{'group'}) {
|
if ($access->{'type'} =~ /^group/ and $access->{'group'}) {
|
||||||
$fnret = OVH::Bastion::get_group_keys(
|
$data{'keys'} = OVH::Bastion::get_group_keys(
|
||||||
group => $access->{'group'},
|
group => $access->{'group'},
|
||||||
listOnly => $listOnly,
|
listOnly => $listOnly,
|
||||||
noexec => $noexec,
|
noexec => $noexec,
|
||||||
forceKey => $access->{'forceKey'}
|
forceKey => $access->{'forceKey'}
|
||||||
);
|
);
|
||||||
$mfaFnret = OVH::Bastion::group_config(key => "mfa_required", group => $access->{'group'});
|
$data{'mfa'} = OVH::Bastion::group_config(key => "mfa_required", group => $access->{'group'});
|
||||||
|
$data{'idle_lock_timeout'} = OVH::Bastion::group_config(%{OVH::Bastion::OPT_GROUP_IDLE_LOCK_TIMEOUT()},
|
||||||
|
group => $access->{'group'});
|
||||||
|
$data{'idle_kill_timeout'} = OVH::Bastion::group_config(%{OVH::Bastion::OPT_GROUP_IDLE_KILL_TIMEOUT()},
|
||||||
|
group => $access->{'group'});
|
||||||
}
|
}
|
||||||
elsif ($access->{'type'} =~ /^personal/) {
|
elsif ($access->{'type'} =~ /^personal/) {
|
||||||
$fnret = OVH::Bastion::get_personal_account_keys(
|
$data{'keys'} = OVH::Bastion::get_personal_account_keys(
|
||||||
account => $sysaccount,
|
account => $sysaccount,
|
||||||
listOnly => $listOnly,
|
listOnly => $listOnly,
|
||||||
noexec => $noexec,
|
noexec => $noexec,
|
||||||
forceKey => $access->{'forceKey'}
|
forceKey => $access->{'forceKey'}
|
||||||
);
|
);
|
||||||
$mfaFnret = OVH::Bastion::account_config(key => "personal_egress_mfa_required", account => $sysaccount);
|
$data{'mfa'} =
|
||||||
|
OVH::Bastion::account_config(key => "personal_egress_mfa_required", account => $sysaccount);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# unknown access type? no key!
|
# unknown access type? no key!
|
||||||
warn_syslog("Unknown access type '" . $access->{'type'} . "' found, ignoring");
|
warn_syslog("Unknown access type '" . $access->{'type'} . "' found, ignoring");
|
||||||
}
|
}
|
||||||
if ($fnret) {
|
if ($data{'keys'}) {
|
||||||
|
|
||||||
# TODO implement $access->{forceKey} check to include only the proper key
|
# TODO implement $access->{forceKey} check to include only the proper key
|
||||||
$access->{'keys'} = $fnret->value->{'keys'};
|
$access->{'keys'} = $data{'keys'}->value->{'keys'};
|
||||||
$access->{'sortedKeys'} = $fnret->value->{'sortedKeys'};
|
$access->{'sortedKeys'} = $data{'keys'}->value->{'sortedKeys'};
|
||||||
$access->{'mfaRequired'} = $mfaFnret->value if $mfaFnret;
|
$access->{'mfaRequired'} = $data{'mfa'}->value if $data{'mfa'};
|
||||||
|
$access->{'idleLockTimeout'} = $data{'idle_lock_timeout'}->value if $data{'idle_lock_timeout'};
|
||||||
|
$access->{'idleKillTimeout'} = $data{'idle_kill_timeout'}->value if $data{'idle_kill_timeout'};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
|
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
|
||||||
use common::sense;
|
use common::sense;
|
||||||
use Test::More;
|
use Test::More;
|
||||||
|
use Test::Deep;
|
||||||
|
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use lib dirname(__FILE__) . '/../../lib/perl';
|
use lib dirname(__FILE__) . '/../../lib/perl';
|
||||||
|
@ -46,6 +47,9 @@ OVH::Bastion::load_configuration(
|
||||||
],
|
],
|
||||||
bastionName => "mock",
|
bastionName => "mock",
|
||||||
|
|
||||||
|
idleLockTimeout => 17,
|
||||||
|
idleKillTimeout => 29,
|
||||||
|
|
||||||
# all options below are bool, we'll test for their normalization
|
# all options below are bool, we'll test for their normalization
|
||||||
enableSyslog => 1,
|
enableSyslog => 1,
|
||||||
enableGlobalAccessLog => JSON::true,
|
enableGlobalAccessLog => JSON::true,
|
||||||
|
@ -60,6 +64,98 @@ OVH::Bastion::load_configuration(
|
||||||
);
|
);
|
||||||
|
|
||||||
# TESTS
|
# TESTS
|
||||||
|
my $fnret;
|
||||||
|
|
||||||
|
$fnret = OVH::Bastion::build_ttyrec_cmdline(
|
||||||
|
ip => "127.0.0.1",
|
||||||
|
port => 7979,
|
||||||
|
user => "randomuser",
|
||||||
|
account => "bastionuser",
|
||||||
|
uniqid => 'cafed00dcafe',
|
||||||
|
home => "/home/randomuser",
|
||||||
|
);
|
||||||
|
cmp_deeply(
|
||||||
|
$fnret->value->{'saveFile'},
|
||||||
|
re(
|
||||||
|
qr{^\Q/home/randomuser/ttyrec/127.0.0.1/20\E\d\d-\d\d-\d\d.\d\d\-\d\d\-\d\d\.\d{6}\Q.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec\E$}
|
||||||
|
),
|
||||||
|
"build_ttyrec_cmdline saveFile"
|
||||||
|
);
|
||||||
|
cmp_deeply(
|
||||||
|
$fnret->value->{'cmd'},
|
||||||
|
[
|
||||||
|
'ttyrec',
|
||||||
|
'-f',
|
||||||
|
$fnret->value->{'saveFile'},
|
||||||
|
'-F',
|
||||||
|
'/home/randomuser/ttyrec/127.0.0.1/%Y-%m-%d.%H-%M-%S.#usec#.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec',
|
||||||
|
'-k',
|
||||||
|
29,
|
||||||
|
'-t',
|
||||||
|
17,
|
||||||
|
'-s',
|
||||||
|
"To unlock, use '--osh unlock' from another console",
|
||||||
|
'-k',
|
||||||
|
29,
|
||||||
|
],
|
||||||
|
"build_ttyrec_cmdline cmd"
|
||||||
|
);
|
||||||
|
|
||||||
|
$fnret = OVH::Bastion::build_ttyrec_cmdline_part1of2(
|
||||||
|
ip => "127.0.0.1",
|
||||||
|
port => 7979,
|
||||||
|
user => "randomuser",
|
||||||
|
account => "bastionuser",
|
||||||
|
uniqid => 'cafed00dcafe',
|
||||||
|
home => "/home/randomuser",
|
||||||
|
);
|
||||||
|
cmp_deeply(
|
||||||
|
$fnret->value->{'saveFile'},
|
||||||
|
re(
|
||||||
|
qr{^\Q/home/randomuser/ttyrec/127.0.0.1/20\E\d\d-\d\d-\d\d.\d\d\-\d\d\-\d\d\.\d{6}\Q.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec\E$}
|
||||||
|
),
|
||||||
|
"build_ttyrec_cmdline_part1of2 saveFile"
|
||||||
|
);
|
||||||
|
cmp_deeply(
|
||||||
|
$fnret->value->{'cmd'},
|
||||||
|
[
|
||||||
|
'ttyrec',
|
||||||
|
'-f',
|
||||||
|
$fnret->value->{'saveFile'},
|
||||||
|
'-F',
|
||||||
|
'/home/randomuser/ttyrec/127.0.0.1/%Y-%m-%d.%H-%M-%S.#usec#.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec'
|
||||||
|
],
|
||||||
|
"build_ttyrec_cmdline_part1of2 cmd"
|
||||||
|
);
|
||||||
|
$fnret = OVH::Bastion::build_ttyrec_cmdline_part2of2(
|
||||||
|
input => $fnret->value,
|
||||||
|
idleKillTimeout => 88,
|
||||||
|
idleLockTimeout => 99,
|
||||||
|
);
|
||||||
|
cmp_deeply(
|
||||||
|
$fnret->value->{'saveFile'},
|
||||||
|
re(
|
||||||
|
qr{^\Q/home/randomuser/ttyrec/127.0.0.1/20\E\d\d-\d\d-\d\d.\d\d\-\d\d\-\d\d\.\d{6}\Q.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec\E$}
|
||||||
|
),
|
||||||
|
"build_ttyrec_cmdline_part2of2 saveFile"
|
||||||
|
);
|
||||||
|
cmp_deeply(
|
||||||
|
$fnret->value->{'cmd'},
|
||||||
|
[
|
||||||
|
'ttyrec',
|
||||||
|
'-f',
|
||||||
|
$fnret->value->{'saveFile'},
|
||||||
|
'-F',
|
||||||
|
'/home/randomuser/ttyrec/127.0.0.1/%Y-%m-%d.%H-%M-%S.#usec#.cafed00dcafe.bastionuser.randomuser.127.0.0.1.7979.ttyrec',
|
||||||
|
'-k',
|
||||||
|
88,
|
||||||
|
'-t',
|
||||||
|
99,
|
||||||
|
'-s',
|
||||||
|
"To unlock, use '--osh unlock' from another console"
|
||||||
|
],
|
||||||
|
"build_ttyrec_cmdline_part2of2 cmd"
|
||||||
|
);
|
||||||
|
|
||||||
is(OVH::Bastion::config("bastionName")->value, "mock", "bastion name is mocked");
|
is(OVH::Bastion::config("bastionName")->value, "mock", "bastion name is mocked");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue