Skip to content

Instantly share code, notes, and snippets.

@al3xtjames
Last active April 20, 2025 07:31
Show Gist options
  • Save al3xtjames/ddecb984b8c8954dd9a112a697e756e3 to your computer and use it in GitHub Desktop.
Save al3xtjames/ddecb984b8c8954dd9a112a697e756e3 to your computer and use it in GitHub Desktop.
macOS firewall module for nix-darwin
{
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
'';
};
};
}
{ 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