From f461ef84c6b0b819bec2603fa3af408332be4dc4 Mon Sep 17 00:00:00 2001 From: Jamil Date: Wed, 29 Jun 2022 17:21:37 -0700 Subject: [PATCH] Option to disable masquerade (#769) * Option to disable masquerade Fixes #666 * Fix markdown lint issues * Reflow text * Fix markdownlint errors * Clean up conditional --- apps/fz_wall/lib/fz_wall/cli/live.ex | 42 +++++++++++++---- config/config.exs | 2 + config/runtime.exs | 4 ++ docs/docs/reference/configuration-file.md | 2 + .../reference/firewall-templates/index.md | 5 +- .../reference/firewall-templates/nftables.md | 47 +++++++++++-------- .../cookbooks/firezone/attributes/default.rb | 6 +++ .../cookbooks/firezone/libraries/config.rb | 2 + 8 files changed, 79 insertions(+), 31 deletions(-) diff --git a/apps/fz_wall/lib/fz_wall/cli/live.ex b/apps/fz_wall/lib/fz_wall/cli/live.ex index 39857f999..6c0993f29 100644 --- a/apps/fz_wall/lib/fz_wall/cli/live.ex +++ b/apps/fz_wall/lib/fz_wall/cli/live.ex @@ -42,16 +42,40 @@ defmodule FzWall.CLI.Live do "{ type nat hook postrouting priority 100 ; }'" ) - # XXX: Do more testing with this method of creating masquerade rules - for int <- File.ls!("/sys/class/net/") do - # Masquerade all interfaces except loopback and our own wireguard interface - if int not in ["lo", wireguard_interface_name()] do - exec!( - "#{nft()} 'add rule inet #{@table_name} postrouting oifname " <> - "#{int} masquerade persistent'" - ) - end + setup_masquerade() + end + + defp setup_masquerade do + if masquerade_ipv4?() do + setup_masquerade(:ipv4) end + + if masquerade_ipv6?() do + setup_masquerade(:ipv6) + end + end + + defp setup_masquerade(proto) do + File.ls!("/sys/class/net/") + |> Enum.reject(&skip_masquerade_for_interface?/1) + |> Enum.map(fn int -> + exec!( + "#{nft()} 'add rule inet #{@table_name} postrouting oifname " <> + "#{int} meta nfproto #{proto} masquerade persistent'" + ) + end) + end + + defp skip_masquerade_for_interface?(int) do + int in ["lo", wireguard_interface_name()] + end + + defp masquerade_ipv4? do + Application.fetch_env!(:fz_wall, :wireguard_ipv4_masquerade) + end + + defp masquerade_ipv6? do + Application.fetch_env!(:fz_wall, :wireguard_ipv6_masquerade) end def teardown_table do diff --git a/config/config.exs b/config/config.exs index e58a5f584..543993974 100644 --- a/config/config.exs +++ b/config/config.exs @@ -85,6 +85,8 @@ config :fz_http, config :fz_wall, cli: FzWall.CLI.Sandbox, + wireguard_ipv4_masquerade: true, + wireguard_ipv6_masquerade: true, server_process_opts: [name: {:global, :fz_wall_server}], egress_interface: "dummy", wireguard_interface_name: "wg-firezone" diff --git a/config/runtime.exs b/config/runtime.exs index 8178b671f..caf28b61d 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -44,6 +44,8 @@ if config_env() == :prod do wireguard_allowed_ips = System.fetch_env!("WIREGUARD_ALLOWED_IPS") wireguard_persistent_keepalive = System.fetch_env!("WIREGUARD_PERSISTENT_KEEPALIVE") wireguard_ipv4_enabled = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV4_ENABLED")) + wireguard_ipv4_masquerade = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV4_MASQUERADE")) + wireguard_ipv6_masquerade = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV6_MASQUERADE")) wireguard_ipv4_network = System.fetch_env!("WIREGUARD_IPV4_NETWORK") wireguard_ipv4_address = System.fetch_env!("WIREGUARD_IPV4_ADDRESS") wireguard_ipv6_enabled = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV6_ENABLED")) @@ -170,6 +172,8 @@ if config_env() == :prod do ] config :fz_wall, + wireguard_ipv4_masquerade: wireguard_ipv4_masquerade, + wireguard_ipv6_masquerade: wireguard_ipv6_masquerade, nft_path: nft_path, egress_interface: egress_interface, wireguard_interface_name: wireguard_interface_name, diff --git a/docs/docs/reference/configuration-file.md b/docs/docs/reference/configuration-file.md index 44819fe32..52caa0e1a 100644 --- a/docs/docs/reference/configuration-file.md +++ b/docs/docs/reference/configuration-file.md @@ -145,9 +145,11 @@ Shown below is a complete listing of the configuration options available in | `default['firezone']['wireguard']['allowed_ips']` | WireGuard `AllowedIPs` to use for generated device configurations. | `'0.0.0.0/0, ::/0'` | | `default['firezone']['wireguard']['persistent_keepalive']` | Default PersistentKeepalive setting for generated device configurations. A value of 0 disables. | `0` | | `default['firezone']['wireguard']['ipv4']['enabled']` | Enable or disable IPv4 for WireGuard network. | `true` | +| `default['firezone']['wireguard']['ipv4']['masquerade']` | Enable or disable masquerade for packets leaving the IPv4 tunnel. | `true` | | `default['firezone']['wireguard']['ipv4']['network']` | WireGuard network IPv4 address pool. | `'10.3.2.0/24'` | | `default['firezone']['wireguard']['ipv4']['address']` | WireGuard interface IPv4 address. Must be within WireGuard address pool. | `'10.3.2.1'` | | `default['firezone']['wireguard']['ipv6']['enabled']` | Enable or disable IPv6 for WireGuard network. | `true` | +| `default['firezone']['wireguard']['ipv6']['masquerade']` | Enable or disable masquerade for packets leaving the IPv6 tunnel. | `true` | | `default['firezone']['wireguard']['ipv6']['network']` | WireGuard network IPv6 address pool. | `'fd00::3:2:0/120'` | | `default['firezone']['wireguard']['ipv6']['address']` | WireGuard interface IPv6 address. Must be within IPv6 address pool. | `'fd00::3:2:1'` | | `default['firezone']['runit']['svlogd_bin']` | Runit svlogd bin location. | `"#{node['firezone']['install_directory']}/embedded/bin/svlogd"` | diff --git a/docs/docs/reference/firewall-templates/index.md b/docs/docs/reference/firewall-templates/index.md index 5fae5bfc0..4f54c71f3 100644 --- a/docs/docs/reference/firewall-templates/index.md +++ b/docs/docs/reference/firewall-templates/index.md @@ -9,5 +9,6 @@ description: > --- --- -Firewall templates to secure the Firezone server are available from here. If the server -is not running any services other than Firezone, the firewall template should work as-is. +Firewall templates to secure the Firezone server are available from here. If the +server is not running any services other than Firezone, the firewall template +should work as-is. diff --git a/docs/docs/reference/firewall-templates/nftables.md b/docs/docs/reference/firewall-templates/nftables.md index ef4c63e86..8eb21b2fe 100644 --- a/docs/docs/reference/firewall-templates/nftables.md +++ b/docs/docs/reference/firewall-templates/nftables.md @@ -13,10 +13,10 @@ running Firezone. The template does make some assumptions; you may need to adjust the rules to suite your use case: * The WireGuard interface is named `wg-firezone`. If this is not correct, -change the `DEV_WIREGUARD` variable to match the -`default['firezone']['wireguard']['interface_name']` configuration option. + change the `DEV_WIREGUARD` variable to match the + `default['firezone']['wireguard']['interface_name']` configuration option. * The port WireGuard is listening on is `51820`. If you are not using the -default port change the `WIREGUARD_PORT` variable. + default port change the `WIREGUARD_PORT` variable. * Only the following inbound traffic will be allowed to the server: * SSH (TCP dport 22) * HTTP (TCP dport 80) @@ -32,16 +32,18 @@ default port change the `WIREGUARD_PORT` variable. * SMTP submission (TCP dport 587) * UDP traceroute (UDP dport 33434-33524, rate limited to 500/second) * Unmatched traffic will be logged. The rules used for logging are separated -from the rules to drop traffic and are rate limited. Removing the relevant -logging rules will not affect trafic. + from the rules to drop traffic and are rate limited. Removing the relevant + logging rules will not affect trafic. -#### Firezone Managed Rules +## Firezone-managed Rules -Firezone configures its own nftables rules to permit/reject traffic to destinations -configured in the web interface and to handle outbound NAT for client traffic. +Firezone configures its own nftables rules to permit/reject traffic to +destinations configured in the web interface and to handle outbound NAT for +client traffic. -Applying the below firewall template on an already running server (not at boot time) -will result in the Firezone rules being cleared. This may have security implications. +Applying the below firewall template on an already running server (not at boot +time) will result in the Firezone rules being cleared. This may have security +implications. To work around this restart the `phoenix` service: @@ -49,7 +51,9 @@ To work around this restart the `phoenix` service: firezone-ctl restart phoenix ``` -#### Base Firewall Template +## Base Firewall Template + + ```shell #!/usr/sbin/nft -f @@ -321,24 +325,27 @@ table inet nat { } ``` -#### Usage + -The firewall should be stored in the relevant location for the Linux distribution -that is running. For Debian/Ubuntu this is `/etc/nftables.conf` and for RHEL this -is `/etc/sysconfig/nftables.conf`. +## Usage -`nftables.service` will need to be configured to start on boot (if not already) set: +The firewall should be stored in the relevant location for the Linux +distribution that is running. For Debian/Ubuntu this is `/etc/nftables.conf` +and for RHEL this is `/etc/sysconfig/nftables.conf`. + +`nftables.service` will need to be configured to start on boot (if not already) +set: ```shell systemctl enable nftables.service ``` -If making any changes to the firewall template the syntax can be validated by running -the check command: +If making any changes to the firewall template the syntax can be validated by +running the check command: ```shell nft -f /path/to/nftables.conf -c ``` -Be sure to validate the firewall works as expected as certain nftables features may -not be available depending on the release running on the server. +Be sure to validate the firewall works as expected as certain nftables features +may not be available depending on the release running on the server. diff --git a/omnibus/cookbooks/firezone/attributes/default.rb b/omnibus/cookbooks/firezone/attributes/default.rb index eb347107e..534e08ac5 100644 --- a/omnibus/cookbooks/firezone/attributes/default.rb +++ b/omnibus/cookbooks/firezone/attributes/default.rb @@ -352,6 +352,9 @@ default['firezone']['wireguard']['persistent_keepalive'] = 0 # Enable or disable IPv4 connectivity in your WireGuard network. Default enabled. default['firezone']['wireguard']['ipv4']['enabled'] = true +# Enable or disable SNAT/Masquerade for packets leaving the WireGuard ipv4 tunnel. Default true. +default['firezone']['wireguard']['ipv4']['masquerade'] = true + # The CIDR-formatted IPv4 network to use for your WireGuard network. Default 10.3.2.0/24. default['firezone']['wireguard']['ipv4']['network'] = '10.3.2.0/24' @@ -362,6 +365,9 @@ default['firezone']['wireguard']['ipv4']['address'] = '10.3.2.1' # Enable or disable IPv6 connectivity in your WireGuard network. Default enabled. default['firezone']['wireguard']['ipv6']['enabled'] = true +# Enable or disable SNAT/Masquerade for packets leaving the WireGuard ipv6 tunnel. Default true. +default['firezone']['wireguard']['ipv6']['masquerade'] = true + # The CIDR-formatted IPv6 network to use for your WireGuard network. Default fd00::3:2:0/120. default['firezone']['wireguard']['ipv6']['network'] = 'fd00::3:2:0/120' diff --git a/omnibus/cookbooks/firezone/libraries/config.rb b/omnibus/cookbooks/firezone/libraries/config.rb index 9169d1ffe..64f963a78 100644 --- a/omnibus/cookbooks/firezone/libraries/config.rb +++ b/omnibus/cookbooks/firezone/libraries/config.rb @@ -235,8 +235,10 @@ class Firezone 'WIREGUARD_ALLOWED_IPS' => attributes['wireguard']['allowed_ips'].to_s, 'WIREGUARD_PERSISTENT_KEEPALIVE' => attributes['wireguard']['persistent_keepalive'].to_s, 'WIREGUARD_IPV4_ENABLED' => attributes['wireguard']['ipv4']['enabled'].to_s, + 'WIREGUARD_IPV4_MASQUERADE' => attributes['wireguard']['ipv4']['masquerade'].to_s, 'WIREGUARD_IPV4_NETWORK' => attributes['wireguard']['ipv4']['network'], 'WIREGUARD_IPV4_ADDRESS' => attributes['wireguard']['ipv4']['address'], + 'WIREGUARD_IPV6_MASQUERADE' => attributes['wireguard']['ipv6']['masquerade'].to_s, 'WIREGUARD_IPV6_ENABLED' => attributes['wireguard']['ipv6']['enabled'].to_s, 'WIREGUARD_IPV6_NETWORK' => attributes['wireguard']['ipv6']['network'], 'WIREGUARD_IPV6_ADDRESS' => attributes['wireguard']['ipv6']['address'],