Last active
April 20, 2025 07:31
-
-
Save al3xtjames/ddecb984b8c8954dd9a112a697e756e3 to your computer and use it in GitHub Desktop.
macOS firewall module for nix-darwin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
security.firewall = { | |
enable = true; | |
pf = { | |
enable = true; | |
rules = '' | |
# `set skip on lo0` doesn't appear to work on macOS. | |
pass quick on lo0 no state | |
# Only allow SSH access via Tailscale. | |
# It is tempting to use the interface name for the destination address, | |
# but unfortunately this will fail during boot as the tunnel isn't up. | |
block return in proto tcp from any to any port ssh | |
pass in on utun4 proto tcp from any to 100.100.100.100 port ssh | |
''; | |
}; | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ config, lib, pkgs, ... }: | |
let | |
cfg = config.security.firewall; | |
in { | |
options = { | |
security.firewall = { | |
enable = lib.mkOption { | |
type = lib.types.nullOr lib.types.bool; | |
default = null; | |
description = '' | |
Whether to enable Apple's built-in application firewall. | |
The default is null which lets macOS manage the firewall. | |
''; | |
}; | |
stealthmode = lib.mkOption { | |
type = lib.types.bool; | |
default = false; | |
description = '' | |
Whether to enable stealth mode. | |
''; | |
}; | |
pf = { | |
enable = lib.mkEnableOption "packet filtering with pf"; | |
rules = lib.mkOption { | |
default = ""; | |
type = lib.types.lines; | |
description = '' | |
Packet filtering rules for {manpage}`pf(4)`. | |
See {manpage}`pf.conf(5)` for documentation. | |
''; | |
}; | |
}; | |
}; | |
}; | |
config = let | |
boolToStr = b: if b then "on" else "off"; | |
anchor = pkgs.writeText "nix" ('' | |
# | |
# pf rules managed by nix-darwin | |
# | |
'' + cfg.pf.rules); | |
in { | |
system.activationScripts.networking.text = lib.mkMerge [ | |
(lib.mkIf (cfg.enable != null) '' | |
/usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate ${boolToStr cfg.enable} | |
/usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode ${boolToStr cfg.stealthmode} | |
'') | |
(lib.mkIf (!cfg.pf.enable) '' | |
pfctl -a com.apple/nix -F all &> /dev/null | |
# Disable pf unless stealth mode is enabled (this is the default behavior in macOS). | |
if [ "$(/usr/libexec/ApplicationFirewall/socketfilterfw --getstealthmode)" == "Firewall stealth mode is off" ]; then | |
pfctl -d &> /dev/null | |
fi | |
'') | |
]; | |
launchd.daemons.pf-loader = lib.mkIf cfg.pf.enable { | |
serviceConfig = { | |
ProgramArguments = [ | |
"/bin/sh" "-c" | |
"/bin/wait4path /nix/store && /sbin/pfctl -e -a com.apple/nix -f ${anchor}" | |
]; | |
RunAtLoad = true; | |
}; | |
}; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment