From: Thomas Lamprecht <t.lamprecht@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>,
Stefan Hanreich <s.hanreich@proxmox.com>
Cc: Wolfgang Bumiller <w.bumiller@proxmox.com>
Subject: Re: [pve-devel] [PATCH pve-firewall v4 4/9] add support for loading sdn firewall configuration
Date: Sun, 17 Nov 2024 15:57:40 +0100 [thread overview]
Message-ID: <067c607a-d1da-4abb-b699-6e2a26ff68cd@proxmox.com> (raw)
In-Reply-To: <20241115120937.169342-5-s.hanreich@proxmox.com>
Am 15.11.24 um 13:09 schrieb Stefan Hanreich:
> This also includes support for parsing rules referencing IPSets in the
> new SDN scope and generating those IPSets in the firewall.
>
> Loading SDN configuration is optional, since loading it requires root
> privileges which we do not have in all call sites. Adding the flag
> allows us to selectively load the SDN configuration only where
> required and at the same time allows us to only elevate privileges in
> the API where absolutely needed.
>
> Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
> Reviewed-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
> Tested-By: Gabriel Goller <g.goller@proxmox.com>
> Tested-By: Hannes Dürr <h.duerr@proxmox.com>
> ---
> src/PVE/Firewall.pm | 62 +++++++++++++++++++++++++++++----
> src/PVE/Service/pve_firewall.pm | 4 +--
> 2 files changed, 57 insertions(+), 9 deletions(-)
>
> diff --git a/src/PVE/Firewall.pm b/src/PVE/Firewall.pm
> index 09544ba..7642bf6 100644
> --- a/src/PVE/Firewall.pm
> +++ b/src/PVE/Firewall.pm
> @@ -25,6 +25,7 @@ use PVE::Tools qw($IPV4RE $IPV6RE);
> use PVE::Tools qw(run_command lock_file dir_glob_foreach);
>
> use PVE::Firewall::Helpers;
> +use PVE::RS::Firewall::SDN;
>
> my $pvefw_conf_dir = "/etc/pve/firewall";
> my $clusterfw_conf_filename = "$pvefw_conf_dir/cluster.fw";
> @@ -1689,9 +1690,12 @@ sub verify_rule {
>
> if (my $value = $rule->{$name}) {
> if ($value =~ m/^\+/) {
> - if ($value =~ m@^\+(guest/|dc/)?(${ipset_name_pattern})$@) {
> + if ($value =~ m@^\+(guest/|dc/|sdn/)?(${ipset_name_pattern})$@) {
> &$add_error($name, "no such ipset '$2'")
> - if !($cluster_conf->{ipset}->{$2} || ($fw_conf && $fw_conf->{ipset}->{$2}));
> + if !($cluster_conf->{ipset}->{$2}
> + || ($fw_conf && $fw_conf->{ipset}->{$2})
> + || ($cluster_conf->{sdn} && $cluster_conf->{sdn}->{ipset}->{$2})
> + || ($fw_conf->{sdn} && $fw_conf->{sdn}->{ipset}->{$2}));
Avoid multi-line post-ifs:
https://pve.proxmox.com/wiki/Perl_Style_Guide#Wrapping_Post-If
rather use something like
if (
!$cluster_conf->{ipset}->{$2}
&& !($fw_conf && $fw_conf->{ipset}->{$2})
&& !($cluster_conf->{sdn} && $cluster_conf->{sdn}->{ipset}->{$2})
&& !($fw_conf->{sdn} && $fw_conf->{sdn}->{ipset}->{$2}))
) {
$add_error->($name, "no such ipset '$2'")
}
>
> } else {
> &$add_error($name, "invalid ipset name '$value'");
> @@ -2108,13 +2112,15 @@ sub ipt_gen_src_or_dst_match {
>
> my $match;
> if ($adr =~ m/^\+/) {
> - if ($adr =~ m@^\+(guest/|dc/)?(${ipset_name_pattern})$@) {
> + if ($adr =~ m@^\+(guest/|dc/|sdn/)?(${ipset_name_pattern})$@) {
> my $scope = $1 // "";
> my $name = $2;
A small closer could help to reduce bewlow if expressions, e.g. like:
my $is_scope = sub { return !$scope || $scope eq "$_[0]/" };
#...
if ($is_scope->('guest') && $fw_conf && $fw_conf->{ipset}->{$name}) {
#...
> my $ipset_chain;
> - if ($scope ne 'dc/' && $fw_conf && $fw_conf->{ipset}->{$name}) {
> + if ((!$scope || $scope eq 'guest/') && $fw_conf && $fw_conf->{ipset}->{$name}) {
> $ipset_chain = compute_ipset_chain_name($fw_conf->{vmid}, $name, $ipversion);
> - } elsif ($scope ne 'guest/' && $cluster_conf && $cluster_conf->{ipset}->{$name}) {
> + } elsif ((!$scope || $scope eq 'dc/') && $cluster_conf && $cluster_conf->{ipset}->{$name}) {
> + $ipset_chain = compute_ipset_chain_name(0, $name, $ipversion);
> + } elsif ((!$scope || $scope eq 'sdn/') && $cluster_conf->{sdn} && $cluster_conf->{sdn}->{ipset}->{$name}) {
> $ipset_chain = compute_ipset_chain_name(0, $name, $ipversion);
> } else {
> die "no such ipset '$name'\n";
> @@ -3644,7 +3650,8 @@ sub lock_clusterfw_conf {
> }
>
> sub load_clusterfw_conf {
> - my ($filename) = @_;
> + my ($filename, $options) = @_;
> +
>
> $filename = $clusterfw_conf_filename if !defined($filename);
> my $empty_conf = {
> @@ -3655,6 +3662,7 @@ sub load_clusterfw_conf {
> group_comments => {},
> ipset => {} ,
> ipset_comments => {},
> + sdn => load_sdn_conf(),
it's a bit odd to assign the full SDN related config to a variable named
$empty_config, but assigning it after the parser will cause a semantic difference
for the case where the firewall config is empty, not sure if that is fine.
> };
>
> my $cluster_conf = generic_fw_config_parser($filename, $empty_conf, $empty_conf, 'cluster');
> @@ -3663,6 +3671,45 @@ sub load_clusterfw_conf {
> return $cluster_conf;
> }
>
> +sub load_sdn_conf {
> + my $rpcenv = eval { PVE::RPCEnvironment::get(); };
Missing use statement for that module, also the semicolon inside the eval can be dropped.
> +
> + if ($@) {
> + warn "could not load SDN configuration because RPCEnvironment is not initialized.";
> + return {};
> + }
> +
> + my $authuser = $rpcenv->get_user();
> +
> + my $guests = PVE::Cluster::get_vmlist();
> + my $allowed_vms = [];
> + foreach my $vmid (sort keys %{$guests->{ids}}) {
> + next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ], 1);
> + push @$allowed_vms, $vmid;
> + }
Above one could be:
$allowed_vms = [
grep { $rpcenv->check($authuser, "/vms/$_", [ 'VM.Audit' ], 1) } sort keys $guests->{ids}->%*
];
> + my $vnets = PVE::Network::SDN::Vnets::config(1);
> + my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
> + my $allowed_vnets = [];
> + foreach my $vnet (sort keys %{$vnets->{ids}}) {
> + my $zone = $vnets->{ids}->{$vnet}->{zone};
> + next if !$rpcenv->check_any($authuser, "/sdn/zones/$zone/$vnet", $privs, 1);
> + push @$allowed_vnets, $vnet;
> + }
> +
> + my $sdn_config = {
> + ipset => {} ,
> + ipset_comments => {},
> + };
> +
> + eval {
> + $sdn_config = PVE::RS::Firewall::SDN::config($allowed_vnets, $allowed_vms);
> + };
> + warn $@ if $@;
above might be more readable by doing:
my $empty_sdn_config = { ipset => {} , ipset_comments => {} };
my $sdn_config = eval { PVE::RS::Firewall::SDN::config($allowed_vnets, $allowed_vms) };
warn $@ if $@;
return $sdn_config // $empty_sdn_config;
> +
> + return $sdn_config;
> +}
> +
> sub save_clusterfw_conf {
> my ($cluster_conf) = @_;
>
> @@ -3768,7 +3815,7 @@ sub compile {
>
> $vmfw_configs = read_vm_firewall_configs($cluster_conf, $vmdata, $testdir);
> } else { # normal operation
> - $cluster_conf = load_clusterfw_conf(undef) if !$cluster_conf;
> + $cluster_conf = load_clusterfw_conf() if !$cluster_conf;
>
> $hostfw_conf = load_hostfw_conf($cluster_conf, undef) if !$hostfw_conf;
>
> @@ -4043,6 +4090,7 @@ sub compile_ipsets {
> }
>
> generate_ipset_chains($ipset_ruleset, undef, $cluster_conf, undef, $cluster_conf->{ipset});
> + generate_ipset_chains($ipset_ruleset, undef, $cluster_conf, undef, $cluster_conf->{sdn}->{ipset});
>
> return $ipset_ruleset;
> }
> diff --git a/src/PVE/Service/pve_firewall.pm b/src/PVE/Service/pve_firewall.pm
> index 65cb2b8..02b507a 100755
> --- a/src/PVE/Service/pve_firewall.pm
> +++ b/src/PVE/Service/pve_firewall.pm
> @@ -158,7 +158,7 @@ __PACKAGE__->register_method ({
>
> PVE::Firewall::set_verbose(1); # show syntax errors
>
> - my $cluster_conf = PVE::Firewall::load_clusterfw_conf(undef);
> + my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
just to be sure, above and below does not change anything, or?
> $res->{enable} = $cluster_conf->{options}->{enable} ? 1 : 0;
>
> if ($status eq 'running') {
> @@ -202,7 +202,7 @@ __PACKAGE__->register_method ({
>
> PVE::Firewall::set_verbose(1);
>
> - my $cluster_conf = PVE::Firewall::load_clusterfw_conf(undef);
> + my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
> my ($ruleset, $ipset_ruleset, $rulesetv6, $ebtables_ruleset) = PVE::Firewall::compile($cluster_conf, undef, undef);
>
> print "ipset cmdlist:\n";
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2024-11-17 14:57 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-15 12:09 [pve-devel] [PATCH docs/firewall/manager/proxmox{-firewall, -perl-rs} v4 0/9] autogenerate ipsets for sdn objects Stefan Hanreich
2024-11-15 12:09 ` [pve-devel] [PATCH proxmox-firewall v4 1/9] add proxmox-ve-rs crate - move proxmox-ve-config there Stefan Hanreich
2024-11-17 14:08 ` [pve-devel] applied: " Thomas Lamprecht
2024-11-15 12:09 ` [pve-devel] [PATCH proxmox-firewall v4 2/9] config: tests: add support for loading sdn and ipam config Stefan Hanreich
2024-11-17 14:08 ` [pve-devel] applied: " Thomas Lamprecht
2024-11-15 12:09 ` [pve-devel] [PATCH proxmox-firewall v4 3/9] ipsets: autogenerate ipsets for vnets and ipam Stefan Hanreich
2024-11-17 14:08 ` [pve-devel] applied: " Thomas Lamprecht
2024-11-15 12:09 ` [pve-devel] [PATCH pve-firewall v4 4/9] add support for loading sdn firewall configuration Stefan Hanreich
2024-11-17 14:57 ` Thomas Lamprecht [this message]
2024-11-18 9:22 ` Stefan Hanreich
2024-11-18 9:35 ` Stefan Hanreich
2024-11-15 12:09 ` [pve-devel] [PATCH pve-firewall v4 5/9] nftables: make is_nftables check flag file instead of config Stefan Hanreich
2024-11-17 14:58 ` [pve-devel] applied: " Thomas Lamprecht
2024-11-15 12:09 ` [pve-devel] [PATCH pve-firewall v4 6/9] api: load sdn ipsets Stefan Hanreich
2024-11-17 14:30 ` Thomas Lamprecht
2024-11-18 9:02 ` Stefan Hanreich
2024-11-18 11:38 ` Thomas Lamprecht
2024-11-18 13:23 ` Thomas Lamprecht
2024-11-18 13:32 ` Stefan Hanreich
2024-11-15 12:09 ` [pve-devel] [PATCH proxmox-perl-rs v4 7/9] add PVE::RS::Firewall::SDN module Stefan Hanreich
2024-11-17 14:36 ` [pve-devel] applied: " Thomas Lamprecht
2024-11-15 12:09 ` [pve-devel] [PATCH pve-manager v4 8/9] firewall: add sdn scope to IPRefSelector Stefan Hanreich
2024-11-15 12:09 ` [pve-devel] [PATCH pve-docs v4 9/9] sdn: add documentation for firewall integration Stefan Hanreich
2024-11-18 11:47 ` [pve-devel] [PATCH docs/firewall/manager/proxmox{-firewall, -perl-rs} v4 0/9] autogenerate ipsets for sdn objects Stefan Hanreich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=067c607a-d1da-4abb-b699-6e2a26ff68cd@proxmox.com \
--to=t.lamprecht@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
--cc=s.hanreich@proxmox.com \
--cc=w.bumiller@proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox