Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NixOS Firewall should automatically allow ports for enabled services. #19504

Closed
nixy opened this issue Oct 13, 2016 · 16 comments
Closed

NixOS Firewall should automatically allow ports for enabled services. #19504

nixy opened this issue Oct 13, 2016 · 16 comments

Comments

@nixy
Copy link
Contributor

nixy commented Oct 13, 2016

Currently the NixOS firewall will block all ports by default, except for port 22 if openssh is enabled. Why does this special behavior apply only to ssh? It would be very nice if we could create an option for the firewall that would allow services to automatically allow traffic to their specified ports.

This will smooth out a pretty big pain point, because while blocking all traffic by default is good security practice it can be really disorienting for users. NixOS declarative nature means we know which services are enabled and on which ports they should be listening. This means the firewall can automatically listen only on ports with configured services.

This would require all services that listen on ports to support this, but I think it would be a phenomenal idea that would make it way easier for people to get started with NixOS.

@rnhmjoj
Copy link
Contributor

rnhmjoj commented Oct 13, 2016

It's not a special behavior, it's up to the service to configure the firewall. The options already exists: adding the listen port to networking.firewall.allowed{UDP,TCP}Ports will do. It just that not so many services are doing this.

@ghost
Copy link

ghost commented Oct 13, 2016

Currently the NixOS firewall will block all ports by default,

That is the behaviour I expect.

except for port 22 if openssh is enabled.

I put port 22 explicitly into my firewall config. IMHO no service
should enable this itself so I don't really like this.

Why does this special behavior apply only to ssh? It would be very
nice if we could create an option for the firewall that would allow
services to automatically allow traffic to their specified ports.

This will smooth out a pretty big pain point, because while blocking all traffic
by default is good security practice it can be really disorienting for users.
NixOS declarative nature means we know which services are enabled and on which
ports they should be listening. This means the firewall can automatically listen
only on ports with configured services.

This would require all services that listen on ports to support this, but I think
it would be a phenomenal idea that would make it way easier for people to get
started with NixOS.

You could as well get the same effect by turning the firewall off.

@nixy
Copy link
Contributor Author

nixy commented Oct 13, 2016

While it is true that services can be configured to enable their ports, as @tohl mentions not all users want this.

Adding an option to the NixOS firewall that would say "Yes I want services to enable their ports" would allow services to conveniently enable their ports, while giving users the freedom to disable that option and manage all their ports manually.

Right now there are no options specifying whether services should be allowed to configure the firewall. This means that if they are doing it, like openssh, they aren't giving users the flexibility of choice. It also means that most services won't be written to enable their ports as the only way to do so is without the users explicit consent.

I believe adding an option to the firewall module that services could then respect would be an ideal solution as it would allow more flexibility then we currently have.

@FRidh
Copy link
Member

FRidh commented Oct 13, 2016

In #12957 it was discussed whether the firewall should be enabled by default or not. The PR proposed changing the default value, and some also discussed whether modules should be allowed to open ports or not. Because it isn't obvious from the generated configuration.nix that the firewall is active it was discussed that at least the default value should be put in the generated configuration to that it is obvious.

How about we do the following:

  1. add the default value for the firewall to /nixos-generate-config.pl as proposed also in Disable networking.firewall by default #12957. This will make it easier for users to find out why certain services are unreachable.
  2. improve the firewall configuration to more easily open ports of services. We can discuss that implementation in another issue.

@edolstra
Copy link
Member

This has been discussed in the past, but the consensus was that services shouldn't open ports in the firewall automatically because this should be an admin decision. For example, just because I have Apache httpd running, doesn't mean I want to open it to the outside world (I'm just running it for testing). Even (say) a DHCP server may not be outward facing - I could use it to provide DHCP to local containers. SSH was an exception for historical reasons (we didn't want to risk locking people out of their machines by blocking port 22), IIRC.

However, we could add some convenience options like services.httpd.openInFirewall (not a global option to open all enabled services in the firewall please...).

@domenkozar
Copy link
Member

And most importantly, document the convention so it can be linked if such questions come up again.

@primeos
Copy link
Member

primeos commented Jan 7, 2017

Documentation:

And most importantly, document the convention so it can be linked if such questions come up again.

It is actually documented by now - nixpkgs-manual: 12.4. New modules:

  • Ensure that the module respect other modules functionality.
    • For example, enabling a module should not open firewall ports by default.

OpenSSH exception:

This has been discussed in the past, but the consensus was that services shouldn't open ports in the firewall automatically because this should be an admin decision.

+1

And I would also suggest removing that functionality from the openssh module (for the next release). Especially since this can cause unexpected problems, e.g. by using the following option:

