mirror of https://github.com/ovh/the-bastion
parent
62613bf894
commit
92bc512050
@ -0,0 +1,119 @@
|
||||
#! /usr/bin/perl -T
|
||||
# vim: set filetype=perl ts=4 sw=4 sts=4 et:
|
||||
# NEEDGROUP osh-assetForgetHostKey
|
||||
# SUDOERS %osh-assetForgetHostKey ALL=(root) NOPASSWD:/usr/bin/env perl -T /opt/bastion/bin/helper/osh-assetForgetHostKey *
|
||||
# FILEMODE 0700
|
||||
# FILEOWN 0 0
|
||||
|
||||
#>HEADER
|
||||
use common::sense;
|
||||
use Getopt::Long qw(:config no_auto_abbrev no_ignore_case);
|
||||
use DateTime;
|
||||
|
||||
use File::Basename;
|
||||
use lib dirname(__FILE__) . '/../../lib/perl';
|
||||
use OVH::Result;
|
||||
use OVH::Bastion;
|
||||
use OVH::Bastion::Helper;
|
||||
|
||||
# Fetch command options
|
||||
my $fnret;
|
||||
my ($result, @optwarns);
|
||||
my ($ip, $port);
|
||||
eval {
|
||||
local $SIG{__WARN__} = sub { push @optwarns, shift };
|
||||
$result = GetOptions(
|
||||
"ip=s" => sub { $ip //= $_[1] },
|
||||
"port=i" => sub { $port //= $_[1] },
|
||||
);
|
||||
};
|
||||
if ($@) { die $@ }
|
||||
|
||||
if (!$result) {
|
||||
local $" = ", ";
|
||||
HEXIT('ERR_BAD_OPTIONS', msg => "Error parsing options: @optwarns");
|
||||
}
|
||||
|
||||
OVH::Bastion::Helper::check_spurious_args();
|
||||
|
||||
if (not $ip or not $port) {
|
||||
HEXIT('ERR_MISSING_PARAMETER', msg => "Missing argument 'ip' or 'port'");
|
||||
}
|
||||
|
||||
#<HEADER
|
||||
|
||||
#>CODE
|
||||
|
||||
# Build the regex we'll be looking for.
|
||||
my $re;
|
||||
if ($port == 22) {
|
||||
# format is "IP ssh-..."
|
||||
$re = qr/^\Q$ip ssh-\E/m;
|
||||
}
|
||||
else {
|
||||
# format is "[IP]:port ssh-..."
|
||||
$re = qr/^\Q[$ip]:$port ssh-\E/m;
|
||||
}
|
||||
|
||||
# First, get all bastion accounts, including realm sysaccounts
|
||||
$fnret = OVH::Bastion::get_account_list();
|
||||
$fnret or HEXIT($fnret);
|
||||
my %accounts = %{$fnret->value || {}};
|
||||
|
||||
$fnret = OVH::Bastion::get_realm_list();
|
||||
$fnret or HEXIT($fnret);
|
||||
foreach my $realmName (keys %{$fnret->value || {}}) {
|
||||
$accounts{$fnret->value->{$realmName}{'sysaccount'}} = $fnret->value->{$realmName};
|
||||
}
|
||||
|
||||
my $nbchanges = 0;
|
||||
my $now = DateTime->now()->iso8601() . 'Z';
|
||||
foreach my $name (keys %accounts) {
|
||||
my $accountHome = $accounts{$name}{'home'};
|
||||
if (!-d $accountHome) {
|
||||
warn_syslog("Account '$name' home '$accountHome' doesn't exist");
|
||||
next;
|
||||
}
|
||||
|
||||
my $knownHosts = "$accountHome/.ssh/known_hosts";
|
||||
if (!-f $knownHosts) {
|
||||
# This can happen if the account has never been used yet
|
||||
next;
|
||||
}
|
||||
|
||||
# now, slurp the file and look for the host we're being asked about
|
||||
if (open(my $fh, '<', $knownHosts)) {
|
||||
my $contents = do {
|
||||
local $/;
|
||||
<$fh>;
|
||||
};
|
||||
close($fh);
|
||||
|
||||
my $nbmatches = $contents =~ s/$re/# removed by $self at $now in session with uniqid $ENV{'UNIQID'}: $&/g;
|
||||
|
||||
# remove found lines if any
|
||||
if ($nbmatches) {
|
||||
osh_info("Removing $nbmatches lines from ${name}'s known_hosts file");
|
||||
if (open($fh, '>', $knownHosts)) {
|
||||
print $fh $contents;
|
||||
close($fh);
|
||||
$nbchanges++;
|
||||
}
|
||||
else {
|
||||
osh_warn("Couldn't adjust ${name}'s known_hosts file");
|
||||
warn_syslog("Error while opening $knownHosts file for write: $!");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
warn_syslog("Couldn't open '$knownHosts': $!");
|
||||
}
|
||||
}
|
||||
|
||||
HEXIT(
|
||||
R(
|
||||
$nbchanges ? 'OK' : 'OK_NO_CHANGE',
|
||||
msg => "Finally modified $nbchanges known_hosts accounts' files",
|
||||
value => {changed_files => $nbchanges}
|
||||
)
|
||||
);
|
||||
@ -0,0 +1,43 @@
|
||||
#! /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 help );
|
||||
|
||||
my $remainingOptions = OVH::Bastion::Plugin::begin(
|
||||
argv => \@ARGV,
|
||||
header => "remove the host key of a given asset from all accounts' known hosts",
|
||||
options => {},
|
||||
helptext => <<'EOF',
|
||||
Remove the host key of a given asset from all accounts' known hosts
|
||||
|
||||
Usage: --osh SCRIPT_NAME --host <HOST|IP> [--port <PORT>]
|
||||
|
||||
--host HOST|IP Asset whose host key should be removed
|
||||
--port PORT Asset port serving SSH (default: 22)
|
||||
EOF
|
||||
);
|
||||
|
||||
if (!$ip) {
|
||||
help();
|
||||
osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter --host (or host didn't resolve correctly)";
|
||||
}
|
||||
|
||||
# IP can't be a prefix
|
||||
if ($ip =~ m{/}) {
|
||||
help();
|
||||
osh_exit 'ERR_INVALID_PARAMETER', "Specified IP must not be a prefix ($ip)";
|
||||
}
|
||||
|
||||
osh_info "Removing $ip host key from accounts...";
|
||||
|
||||
my @command = qw{ sudo -n -u root -- /usr/bin/env perl -T };
|
||||
push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-assetForgetHostKey';
|
||||
push @command, '--ip', $ip;
|
||||
push @command, '--port', ($port ? $port : 22);
|
||||
|
||||
osh_exit OVH::Bastion::helper(cmd => \@command);
|
||||
@ -0,0 +1,24 @@
|
||||
===================
|
||||
assetForgetHostKey
|
||||
===================
|
||||
|
||||
Remove the host key of a given asset from all accounts' known hosts
|
||||
===================================================================
|
||||
|
||||
|
||||
.. admonition:: usage
|
||||
:class: cmdusage
|
||||
|
||||
--osh assetForgetHostKey --host <HOST|IP> [--port <PORT>]
|
||||
|
||||
.. program:: assetForgetHostKey
|
||||
|
||||
|
||||
.. option:: --host HOST|IP
|
||||
|
||||
Asset whose host key should be removed
|
||||
|
||||
.. option:: --port PORT
|
||||
|
||||
Asset port serving SSH (default: 22)
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
# to modify all accounts' known_hosts we need to be root
|
||||
%osh-assetForgetHostKey ALL=(root) NOPASSWD:/usr/bin/env perl -T /opt/bastion/bin/helper/osh-assetForgetHostKey *
|
||||
@ -0,0 +1,73 @@
|
||||
# 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_assetforgethostkey()
|
||||
{
|
||||
# create a1 and a2
|
||||
grant accountCreate
|
||||
|
||||
success create_account1 $a0 --osh accountCreate --account $account1 --uid $uid1 --public-key \""$(cat $account1key1file.pub)"\"
|
||||
json .error_code OK .command accountCreate .value null
|
||||
|
||||
success create_account2 $a0 --osh accountCreate --account $account2 --uid $uid2 --public-key \""$(cat $account2key1file.pub)"\"
|
||||
json .error_code OK .command accountCreate .value null
|
||||
|
||||
revoke accountCreate
|
||||
|
||||
# grant personal accesses to these accounts
|
||||
grant accountAddPersonalAccess
|
||||
|
||||
success a0_allow_a1_localhost $a0 --osh accountAddPersonalAccess --account $account1 --host 127.0.0.0/24 --port '*' --user '*'
|
||||
json .error_code OK .command accountAddPersonalAccess
|
||||
|
||||
success a0_allow_a2_localhost $a0 --osh accountAddPersonalAccess --account $account2 --host 127.0.0.0/24 --port '*' --user '*'
|
||||
json .error_code OK .command accountAddPersonalAccess
|
||||
|
||||
revoke accountAddPersonalAccess
|
||||
|
||||
# connect to localhost from these accounts (it won't work in the end but their known_hosts files will be updated and that's what we need)
|
||||
run a1_connect_localhost1 $a1 user1@127.0.0.1
|
||||
contain "Connecting..."
|
||||
|
||||
run a2_connect_localhost1_226 $a2 user1@127.0.0.1 -p 226
|
||||
contain "Connecting..."
|
||||
|
||||
run a2_connect_localhost1 $a2 user1@127.0.0.1
|
||||
contain "Connecting..."
|
||||
|
||||
run a2_connect_localhost2 $a2 user1@127.0.0.2
|
||||
contain "Connecting..."
|
||||
|
||||
grant assetForgetHostKey
|
||||
|
||||
# now, delete the host keys for 127.0.0.1
|
||||
success a0_asset_forgethostkey $a0 --osh assetForgetHostKey --host 127.0.0.1
|
||||
json .error_code OK .command assetForgetHostKey .value.changed_files 2
|
||||
|
||||
success a0_asset_forgethostkey_dupe $a0 --osh assetForgetHostKey --host 127.0.0.1
|
||||
json .error_code OK_NO_CHANGE .command assetForgetHostKey .value.changed_files 0
|
||||
|
||||
# same but with port 226
|
||||
success a0_asset_forgethostkey_226 $a0 --osh assetForgetHostKey --host 127.0.0.1 --port 226
|
||||
json .error_code OK .command assetForgetHostKey .value.changed_files 1
|
||||
|
||||
success a0_asset_forgethostkey_226_dupe $a0 --osh assetForgetHostKey --host 127.0.0.1 --port 226
|
||||
json .error_code OK_NO_CHANGE .command assetForgetHostKey .value.changed_files 0
|
||||
|
||||
revoke assetForgetHostKey
|
||||
|
||||
# delete those accounts
|
||||
grant accountDelete
|
||||
|
||||
success account1_cleanup $a0 --osh accountDelete --account $account1 --no-confirm
|
||||
success account2_cleanup $a0 --osh accountDelete --account $account2 --no-confirm
|
||||
|
||||
revoke accountDelete
|
||||
}
|
||||
|
||||
testsuite_assetforgethostkey
|
||||
unset -f testsuite_assetforgethostkey
|
||||
Loading…
Reference in new issue