#! /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 ); use OVH::Bastion::Plugin::ACL; my $remainingOptions = OVH::Bastion::Plugin::begin( loadConfig => 1, argv => \@ARGV, header => "adding personal access to a server on your account", userAllowWildcards => 1, options => { "protocol=s" => \my $protocol, "force-key=s" => \my $forceKey, "force-password=s" => \my $forcePassword, "force" => \my $force, "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 personal server access to your account Usage: --osh SCRIPT_NAME --host HOST --user USER --port PORT [OPTIONS] --host HOST|IP|PREFIX/SIZE Host(s) to add access to, either a HOST which will be resolved to an IP immediately, or an IP, or a whole netblock using the PREFIX/SIZE notation --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. 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: scpupload allow SCP upload, you--bastion-->server scpdownload allow SCP download, you<--bastion--server sftp allow usage of the SFTP subsystem, through the bastion rsync allow usage of rsync, through the bastion --force Add the access without checking that the public SSH key is properly installed remotely --force-key FINGERPRINT Only use the key with the specified fingerprint to connect to the server (cf selfListEgressKeys) --force-password HASH Only use the password with the specified hash to connect to the server (cf selfListPasswords) --ttl SECONDS|DURATION Specify a number of seconds (or a duration string, such as "1d7h8m") after which the access will automatically expire --comment "'ANY TEXT'" Add a comment alongside this server. Quote it twice as shown if you're under a shell. EOF ); =pod CONFIGURATION =head1 items =head2 widest_v4_prefix (optional, integer, between 0 and 32) When specified, this limits the size of prefixes that can be added to an ACL, e.g. 24 would not allow prefixes wider than /24 (such as /20 or /16). Note that this doesn't prevent users from adding thousands of ACLs to cover a wide range of networks, but this helps ensuring ACLs such as 0.0.0.0/0 can't be added in a single command. =head2 self_remote_user_only (optional, boolean) When true, this only allows to add ACLs with the remote user being the same than the account name, i.e. a bastion account named "johndoe" would only be able to use ``selfAddPersonalAccess --user johndoe``. =head1 example { "widest_v4_prefix": 24, "self_remote_user_only": true } =cut my $fnret; if (!$ip) { help(); osh_exit 'ERR_MISSING_PARAMETER', "Missing parameter 'host' or didn't resolve correctly"; } $fnret = OVH::Bastion::Plugin::ACL::check( 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); $fnret or osh_exit $fnret; $ttl = $fnret->value->{'seconds'}; } if ($forceKey && $forcePassword) { osh_exit 'ERR_INCOMPATIBLE_PARAMETERS', "Can't use --force-key and --force-password at the same time"; } if ($forceKey) { $fnret = OVH::Bastion::is_valid_fingerprint(fingerprint => $forceKey); $fnret or osh_exit $fnret; $forceKey = $fnret->value->{'fingerprint'}; } if ($forcePassword) { $fnret = OVH::Bastion::is_valid_hash(hash => $forcePassword); $fnret or osh_exit $fnret; $forcePassword = $fnret->value->{'hash'}; } # # Now do it # # check plugin config if ($pluginConfig && $pluginConfig->{'self_remote_user_only'}) { if (!$user || $user ne $self) { osh_exit('ERR_INVALID_PARAMETER', msg => "This bastion policy forces the remote user of personal accesses to match\n" . "the account name: you may retry with --user $self"); } } # if no comment is specified, but we're adding the server by hostname, # use it to craft a comment if (!$comment && $host ne $ip) { $comment = "hostname=$host"; } # use dryrun to validate all parameters $fnret = OVH::Bastion::access_modify( dryrun => 1, sudo => 0, way => 'personal', account => $self, action => 'add', user => $user, ip => $ip, port => $port, ttl => $ttl, forceKey => $forceKey, forcePassword => $forcePassword, comment => $comment, widestV4Prefix => ($pluginConfig ? $pluginConfig->{'widest_v4_prefix'} : undef), ); $fnret or osh_exit($fnret); if (not $force) { $fnret = OVH::Bastion::ssh_test_access_way( account => $self, user => $user, port => $port, ip => $ip, forceKey => $forceKey, forcePassword => $forcePassword ); if ($fnret->is_ok and $fnret->err ne 'OK') { # we have something to say, say it osh_info $fnret->msg; } elsif (not $fnret) { osh_info "Note: if you still want to add this access even if it doesn't work, use --force"; osh_exit $fnret; } } else { osh_info "Forcing add as asked, we didn't test the SSH connection, maybe it won't work!"; } my @command = qw{ sudo -n -u allowkeeper -- /usr/bin/env perl -T }; push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-accountModifyPersonalAccess'; push @command, '--target', 'self'; push @command, '--action', 'add'; push @command, '--account', $self; push @command, '--ip', $ip; push @command, '--user', $user if $user; push @command, '--port', $port if $port; push @command, '--force-key', $forceKey if $forceKey; push @command, '--force-password', $forcePassword if $forcePassword; push @command, '--ttl', $ttl if $ttl; push @command, '--comment', $comment if $comment; osh_exit OVH::Bastion::helper(cmd => \@command);