-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
461 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#! /usr/bin/perl -T | ||
# vim: set filetype=perl ts=4 sw=4 sts=4 et: | ||
# KEYSUDOERS # as an aclkeeper, we can add/del a server from the group server list in /home/%GROUP%/allowed.ip | ||
# KEYSUDOERS SUPEROWNERS, %%GROUP%-aclkeeper ALL=(%GROUP%) NOPASSWD: /usr/bin/env perl -T %BASEPATH%/bin/helper/osh-groupSetServers --group %GROUP% | ||
# FILEMODE 0755 | ||
# FILEOWN 0 0 | ||
|
||
#>HEADER | ||
use common::sense; | ||
use Getopt::Long qw(:config no_auto_abbrev no_ignore_case); | ||
use JSON; | ||
|
||
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 $group; | ||
eval { | ||
local $SIG{__WARN__} = sub { push @optwarns, shift }; | ||
$result = GetOptions( | ||
"group=s" => sub { $group //= $_[1] }, # ignore subsequent --group on cmdline (anti-sudoers-override) | ||
); | ||
}; | ||
if ($@) { die $@ } | ||
|
||
if (!$result) { | ||
local $" = ", "; | ||
HEXIT('ERR_BAD_OPTIONS', msg => "Error parsing options: @optwarns"); | ||
} | ||
|
||
OVH::Bastion::Helper::check_spurious_args(); | ||
|
||
if (not $group) { | ||
HEXIT('ERR_MISSING_PARAMETER', msg => "Missing argument 'group'"); | ||
} | ||
|
||
#<HEADER | ||
|
||
#>PARAMS:GROUP | ||
osh_debug("Checking group $group"); | ||
$fnret = OVH::Bastion::is_valid_group_and_existing(group => $group, groupType => 'key'); | ||
$fnret or HEXIT($fnret); | ||
|
||
# get returned untainted value | ||
$group = $fnret->value->{'group'}; | ||
my $shortGroup = $fnret->value->{'shortGroup'}; | ||
osh_debug("got group $group/$shortGroup"); | ||
|
||
#<PARAMS:GROUP | ||
|
||
#>RIGHTSCHECK | ||
if ($self eq 'root') { | ||
osh_debug "Real root, skipping checks of permissions"; | ||
} | ||
else { | ||
$fnret = OVH::Bastion::is_group_aclkeeper(account => $self, group => $shortGroup, sudo => 1, superowner => 1); | ||
$fnret or HEXIT('ERR_NOT_ALLOWED', msg => "Sorry, you must be an aclkeeper of group $shortGroup"); | ||
} | ||
|
||
#<RIGHTSCHECK | ||
|
||
#>CODE | ||
|
||
# the new ACL is built by the plugin and sent to our STDIN in pre-parsed JSON format | ||
my $jsonData = <STDIN>; | ||
my $data = eval { decode_json($jsonData); }; | ||
if ($@) { | ||
HEXIT('ERR_INVALID_ARGUMENT', msg => "Invalid JSON data sent by the plugin, couldn't decode"); | ||
} | ||
|
||
if (!$data || ref $data ne 'ARRAY') { | ||
HEXIT('ERR_INVALID_ARGUMENT', msg => "Invalid JSON import format sent by the plugin"); | ||
} | ||
|
||
$fnret = OVH::Bastion::access_modify( | ||
way => 'group', | ||
action => 'clear', | ||
group => $group, | ||
); | ||
$fnret or HEXIT($fnret); | ||
|
||
osh_info("Setting ACL entries, this may take a while..."); | ||
|
||
my @errors; | ||
foreach my $entry (@$data) { | ||
$fnret = OVH::Bastion::access_modify( | ||
way => 'group', | ||
action => 'add', | ||
group => $group, | ||
ip => $entry->{ip}, | ||
user => $entry->{user}, | ||
port => $entry->{port}, | ||
); | ||
push @errors, $fnret if !$fnret; | ||
} | ||
|
||
if (!@errors) { | ||
HEXIT('OK', value => {ACL => $data, errors => []}); | ||
} | ||
HEXIT('OK_WITH_ERRORS', value => {ACL => $data, errors => \@errors}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
#! /usr/bin/env perl | ||
# vim: set filetype=perl ts=4 sw=4 sts=4 et: | ||
use common::sense; | ||
use JSON; | ||
|
||
use File::Basename; | ||
use lib dirname(__FILE__) . '/../../../lib/perl'; | ||
use OVH::Result; | ||
use OVH::Bastion; | ||
use OVH::Bastion::Plugin qw( :DEFAULT help ); | ||
use OVH::Bastion::Plugin::ACL; | ||
|
||
my $remainingOptions = OVH::Bastion::Plugin::begin( | ||
argv => \@ARGV, | ||
header => "replace a group's current ACL by a new one", | ||
userAllowWildcards => 1, | ||
options => { | ||
"group=s" => \my $group, | ||
"dry-run" => \my $dryRun, | ||
"skip-errors" => \my $skipErrors, | ||
}, | ||
helptext => <<'EOF', | ||
Replace a group's current ACL by a new list | ||
Usage: --osh SCRIPT_NAME --group GROUP [OPTIONS] | ||
--group GROUP Specify which group this machine should be added to | ||
--dry-run Don't actually modify the ACL, just report whether the input contains errors | ||
--skip-errors Don't abort on STDIN parsing errors, just skip the non-parseable lines | ||
The list of the assets to constitute the new ACL should then be given on STDIN, | ||
in the following format: ``[USER@]HOST[:PORT][ COMMENT]``, with USER and PORT being optional, | ||
and HOST being either a hostname, an IP, or an IP block in CIDR notation. The COMMENT is | ||
also optional, and may contain spaces. | ||
Examples:: | ||
server12.example.org | ||
logs@server | ||
host1.example.net:2222 host1 on secondary sshd with alternate port | ||
[email protected]/24 production database cluster | ||
EOF | ||
); | ||
|
||
my $fnret; | ||
|
||
if (not $group) { | ||
help(); | ||
osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'group'"; | ||
} | ||
|
||
$fnret = OVH::Bastion::is_valid_group_and_existing(group => $group, groupType => "key"); | ||
$fnret or osh_exit($fnret); | ||
|
||
# get returned untainted value | ||
$group = $fnret->value->{'group'}; | ||
my $shortGroup = $fnret->value->{'shortGroup'}; | ||
|
||
$fnret = OVH::Bastion::is_group_aclkeeper(account => $self, group => $shortGroup, superowner => 1); | ||
$fnret | ||
or osh_exit 'ERR_NOT_GROUP_ACLKEEPER', | ||
"Sorry, you must be an aclkeeper of group $shortGroup to be able to add servers to it"; | ||
|
||
osh_info | ||
"Specify the entries of the new ACL below, one per line, with the following format: [USER\@]HOST[:PORT][ COMMENT]"; | ||
osh_info "The list ends at EOF (usually CTRL+D)."; | ||
osh_info "You may abort with CTRL+C if needed."; | ||
|
||
my @ACL; | ||
my @errors; | ||
my $nbLines = 0; | ||
my $comment; | ||
while (my $line = <STDIN>) { | ||
# trim white spaces | ||
$line =~ s/^\s+|\s+$//g; | ||
|
||
# empty line ? | ||
$line or next; | ||
|
||
$nbLines++; | ||
|
||
if ($line =~ m{^(?:(\S+)\@)?([a-zA-Z0-9_./-]+)(?::(\d+))?(?:\s+(.+))?$}) { | ||
$user = $1; | ||
$host = $2; | ||
$port = $3; | ||
$comment = $4; | ||
} | ||
else { | ||
push @errors, "Couldn't parse the line '$line'"; | ||
osh_warn($errors[-1]); | ||
next; | ||
} | ||
|
||
# check port | ||
if (defined $port) { | ||
$fnret = OVH::Bastion::is_valid_port(port => $port); | ||
if (!$fnret) { | ||
push @errors, "In line $nbLines ($line), port '$port' is invalid"; | ||
osh_warn($errors[-1]); | ||
next; | ||
} | ||
$port = $fnret->value; | ||
} | ||
|
||
# check user | ||
if (defined $user) { | ||
$fnret = OVH::Bastion::is_valid_remote_user(user => $user, allowWildcards => 1); | ||
if (!$fnret) { | ||
push @errors, "In line $nbLines ($line), user '$user' is invalid"; | ||
osh_warn($errors[-1]); | ||
next; | ||
} | ||
$user = $fnret->value; | ||
} | ||
|
||
# resolve host, unless it looks like a prefix | ||
if ($host =~ m{/}) { | ||
$fnret = OVH::Bastion::is_valid_ip(ip => $host, allowPrefixes => 1); | ||
} | ||
else { | ||
$fnret = OVH::Bastion::get_ip(host => $host); | ||
} | ||
if (!$fnret) { | ||
push @errors, "In line $nbLines ($line), $fnret"; | ||
osh_warn($errors[-1]); | ||
next; | ||
} | ||
else { | ||
$ip = $fnret->value->{'ip'}; | ||
} | ||
|
||
push @ACL, {ip => $ip, port => $port, user => $user, comment => $comment}; | ||
} | ||
|
||
osh_info("Parsed " . (scalar(@ACL)) . "/$nbLines lines successfully"); | ||
|
||
if (@errors && !$skipErrors) { | ||
osh_exit( | ||
R( | ||
'ERR_INVALID_PARAMETER', | ||
msg => "Aborting due to the " | ||
. scalar(@errors) | ||
. " parsing or host resolving errors above, use --skip-errors to proceed anyway", | ||
value => {parsedLines => $nbLines, dryrun => $dryRun ? \1 : \0, errors => \@errors, ACL => \@ACL}, | ||
) | ||
); | ||
} | ||
|
||
if ($dryRun) { | ||
osh_ok({parsedLines => $nbLines, errors => \@errors, dryrun => \1, ACL => \@ACL}); | ||
} | ||
|
||
# | ||
# Now do it | ||
# | ||
|
||
if (!@ACL) { | ||
osh_exit(R('OK_NO_CHANGE', msg => "No ACL was given, no change was made")); | ||
} | ||
|
||
my @command = qw{ sudo -n -u }; | ||
push @command, | ||
($group, '--', '/usr/bin/env', 'perl', '-T', $OVH::Bastion::BASEPATH . '/bin/helper/osh-groupSetServers'); | ||
push @command, '--group', $group; | ||
|
||
$fnret = OVH::Bastion::helper(cmd => \@command, stdin_str => encode_json(\@ACL)); | ||
$fnret or osh_exit($fnret); | ||
|
||
# merge both error lists | ||
if ($fnret->value && $fnret->value->{'errors'}) { | ||
push @errors, @{$fnret->value->{'errors'} || []}; | ||
} | ||
|
||
osh_exit( | ||
R( | ||
'OK', | ||
msg => "The new ACL has been set with " | ||
. (scalar @{$fnret->value->{'ACL'}}) | ||
. " entries and " | ||
. (scalar @errors) | ||
. " errors", | ||
value => { | ||
parsedLines => $nbLines, | ||
dryrun => $dryRun ? \1 : \0, | ||
group => $shortGroup, | ||
ACL => $fnret->value->{'ACL'}, | ||
errors => \@errors | ||
} | ||
) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
================ | ||
groupSetServers | ||
================ | ||
|
||
Replace a group's current ACL by a new list | ||
=========================================== | ||
|
||
|
||
.. admonition:: usage | ||
:class: cmdusage | ||
|
||
--osh groupSetServers --group GROUP [OPTIONS] | ||
|
||
.. program:: groupSetServers | ||
|
||
|
||
.. option:: --group GROUP | ||
|
||
Specify which group this machine should be added to | ||
|
||
.. option:: --dry-run | ||
|
||
Don't actually modify the ACL, just report whether the input contains errors | ||
|
||
.. option:: --skip-errors | ||
|
||
Don't abort on STDIN parsing errors, just skip the non-parseable lines | ||
|
||
|
||
The list of the assets to constitute the new ACL should then be given on STDIN, | ||
in the following format: ``[USER@]HOST[:PORT][ COMMENT]``, with USER and PORT being optional, | ||
and HOST being either a hostname, an IP, or an IP block in CIDR notation. The COMMENT is | ||
also optional, and may contain spaces. | ||
|
||
Examples:: | ||
|
||
server12.example.org | ||
logs@server | ||
host1.example.net:2222 host1 on secondary sshd with alternate port | ||
[email protected]/24 production database cluster |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ group-aclkeeper plugins | |
|
||
groupAddServer | ||
groupDelServer | ||
groupSetServers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.