-
-
Notifications
You must be signed in to change notification settings - Fork 13.9k
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
Finer-grained firewall: allow specific hosts, in particular to SSH #22586
Changes from 1 commit
6c43d68
5da578d
2060825
c55880b
4f203bd
8aeaf75
5677c04
20dc8f1
0872e73
a3133f9
d503e79
27ce317
db8d11e
9215385
77ee320
ce8f425
fdac4be
e036c45
9504ce9
7c6b061
ea14eac
7277ca0
b2d7740
72c75e7
d30cd1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,6 +177,21 @@ let | |
) cfg.allowedUDPPortRanges | ||
} | ||
|
||
# Accept packets on the extra allowed host+port combination. | ||
${concatMapStrings (allowed: | ||
if (allowed.useIPv4 || allowed.usedIPv6) then ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Parentheses around "if" conditions are unnecessary, this isn't C. |
||
(if allowed.useIPv4 then ( | ||
if allowed.useIPv6 then ("ip46tables -A nixos-fw ") else ("iptables -A nixos-fw ") | ||
) else ( | ||
"ip6tables -A nixos-fw " | ||
)) | ||
+ (if (allowed.source != "") then (" --source " + allowed.source) else "") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use ex.:
|
||
+ (if (allowed.protocol != "") then (" -p " + allowed.protocol) else "") | ||
+ (if (allowed.dport != 0) then (" --dport " + toString allowed.dport) else "") | ||
+ " -j nixos-fw-accept\n" | ||
) else "") cfg.extraAllowed | ||
} | ||
|
||
# Accept IPv4 multicast. Not a big security risk since | ||
# probably nobody is listening anyway. | ||
#iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept | ||
|
@@ -493,6 +508,22 @@ in | |
''; | ||
}; | ||
|
||
networking.firewall.extraAllowed = mkOption { | ||
type = types.listOf (types.submodule { options = { | ||
source = mkOption { type = types.string; default = ""; example = "example.com"; description = "Source of the packets"; }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||
protocol = mkOption { type = types.enum ["tcp" "udp" "icmp"]; default = ""; example = "tcp"; description = "Protocol used."; }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does an empty default do? Note that |
||
dport = mkOption { type = types.int; default = 0; example = 22; description = "Destination port of the packet."; }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find |
||
useIPv4 = mkOption { type = types.bool; default = true; description = "Use the IPv4 address of this host."; }; | ||
useIPv6 = mkOption { type = types.bool; default = true; description = "Use the IPv6 address of this host."; }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does "Use the IPv4/IPv6 address of this host" mean? Do you mean "Accept IPv4/IPv6 traffic from this host"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact it's unclear what "host" means. Should that be "from this source"? Can source be a CIDR prefix? |
||
};}); | ||
default = []; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed that, thanks. |
||
example = [ { source = "example.com"; protocol = "tcp"; dport = 22; } ]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From the
So in order not to give people bad ideas, it would be better to use an IP address in the example. (See https://tools.ietf.org/search/rfc5737) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had not realized that, but this felt wrong indeed. The reason for the Since some hosts don't have an IPv6 yet, or don't have an IPv4 anymore, we need a way to tell whether to call iptables or ip6tables. |
||
description = | ||
'' | ||
Additional exceptions in the firewall. | ||
''; | ||
}; | ||
|
||
}; | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -128,6 +128,16 @@ in | |
''; | ||
}; | ||
|
||
firewallOpenPorts = mkOption { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. => |
||
type = types.bool; | ||
default = true; | ||
description = '' | ||
Specifies whether the ports the SSH daemon listens on must | ||
be enabled in the firewall. Remember to open at least some | ||
of them. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a great change (imho) - related to #19504
I don't think we should immediately use Additional information can be found in the related issue: #19504 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, as far as I'm concerned, I appreciate the fact that nixops doesn't lock me out of my machine on the first run. Even though nixops is a great tool after some time, it is not totally easy to master at first (potentially due to lack of documentation on how it works conceptually). I remember learning both nix and nixops at the same time, it wasn't very "fun" (I'm having a lot of fun using it now, though). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @P-E-Meunier Yeah, that's why changing the default is indeed really problematic... However using Another possible solution would be to use your new option for allowing the (IP, Port) combinations from @edolstra, @Mic92, @wkennington, #19504 - Any opinions on that? We could also start using the "services" solution (#19504 (comment) from @Mic92) which would also greatly improve our current situation (imho) but probably require some additional thinking/discussion. Imho it would also be a good idea to move that option over to the firewall module (e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you be more specific as to why it might be useful to combine In my situation (VPS + nixops), this PR would have enabled me to just logged via a "web console", and type "iptables -F" to re-enable everything, whereas There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We don't necessarily have to combine it with this PR, but Imho it is a good idea to consider this since you made related modifications inside the openssh module (and at least we have to get the description right!).
It doesn't modify the firewall (atm) so you have to do that manually (I thought this is how you've locked yourself out in the first place). By default OpenSSH will listen on port
I assume that RST packet (TCP reset) came from the firewall. Then you should only get those for existing connections (I guess that terminated your running SSH session).
The change is intended to prevent a user from getting into that situation (not to fix a "broken" firewall) 😉 |
||
''; | ||
}; | ||
|
||
listenAddresses = mkOption { | ||
type = with types; listOf (submodule { | ||
options = { | ||
|
@@ -308,7 +318,7 @@ in | |
|
||
}; | ||
|
||
networking.firewall.allowedTCPPorts = cfg.ports; | ||
networking.firewall.allowedTCPPorts = if cfg.firewallOpenPorts then cfg.ports else []; | ||
|
||
security.pam.services.sshd = | ||
{ startSession = true; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
allowed.useIpv6
notallowed.usedIpv6
. If you use an enum for the address family you can drop thisif
clause.