はじめに
macOSでは、ネットワークへのアクセスを制御する手法として、BSD系のOSで利用されてきたPF(packet filter)が採用されている。この設定をカスタマイズすることで、アクセス制限が可能になる。
筆者はネットワークに関する知識が乏しく、根本的に間違っている箇所があるかもしれませんので、十分に注意して自己責任で設定してください。macOSのPFに関する日本語の情報があまり多くないので、本稿はその一助とするための記事です。有識者の方はぜひより詳しいことを教えて下さい。
設定を行った環境:macOS Sequoia 15.4
PFの設定ファイルを作成する
PFのデフォルトの設定ファイルは、 /etc/pf.conf
である。しかし、このファイルはOSアップデート時などに上書きされる。そこで、本稿では、 /usr/local/etc/pf.conf
を設定ファイルとする。
まず、PFの設定ファイルなどを置くためのディレクトリを作成する。
$ sudo mkdir -p /usr/local/etc /usr/local/bin
設定ファイルとして、 /usr/local/etc/pf.conf
を以下のように作成する。
pf.conf
の最後の行には、空白行を入れる必要がある?
# IPアドレスによるアクセス制限を行うためのPFの設定ファイル
# !!!! このファイルの最後の行は、空白行にする必要がある? !!!!
# このコンピュータのIPアドレス(適宜変更する)
my_ip = "xxx.xxx.xxx.xxx"
# アクセス可能なIPアドレスリストの例
allowed_ips = "{ yyy.yyy.yyy.yyy, zzz.zzz.zzz.zzz/24 }"
# ループバックは常に許可する(他の設定よりも優先される)
pass quick on lo0 all
# 許可されたIPアドレスから下で設定するポートに対して入力される接続以外のすべてはブロックする
block in all # ブロックされた接続のログも取るには、 block in log all とする
# 既存の接続は維持する(外向きの接続はそのまま通過させる)
pass out all keep state
# 許可されたIPアドレスからのSSH/SFTP(22番ポート)を許可する
pass in log on en0 proto tcp from $allowed_ips to $my_ip port 22 keep state
# 許可されたIPアドレスからのXXXX番ポートに対する通信を許可する
# pass in log on en0 proto tcp from $allowed_ips to $my_ip port XXXX keep state
このファイルの所有者と権限を以下のように設定する。
$ sudo chown root:wheel /usr/local/etc/pf.conf
$ sudo chmod 644 /usr/local/etc/pf.conf
PFの設定を読み込むためのスクリプトを作成する
次に、OS起動時にこの設定でPFを起動するためのシェルスクリプト( /usr/local/bin/load_pf.sh
)を以下のように作成する。
#!/bin/bash
# pflog0インタフェースを作成する
/sbin/ifconfig pflog0 create
# pfの設定を読み込む
/sbin/pfctl -f /usr/local/etc/pf.conf
# pfを有効化する
/sbin/pfctl -e
# pfのログを保存するためのディレクトリを作成する(存在しない場合)
mkdir -p /var/log/pflog
# pfのログを書き出す(/var/log/pflogにpflog_YYYYmmddHHMMの命名形式のバイナリファイルが作成される)
tcpdump -n -e -w /var/log/pflog/pflog_$(date +%Y%m%d%H%M).log -ttt -i pflog0
このスクリプトに実行権限を付与する。
$ sudo chmod +x /usr/local/bin/load_pf.sh
BSD系のOSでは、PFのログは pflog0
というインターフェイスに出力され、これをリッスンしている pflogd
というデーモンがログファイルを生成する。しかし、macOSで pflogd
を使用する方法が不明なので、暫定的に tcpdump
によってログファイルを生成する。
このスクリプトでは、OSが再起動するごとにログファイルが生成され、 tcpdump
のバイナリフォーマットで書き込まれる。このログファイルを読むときには、
$ tcpdump -n -e -ttt -r /var/log/pflog/pflog_*YYYYmmddHHMM*.log
というコマンドを使用する。また、例えば22番ポートに対する通信のみを表示するには、
$ tcpdump -n -e -ttt -r /var/log/pflog/pflog_*YYYYmmddHHMM*.log port 22
のようにする。
前節のPFの設定では、許可された接続のみをログするようにしている。もし、ブロックされた接続も含めてすべてのログを取るには、 pf.conf
の block in all
となっている箇所を、 block in log all
とする。
OS起動時に自動的に起動させる
macOSでは、デーモンの管理・実行をLaunchDaemons( launchd
)が行っている。したがって、上のスクリプトの実行をLaunchDaemonsに登録すれば、OS起動時に自動的に起動することができる。
このために、以下のような /Library/LaunchDaemons/local.pf.plist
を作成して、上のスクリプトの実行を登録する。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.pf</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/load_pf.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
このファイルの所有者と権限を以下のように設定する。
$ sudo chown root:wheel /Library/LaunchDaemons/local.pf.plist
$ sudo chmod 644 /Library/LaunchDaemons/local.pf.plist
local.pf.plist
を、LaunchDaemonsに読み込む。
$ sudo launchctl load -w /Library/LaunchDaemons/local.pf.plist
local.pf.plist
では、 RunAtLoad
を <true/>
としているので、上のコマンドを実行することで、読み込みと同時にプロセスが起動する。