From 34fa77a0d6bf099dc4153d91077475044ccd8750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lesimple?= Date: Mon, 12 Aug 2024 11:32:46 +0000 Subject: [PATCH] enh: plugins: add --protocol to handle scp, sftp, rsync Replace --sftp --scpup --scpdown by --protocol PROTOCOL. Also take the opportunity to replace --user-any by --user * and --port-any by --port *. All the legacy options are still supported but are now undocumented. --- bin/plugin/group-aclkeeper/groupAddServer | 59 +++++++++++------- bin/plugin/group-aclkeeper/groupDelServer | 42 +++++++------ .../group-gatekeeper/groupAddGuestAccess | 5 +- .../group-gatekeeper/groupDelGuestAccess | 5 +- .../restricted/accountAddPersonalAccess | 61 +++++++++++-------- .../restricted/accountDelPersonalAccess | 50 ++++++++------- bin/plugin/restricted/selfAddPersonalAccess | 59 +++++++++++------- bin/plugin/restricted/selfDelPersonalAccess | 38 +++++++----- .../group-aclkeeper/groupAddServer.rst | 4 ++ .../group-aclkeeper/groupDelServer.rst | 4 ++ .../group-gatekeeper/groupAddGuestAccess.rst | 4 ++ .../group-gatekeeper/groupDelGuestAccess.rst | 4 ++ .../restricted/accountAddPersonalAccess.rst | 4 ++ .../restricted/accountDelPersonalAccess.rst | 4 ++ .../restricted/selfAddPersonalAccess.rst | 4 ++ .../restricted/selfDelPersonalAccess.rst | 4 ++ lib/perl/OVH/Bastion/Plugin/ACL.pm | 61 ++++++++++++++----- lib/perl/OVH/Bastion/Plugin/otherProtocol.pm | 4 +- lib/perl/OVH/Bastion/allowdeny.inc | 10 ++- lib/perl/OVH/Bastion/allowkeeper.inc | 16 ++--- 20 files changed, 289 insertions(+), 153 deletions(-) diff --git a/bin/plugin/group-aclkeeper/groupAddServer b/bin/plugin/group-aclkeeper/groupAddServer index 0e8d12561..79b487a33 100755 --- a/bin/plugin/group-aclkeeper/groupAddServer +++ b/bin/plugin/group-aclkeeper/groupAddServer @@ -15,34 +15,41 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( userAllowWildcards => 1, options => { "group=s" => \my $group, - "user-any" => \my $userAny, - "port-any" => \my $portAny, - "scpup" => \my $scpUp, - "scpdown" => \my $scpDown, - "sftp" => \my $sftp, + "protocol=s" => \my $protocol, "force" => \my $force, # for slashes, and/or for servers that are down (no connection test) "force-key=s" => \my $forceKey, "force-password=s" => \my $forcePassword, "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 an IP or IP block to a group's servers list -Usage: --osh SCRIPT_NAME --group GROUP [OPTIONS] +Usage: --osh SCRIPT_NAME --group GROUP --host HOST --user USER|* --port PORT|* [OPTIONS] --group GROUP Specify which group this machine should be added to --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) + 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 --force Don't try the ssh connection, just add the host to the group blindly --force-key FINGERPRINT Only use the key with the specified fingerprint to connect to the server (cf groupInfo) --force-password HASH Only use the password with the specified hash to connect to the server (cf groupListPasswords) @@ -51,8 +58,13 @@ Usage: --osh SCRIPT_NAME --group GROUP [OPTIONS] Examples:: - --osh SCRIPT_NAME --group grp1 --host 203.0.113.0/24 --user-any --port-any --force --comment '"a whole network"' - --osh SCRIPT_NAME --group grp2 --host srv1.example.org --user root --port 22 + --osh SCRIPT_NAME --group grp1 --host 203.0.113.0/24 --user '*' --port '*' --force --ttl 1d12h --comment '"a whole network"' + --osh SCRIPT_NAME --group grp2 --host srv1.example.org --user data --port 22 + --osh SCRIPT_NAME --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 SCRIPT_NAME --group grp2 --host srv1.example.org --port 22 --protocol sftp EOF ); @@ -65,19 +77,21 @@ if (not $group or not $ip) { } $fnret = OVH::Bastion::Plugin::ACL::check( - user => $user, - userAny => $userAny, - port => $port, - portAny => $portAny, - scpUp => $scpUp, - scpDown => $scpDown, - sftp => $sftp + 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::is_valid_group_and_existing(group => $group, groupType => "key"); $fnret or osh_exit($fnret); @@ -127,7 +141,6 @@ if (not $force) { forcePassword => $forcePassword ); if ($fnret->is_ok and $fnret->err ne 'OK') { - # we have something to say, say it osh_info $fnret->msg; } diff --git a/bin/plugin/group-aclkeeper/groupDelServer b/bin/plugin/group-aclkeeper/groupDelServer index e54161e6a..f1be07ef7 100755 --- a/bin/plugin/group-aclkeeper/groupDelServer +++ b/bin/plugin/group-aclkeeper/groupDelServer @@ -14,31 +14,37 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( header => "removing a server from a group", userAllowWildcards => 1, options => { - "group=s" => \my $group, + "group=s" => \my $group, + "protocol=s" => \my $protocol, + "force" => \my $force, + # undocumented/compatibility: "user-any" => \my $userAny, "port-any" => \my $portAny, "scpup" => \my $scpUp, "scpdown" => \my $scpDown, "sftp" => \my $sftp, - "force" => \my $force, }, helptext => <<'EOF', Remove an IP or IP block from a group's server list -Usage: --osh SCRIPT_NAME --group GROUP --host HOST [OPTIONS] +Usage: --osh SCRIPT_NAME --group GROUP --host HOST --user USER --port PORT [OPTIONS] --group GROUP Specify which group this machine should be removed 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) + 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) + --protocol PROTO 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`` @@ -60,19 +66,21 @@ if (not $group or not $ip) { } $fnret = OVH::Bastion::Plugin::ACL::check( - user => $user, - userAny => $userAny, - port => $port, - portAny => $portAny, - scpUp => $scpUp, - scpDown => $scpDown, - sftp => $sftp + 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::is_valid_group_and_existing(group => $group, groupType => "key"); $fnret or osh_exit($fnret); diff --git a/bin/plugin/group-gatekeeper/groupAddGuestAccess b/bin/plugin/group-gatekeeper/groupAddGuestAccess index 12e1e38cf..87ea34a07 100755 --- a/bin/plugin/group-gatekeeper/groupAddGuestAccess +++ b/bin/plugin/group-gatekeeper/groupAddGuestAccess @@ -22,6 +22,7 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( "scpup" => \my $scpUp, "scpdown" => \my $scpDown, "sftp" => \my $sftp, + "rsync" => \my $rsync, "ttl=s" => \my $ttl, "comment=s" => \my $comment, }, @@ -44,6 +45,7 @@ Usage: --osh SCRIPT_NAME --group GROUP --account ACCOUNT [OPTIONS] --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. If omitted, we'll use the closest preexisting group access' comment as seen in groupListServers @@ -76,7 +78,8 @@ $fnret = OVH::Bastion::Plugin::ACL::check( portAny => $portAny, scpUp => $scpUp, scpDown => $scpDown, - sftp => $sftp + sftp => $sftp, + rsync => $rsync, ); if (!$fnret) { help(); diff --git a/bin/plugin/group-gatekeeper/groupDelGuestAccess b/bin/plugin/group-gatekeeper/groupDelGuestAccess index dbaef8155..2b85da5d0 100755 --- a/bin/plugin/group-gatekeeper/groupDelGuestAccess +++ b/bin/plugin/group-gatekeeper/groupDelGuestAccess @@ -22,6 +22,7 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( "scpup" => \my $scpUp, "scpdown" => \my $scpDown, "sftp" => \my $sftp, + "rsync" => \my $rsync, }, helptext => <<'EOF', Remove a specific group server access from an account @@ -41,6 +42,7 @@ Usage: --osh SCRIPT_NAME --group GROUP --account ACCOUNT [OPTIONS] --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 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`` @@ -69,7 +71,8 @@ $fnret = OVH::Bastion::Plugin::ACL::check( portAny => $portAny, scpUp => $scpUp, scpDown => $scpDown, - sftp => $sftp + sftp => $sftp, + rsync => $rsync, ); if (!$fnret) { help(); diff --git a/bin/plugin/restricted/accountAddPersonalAccess b/bin/plugin/restricted/accountAddPersonalAccess index dbb9acfc2..f08a17dcb 100755 --- a/bin/plugin/restricted/accountAddPersonalAccess +++ b/bin/plugin/restricted/accountAddPersonalAccess @@ -16,34 +16,41 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( userAllowWildcards => 1, options => { "account=s" => \my $account, - "user-any" => \my $userAny, - "port-any" => \my $portAny, - "scpup" => \my $scpUp, - "scpdown" => \my $scpDown, - "sftp" => \my $sftp, + "protocol=s" => \my $protocol, "force-key=s" => \my $forceKey, "force-password=s" => \my $forcePassword, "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 an account -Usage: --osh SCRIPT_NAME --account ACCOUNT --host HOST [OPTIONS] +Usage: --osh SCRIPT_NAME --account ACCOUNT --host HOST --user USER --port PORT [OPTIONS] --account Bastion account to add the access to --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) - --force-key FINGERPRINT Only use the key with the specified fingerprint to connect to the server (cf selfListEgressKeys) + 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 + --force-key FINGERPRINT Only use the key with the specified fingerprint to connect to the server (cf accountListEgressKeys) --force-password HASH Only use the password with the specified hash to connect to the server (cf accountListPasswords) --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. @@ -88,19 +95,21 @@ if (!$ip) { } $fnret = OVH::Bastion::Plugin::ACL::check( - user => $user, - userAny => $userAny, - port => $port, - portAny => $portAny, - scpUp => $scpUp, - scpDown => $scpDown, - sftp => $sftp + 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); @@ -108,6 +117,10 @@ if (defined $ttl) { $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 (not $account) { help(); osh_exit 'ERR_MISSING_PARAMETER', "Missing mandatory parameter 'account'"; @@ -129,9 +142,9 @@ if ($forcePassword) { $forcePassword = $fnret->value->{'hash'}; } -if ($forceKey && $forcePassword) { - osh_exit 'ERR_INCOMPATIBLE_PARAMETERS', "Can't use --force-key and --force-password at the same time"; -} +# +# Now do it +# # check plugin config if ($pluginConfig && $pluginConfig->{'self_remote_user_only'}) { diff --git a/bin/plugin/restricted/accountDelPersonalAccess b/bin/plugin/restricted/accountDelPersonalAccess index 25316a865..b7b8aa4bf 100755 --- a/bin/plugin/restricted/accountDelPersonalAccess +++ b/bin/plugin/restricted/accountDelPersonalAccess @@ -14,30 +14,36 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( header => "removing personal access to a server from an account", userAllowWildcards => 1, options => { - "account=s" => \my $account, - "user-any" => \my $userAny, - "port-any" => \my $portAny, - "scpup" => \my $scpUp, - "scpdown" => \my $scpDown, - "sftp" => \my $sftp, + "account=s" => \my $account, + "protocol=s" => \my $protocol, + # undocumented/compatibility: + "user-any" => \my $userAny, + "port-any" => \my $portAny, + "scpup" => \my $scpUp, + "scpdown" => \my $scpDown, + "sftp" => \my $sftp, }, helptext => <<'EOF', Remove a personal server access from an account -Usage: --osh SCRIPT_NAME --account ACCOUNT --host HOST [OPTIONS] +Usage: --osh SCRIPT_NAME --account ACCOUNT --host HOST --user USER --port PORT [OPTIONS] --account Bastion account to remove access 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) + 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) + --protocol PROTO 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 EOF ); @@ -49,19 +55,21 @@ if (!$ip) { } $fnret = OVH::Bastion::Plugin::ACL::check( - user => $user, - userAny => $userAny, - port => $port, - portAny => $portAny, - scpUp => $scpUp, - scpDown => $scpDown, - sftp => $sftp + 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 (not $account) { help(); diff --git a/bin/plugin/restricted/selfAddPersonalAccess b/bin/plugin/restricted/selfAddPersonalAccess index 4af46c3ec..89babdab4 100755 --- a/bin/plugin/restricted/selfAddPersonalAccess +++ b/bin/plugin/restricted/selfAddPersonalAccess @@ -15,33 +15,40 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( header => "adding personal access to a server on your account", userAllowWildcards => 1, options => { - "user-any" => \my $userAny, - "port-any" => \my $portAny, - "scpup" => \my $scpUp, - "scpdown" => \my $scpDown, - "sftp" => \my $sftp, + "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 [OPTIONS] +Usage: --osh SCRIPT_NAME --host HOST --user USER --port PORT [OPTIONS] --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) + 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 --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) @@ -84,19 +91,21 @@ if (!$ip) { } $fnret = OVH::Bastion::Plugin::ACL::check( - user => $user, - userAny => $userAny, - port => $port, - portAny => $portAny, - scpUp => $scpUp, - scpDown => $scpDown, - sftp => $sftp + 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); @@ -104,6 +113,10 @@ if (defined $ttl) { $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; @@ -116,9 +129,9 @@ if ($forcePassword) { $forcePassword = $fnret->value->{'hash'}; } -if ($forceKey && $forcePassword) { - osh_exit 'ERR_INCOMPATIBLE_PARAMETERS', "Can't use --force-key and --force-password at the same time"; -} +# +# Now do it +# # check plugin config if ($pluginConfig && $pluginConfig->{'self_remote_user_only'}) { diff --git a/bin/plugin/restricted/selfDelPersonalAccess b/bin/plugin/restricted/selfDelPersonalAccess index f49cf5a1e..42699cab8 100755 --- a/bin/plugin/restricted/selfDelPersonalAccess +++ b/bin/plugin/restricted/selfDelPersonalAccess @@ -14,6 +14,8 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( header => "removing personal access to a server from an account", userAllowWildcards => 1, options => { + "protocol=s" => \my $protocol, + # undocumented/compatibility: "user-any" => \my $userAny, "port-any" => \my $portAny, "scpup" => \my $scpUp, @@ -23,19 +25,23 @@ my $remainingOptions = OVH::Bastion::Plugin::begin( helptext => <<'EOF', Remove a personal server access from your account -Usage: --osh SCRIPT_NAME --host HOST [OPTIONS] +Usage: --osh SCRIPT_NAME --host HOST --user USER --port PORT [OPTIONS] --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) + 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) + --protocol PROTO 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 EOF ); @@ -47,19 +53,21 @@ if (!$ip) { } $fnret = OVH::Bastion::Plugin::ACL::check( - user => $user, - userAny => $userAny, - port => $port, - portAny => $portAny, - scpUp => $scpUp, - scpDown => $scpDown, - sftp => $sftp + 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'}; my @command = qw{ sudo -n -u allowkeeper -- /usr/bin/env perl -T }; push @command, $OVH::Bastion::BASEPATH . '/bin/helper/osh-accountModifyPersonalAccess'; diff --git a/doc/sphinx/plugins/group-aclkeeper/groupAddServer.rst b/doc/sphinx/plugins/group-aclkeeper/groupAddServer.rst index 3ddbbcb89..b26080659 100644 --- a/doc/sphinx/plugins/group-aclkeeper/groupAddServer.rst +++ b/doc/sphinx/plugins/group-aclkeeper/groupAddServer.rst @@ -53,6 +53,10 @@ Add an IP or IP block to a group's servers list Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --rsync + + Allow usage of rsync through the bastion + .. option:: --force Don't try the ssh connection, just add the host to the group blindly diff --git a/doc/sphinx/plugins/group-aclkeeper/groupDelServer.rst b/doc/sphinx/plugins/group-aclkeeper/groupDelServer.rst index b1bf0a42c..f3a15309e 100644 --- a/doc/sphinx/plugins/group-aclkeeper/groupDelServer.rst +++ b/doc/sphinx/plugins/group-aclkeeper/groupDelServer.rst @@ -53,6 +53,10 @@ Remove an IP or IP block from a group's server list Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --rsync + + Remove 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`` diff --git a/doc/sphinx/plugins/group-gatekeeper/groupAddGuestAccess.rst b/doc/sphinx/plugins/group-gatekeeper/groupAddGuestAccess.rst index c7e5d898d..bcd87b816 100644 --- a/doc/sphinx/plugins/group-gatekeeper/groupAddGuestAccess.rst +++ b/doc/sphinx/plugins/group-gatekeeper/groupAddGuestAccess.rst @@ -58,6 +58,10 @@ Add a specific group server access to an account Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --rsync + + Allow usage of rsync through the bastion + .. option:: --ttl SECONDS|DURATION specify a number of seconds after which the access will automatically expire diff --git a/doc/sphinx/plugins/group-gatekeeper/groupDelGuestAccess.rst b/doc/sphinx/plugins/group-gatekeeper/groupDelGuestAccess.rst index e2a414baf..27c6c967b 100644 --- a/doc/sphinx/plugins/group-gatekeeper/groupDelGuestAccess.rst +++ b/doc/sphinx/plugins/group-gatekeeper/groupDelGuestAccess.rst @@ -57,6 +57,10 @@ Remove a specific group server access from an account Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --rsync + + Remove 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`` diff --git a/doc/sphinx/plugins/restricted/accountAddPersonalAccess.rst b/doc/sphinx/plugins/restricted/accountAddPersonalAccess.rst index 5bfaf4069..fe285dacc 100644 --- a/doc/sphinx/plugins/restricted/accountAddPersonalAccess.rst +++ b/doc/sphinx/plugins/restricted/accountAddPersonalAccess.rst @@ -53,6 +53,10 @@ Add a personal server access to an account Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --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) diff --git a/doc/sphinx/plugins/restricted/accountDelPersonalAccess.rst b/doc/sphinx/plugins/restricted/accountDelPersonalAccess.rst index 34da98c6b..9d352ff20 100644 --- a/doc/sphinx/plugins/restricted/accountDelPersonalAccess.rst +++ b/doc/sphinx/plugins/restricted/accountDelPersonalAccess.rst @@ -53,3 +53,7 @@ Remove a personal server access from an account Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --rsync + + Remove usage of rsync through the bastion + diff --git a/doc/sphinx/plugins/restricted/selfAddPersonalAccess.rst b/doc/sphinx/plugins/restricted/selfAddPersonalAccess.rst index 94909fd12..433872b23 100644 --- a/doc/sphinx/plugins/restricted/selfAddPersonalAccess.rst +++ b/doc/sphinx/plugins/restricted/selfAddPersonalAccess.rst @@ -49,6 +49,10 @@ Add a personal server access to your account Allow usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --rsync + + Allow usage of rsync through the bastion + .. option:: --force Add the access without checking that the public SSH key is properly installed remotely diff --git a/doc/sphinx/plugins/restricted/selfDelPersonalAccess.rst b/doc/sphinx/plugins/restricted/selfDelPersonalAccess.rst index c990d3a79..2a0581f25 100644 --- a/doc/sphinx/plugins/restricted/selfDelPersonalAccess.rst +++ b/doc/sphinx/plugins/restricted/selfDelPersonalAccess.rst @@ -49,3 +49,7 @@ Remove a personal server access from your account Remove usage of the SFTP subsystem, you<--bastion-->server (omit --user in this case) +.. option:: --rsync + + Remove usage of rsync through the bastion + diff --git a/lib/perl/OVH/Bastion/Plugin/ACL.pm b/lib/perl/OVH/Bastion/Plugin/ACL.pm index b94c87fba..eda63f295 100644 --- a/lib/perl/OVH/Bastion/Plugin/ACL.pm +++ b/lib/perl/OVH/Bastion/Plugin/ACL.pm @@ -9,8 +9,8 @@ use OVH::Bastion; sub check { my %params = @_; - my ($port, $portAny, $user, $userAny, $scpUp, $scpDown, $sftp) = - @params{qw{ port portAny user userAny scpUp scpDown sftp }}; + my ($port, $portAny, $user, $userAny, $scpUp, $scpDown, $sftp, $protocol) = + @params{qw{ port portAny user userAny scpUp scpDown sftp protocol }}; if ($user and $userAny) { return R('ERR_INCOMPATIBLE_PARAMETERS', @@ -18,6 +18,19 @@ sub check { . "both are contradictory, please check your command"); } + # legacy option mapping + $user = '*' if $userAny; + + if ($protocol) { + 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 }) { + return R('ERR_INVALID_PARAMETER', + msg => "The protocol '$protocol' is not supported, expected either scpup, scpdown, sftp or rsync"); + } + } + if ($scpUp and $scpDown) { return R('ERR_INCOMPATIBLE_PARAMETERS', msg => "You specified both --scpup and --scpdown, " @@ -26,23 +39,32 @@ sub check { if ($sftp and ($scpUp or $scpDown)) { return R('ERR_INCOMPATIBLE_PARAMETERS', - msg => "You specified both --scp* and --sftp, " - . "if you want to grant both protocols, please do it in two separate commands"); + msg => "You can specify only one of --sftp --scpup --scpdown at a time, " + . "if you want to grant several of those protocols, please do it in separate commands"); + } + + # legacy options mapping + if (!$protocol) { + $protocol = 'sftp' if $sftp; + $protocol = 'scpupload' if $scpUp; + $protocol = 'scpdownload' if $scpDown; } - if (($scpUp or $scpDown or $sftp) and ($user or $userAny)) { + if ($protocol and $user) { return R('ERR_INCOMPATIBLE_PARAMETERS', - msg => "To grant SCP or SFTP access, first ensure SSH access " - . "is granted to the machine (with the --user you need, or --user-any), then grant with --scpup and/or " - . "--scpdown and/or --sftp, omitting --user/--user-any"); + msg => "To grant access using the $protocol protocol, first ensure SSH access " + . "is granted to the machine (with the --user you need), then grant with --protocol, " + . "omitting --user"); } - $user = '!scpupload' if $scpUp; - $user = '!scpdownload' if $scpDown; - $user = '!sftp' if $sftp; + + # special user when a protocol is specified + $user = "!$protocol" if $protocol; if (not $user and not $userAny) { return R('ERR_MISSING_PARAMETER', - msg => "No user specified, if you want to add this server with any user, use --user-any"); + msg => + "No user specified, if you want to add this server with any user, use --user * (you might need to escape it from your shell)" + ); } if ($portAny and $port) { @@ -51,12 +73,21 @@ sub check { . "along with --port-any, both are contradictory, please check your command"); } - if (not $port and not $portAny) { + # legacy option mapping + $port = '*' if $portAny; + + if (not defined $port) { return R('ERR_MISSING_PARAMETER', - msg => "No port specified, if you want to add this server with any port, use --port-any"); + msg => + "No port specified, if you want to add this server with any port, use --port * (you might need to escape it from your shell)" + ); } - return R('OK', value => {user => $user}); + # now, remap port and user '*' back to undef + undef $user if $user eq '*'; + undef $port if $port eq '*'; + + return R('OK', value => {user => $user, port => $port, protocol => $protocol}); } 1; diff --git a/lib/perl/OVH/Bastion/Plugin/otherProtocol.pm b/lib/perl/OVH/Bastion/Plugin/otherProtocol.pm index 5d080ff9e..267c71755 100644 --- a/lib/perl/OVH/Bastion/Plugin/otherProtocol.pm +++ b/lib/perl/OVH/Bastion/Plugin/otherProtocol.pm @@ -23,7 +23,7 @@ sub has_protocol_access { my $protocol = $params{'protocol'}; if (!$account || !$ipfrom || !$ip || !$protocol || !$user || !$port) { - return R('ERR_MSSING_PARAMETERS', msg => "Missing mandatory parameters for has_protocol_access"); + return R('ERR_MISSING_PARAMETERS', msg => "Missing mandatory parameters for has_protocol_access"); } my $machine = "$user\@$ip:$port"; @@ -52,7 +52,7 @@ sub has_protocol_access { } } - osh_debug("Checking access 2/2 of !rsync to $user of $machine..."); + osh_debug("Checking access 2/2 of !$protocol to $user of $machine..."); $fnret = OVH::Bastion::is_access_granted( account => $account, user => "!$protocol", diff --git a/lib/perl/OVH/Bastion/allowdeny.inc b/lib/perl/OVH/Bastion/allowdeny.inc index 11f7dbdc4..8fc7f7adb 100644 --- a/lib/perl/OVH/Bastion/allowdeny.inc +++ b/lib/perl/OVH/Bastion/allowdeny.inc @@ -92,6 +92,10 @@ sub is_access_way_granted { $exactIpMatch = $exactPortMatch = $exactUserMatch = 1 if $exactMatch; + # normalize '*' to undef + undef $wantedUser if (defined $wantedUser && $wantedUser eq '*'); + undef $wantedPort if (defined $wantedPort && $wantedPort eq '*'); + # 'group', 'account', and 'way' parameters are only useful to, and checked by, get_acl_way() $fnret = OVH::Bastion::get_acl_way(way => $way, account => $account, group => $group); $fnret or return $fnret; @@ -109,6 +113,10 @@ sub is_access_way_granted { my $localForceKey = $entry->{'forceKey'}; my $localForcePassword = $entry->{'forcePassword'}; + # normalize '*' to undef + undef $allowedUser if (defined $allowedUser && $allowedUser eq '*'); + undef $allowedPort if (defined $allowedPort && $allowedPort eq '*'); + osh_debug("checking wanted " . (defined $wantedUser ? $wantedUser : '') . '@' . (defined $wantedIp ? $wantedIp : '') . ':' @@ -951,7 +959,7 @@ sub ssh_test_access_way { $user = $fnret->value; # skip special users and wildcarded-users which are not actual remote users - if ((grep { $user eq $_ } qw{ !scpupload !scpdownload !sftp }) || ($user =~ /[*?]/)) { + if ($user =~ /[*?]|^!/) { return R('OK_MAGIC_USER', msg => "Didn't really test the connection, as the specified user is special"); } diff --git a/lib/perl/OVH/Bastion/allowkeeper.inc b/lib/perl/OVH/Bastion/allowkeeper.inc index b4e0a2820..db4d43718 100644 --- a/lib/perl/OVH/Bastion/allowkeeper.inc +++ b/lib/perl/OVH/Bastion/allowkeeper.inc @@ -301,9 +301,9 @@ sub access_modify { my $action = $params{'action'}; # add or del - my $user = $params{'user'}; # if undef, means a user-wildcard access + my $user = $params{'user'}; # can be undef or '*' for a user-wildcard access my $ip = $params{'ip'}; # can be a single ip or prefix - my $port = $params{'port'}; # if undef, means a port-wildcard access + my $port = $params{'port'}; # can be undef or '*' for a port-wildcard access my $ttl = $params{'ttl'}; my $comment = $params{'comment'}; @@ -341,14 +341,10 @@ sub access_modify { # if undef, default to sudo==1 $sudo //= 1; - # due to how plugins work, sometimes user and port are just '', make them undef in those cases - undef $user if (defined $user && $user eq ''); - undef $port if (defined $port && $port eq ''); - - # allow wildcards, but standardize full wildcard to user=undef - if ($user && $user =~ m{^\*+$}) { - undef $user; - } + # normalize * into undef + # also, due to how plugins work, sometimes user and port are just '', make them undef in those cases + undef $user if (defined $user && ($user eq '*' || $user eq '')); + undef $port if (defined $port && ($port eq '*' || $port eq '')); # check way if ($way eq 'personal') {