services.openssh.listenAddresses = [ {
  addr = "192.168.1.1";
  port = 123;
} ];

Now OpenSSH will be listening on port 123 but since services.openssh.ports is still set to [ 22 ] the firewall will be accepting new TCP connections to port 22 but not to port 123.

SSH was an exception for historical reasons (we didn't want to risk locking people out of their machines by blocking port 22), IIRC.

This is indeed a big problem (they should be able to fix this by booting to an older configuration via GRUB tho).

But we could probably find a way to create a smooth transition, e.g. by:

  1. Including that in the release notes (+ email, website (download section), etc.)
  2. Print a warning if OpenSSH is enabled (and the port isn't in allowedTCPPorts)

Or we should at least add an option like openInFirewall and probably change that default to false after printing a warning for a while (imho).

@fpletz fpletz added this to the 17.03 milestone Jan 8, 2017
@Mic92
Copy link
Member

Mic92 commented Jan 8, 2017

I would define services instead of plain ports:
A service specifies what ip:port combinations it uses and there is a way to allow a such services in the firewall. This way we no longer need to add an option to each service to open the firewall. And we can detect collisions between services. if multiple services for example try to bind 0.0.0.0:123 (ntp - #21160 (comment)).

Example (naming/arguments could be improved, I just want to show who holds the information)

# ./nixos/modules/services/mail/postfix.nix
service.postfix.ports.smtp = mkPort {
  port = 25;
  protocol = "tcp";
};

service.postfix.ports.submission = mkPort {
  port = 587;
  protocol = "tcp";
};
# configuration.nix
# allow everything
networking.firewall.allowPorts = [ service.postfix.ports ];
# or  just allow smtp
networking.firewall.allowPorts = [ service.postfix.ports.smtp ];
# ./nixos/modules/services/web-servers/caddy.nix
service.caddy.ports.http-alt = mkPort {
    port = 8080;
    address = "127.0.0.1";
    protocol = "tcp";
};
# configuration.nix
# port forwarding (also useful for containers/other hosts)
networking.firewall.nat = [{
  from = mkPort {
    port = 80;
    protocol = "tcp";
  };
  to = service.caddy.ports.http-alt;
}];
# ./nixos/modules/services/networking/bird.nix
# other protocols then tcp/udp - technically this is no longer a port. That's way I would suggest to use the term service instead of port. 
service.postfix.ports.ospf = mkPort {
    protocol = "ospf";
};

This approach also allows to open ports just for specific source/destination ips (Firewall zones) and the information can be also used for other firewall implementations (ufw, ferm, nftables).

@CMCDragonkai
Copy link
Member

What if enabling services, while not allowing their ports through the firewall raised an info/warning message during the nixos-rebuild. IMO this would make it lot more intuitive.

@jpierre03
Copy link
Contributor

jpierre03 commented May 14, 2017 via email

@CMCDragonkai
Copy link
Member

@jpierre03 Are you disagreeing with making nixos-rebuild notify the user that a service activated doesn't have any open ports (ultimately a ux feature)? Because it seems you're disagreeing with auto-opening ports (a security feature as well).

@jpierre03
Copy link
Contributor

@CMCDragonkai Yes I disagree with auto-opening ports.

@infinisil
Copy link
Member

@Mic92 I have a working prototype of more or less what you described here: https://github.com/Infinisil/nixpkgs/blob/ports/nixos/modules/config/ports.nix

It allows setting

networking.tcpServicePorts = {
  bar = [
    { addr = "192.168.1.1"; port = 80; }
  ];
  foo = [
    { addr = "any"; port = 80; }
    { addr = "127.0.0.1"; port = 8080; }
  ];
}

Which would result in a warning

Port 80 problems:
  has both bindings for any and addresses 192.168.1.1

I originally made this to prevent errors from services starting at the same port, but this could also be extended to support some nice firewall opening mechanism.

@Mic92 Mic92 mentioned this issue Sep 6, 2018
9 tasks
@grahamc
Copy link
Member

grahamc commented Sep 20, 2018

Taking out of 18.09, and I wonder if this ticket should be closed in favor of a ticket specific to the ideas presented later in the issue.

@flokli
Copy link
Contributor

flokli commented Jun 23, 2019

We don't want to automatically open the firewall (but might add convenience options where helpful), see around #19504 (comment).

W.r.t implementing other suggestions from here, please open separate issues :-)

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/overwrite-firewall-settings/9343/9

pacien added a commit to pacien/nixpkgs that referenced this issue Mar 5, 2022
This adds an option `services.taskserver.openFirewall` to allow the user
to choose whether or not the firewall port should be opened for the
service. This is no longer the case by default.

See also NixOS#19504.
@bachp bachp mentioned this issue Nov 6, 2022
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests