白状すると、ここで2週間近くかかってしまいました。Ubuntuとかでは普通にサーバを立てるし、 iptables を普通に設定して使っていたことはあったのですが、MacOSでファイアウォールの設定をするのは初めてでした。結果だけ見ると至極簡単な設定だったのですが、そこに辿り着くまでに相当の試行錯誤があったので、その過程で学んだことを含めてまとめておこうと思います。
GUIのファイアウォールは本質的に無関係
MacOSでネットワーク関連の機能を操作しているだけで自然に目に入るのが、”システム設定” – “ネットワーク”の中にある”ファイアウォール”です。何を隠そう、私も最初はこちらを一生懸命設定していました。
Splunk Webは8000番ポートで待ち受けているのですが、単純にこのファイアウォールを無効にするとか、次の画面でsplunkdを外部からの接続を許可するアプリケーションとして追加するとか、とにかく考えうることをすべて試してみたのですが、外部から接続できる様子は全くありませんでした。
とにかくまず接続することを最優先と考え、上記画面でファイアウォールを無効にした状態で、以下のコマンドラインでtcpdumpを起動してから (en0は外部接続に利用しているインターフェース名)、同一ネットワークの別ホストからSpulnk Webへのアクセスを試みてみたのですが、
% sudo tcpdump -i en0 -nn | grep 8000
接続側がSYNパケットをひたすら送信し続け、非接続側が何も返していない状態であることがわかりました。さらにnmapで突いてみると、8000番ポートは “filtered” と表示されたので、明らかにファイアウォールで外部からの接続が制限されています。ちなみに画面共有に利用する5900番ポートはopenになっており、実際に接続することもできていました。
この状況からGUIのファイアウォールは無関係のように見えたとは言え、逆にそれ以外の手がかりがないのも事実です。MacOSの実態はUnixなので、裏でコマンドラインベースのプログラムが実際の挙動を担っているのは間違いありません。しかし、そうは言っても見た目はGUIベースのOSであるためか、そもそもMacOS自体が現在ではクライアントしかないためか、なかなか情報が見つかりませんでした。
結論から行くと、GUIのファイアウォールの背後にいるのは socketfilterfw で、実体は/usr/libexec/ApplicationFirewall/socketfilterfwにあります。少し触ってみます。
# 設定済みのアプリケーションを確認する
% sudo /usr/libexec/ApplicationFirewall/socketfilterfw --listapps
ALF: total number of apps = 4
1 : /Applications/Dropbox.app
( Allow incoming connections )
2 : /System/Library/CoreServices/UniversalControl.app
( Allow incoming connections )
3 : /System/Library/CoreServices/ControlCenter.app
( Allow incoming connections )
4 : /Applications/Google Chrome.app
( Allow incoming connections )
# ファイアウォールが稼働しているかどうかを確認する (GUIの有効/無効と連動)
% sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
Firewall is disabled. (State = 0)
# "外部からの接続を全てブロック" の状態を確認する
% sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getblockall
Block all DISABLED!
-hでヘルプを見ればわかるのですが、ここで設定できる内容はGUIの設定範囲を超えるものではなく、結局splunkdへの接続を有効にする上ではまったく役に立ちませんでした。ポート番号とかが一切出てこないのですが、CLIでいうところのlsofあたりの情報でそのプログラムが待ち受けているポート番号を調べて、そこへの外部接続を許可するような仕組みなのでしょうか?CLIでも抽象度が高い情報しか出力されないので、挙動がよくわからないですね…
大事なのはpf
さらに色々調べてゆくと、socketfilterfwとは別に、MacOSにはpfというファイアウォールプログラムが組み込まれていることがわかりました。pfはBSD系のUnixに伝統的に搭載されてきたファイアウォール (名前から行くとパケットフィルタ) で、MacOS X 10.7 (Lion) から導入されました (それ以前は ipfw)。
このpfの情報がとても少なくて難儀しました。古くから搭載されている分、情報はそこそこあるのですが、なぜかうまく動かないものが多かったり、ミスがある設定を有効にした瞬間に画面共有が切られて大きなタイムロスが発生したり (管理人のMac miniはヘッドレスで運用しているので、ネットワーク接続が切れると強制電源断をして自室に移設 → モニタとキーボードを接続して再設定 → 再度本来の設置場所に移設) と、とにかく時間を食いました。
pfのあれこれ
試行錯誤の結果なので、ゼロから構築した際にこの手順で正しいのかどうかは確認できないのですが、おそらく以下の手順でSplunk Webが動作する8000番ポートに外部から接続できるようになるはずです。
まず、最初に少しだけpfの基本的な動作を確認します。MacOSの場合、設定ファイルは /etc/pf.conf で、この内容に従って pfctl と言うプログラムで pf を制御することになります。
# pfの設定ファイルの内容を確認する
% cat /etc/pf.conf
#
# Default PF configuration file.
#
# This file contains the main ruleset, which gets automatically loaded
# at startup. PF will not be automatically enabled, however. Instead,
# each component which utilizes PF is responsible for enabling and disabling
# PF via -E and -X as documented in pfctl(8). That will ensure that PF
# is disabled only when the last enable reference is released.
#
# Care must be taken to ensure that the main ruleset does not get flushed,
# as the nested anchors rely on the anchor point defined here. In addition,
# to the anchors loaded by this file, some system services would dynamically
# insert anchors into the main ruleset. These anchors will be added only when
# the system service is used and would removed on termination of the service.
#
# See pf.conf(5) for syntax.
#
#
# com.apple anchor point
#
scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
# pfの動作状態を確認する (デフォルトでは無効)
% sudo pfctl -s info
No ALTQ support in kernel
ALTQ related functions disabled
Status: Disabled for 4 days 03:33:01 Debug: Urgent
(以下略)
# 現時点で有効になっているルールを確認する
% sudo pfctl -s rules
No ALTQ support in kernel
ALTQ related functions disabled
scrub-anchor "com.apple/*" all fragment reassemble
anchor "com.apple/*" all
最後の出力を見てわかる通り、初期状態では具体的な設定が一つも入っていません。エラーが出ているALTQ = ALTernate Queueingは、主に帯域の効率的な利用を目的としたキューイングを行うための機能です。これは本来pfに統合されているもののようですが、ALTQはサーバにとっては重要である一方、クライアントにとってはそうではありません。現在は消滅したMacOS Serverの系統の中ではpfの一部として動作していた時代もあったようですが、少なくともOS X Yosemite Server Updates : OS X v10.10.3 and Server v4.1 の時点で、カーネルから削除されていたようです。確認した限りでは決定的な情報はないのですが、ここは本質ではないので先に進みます。
また、GUIのファイアウォールとpfとの関係ですが、PF on Mac OS Xによると 先に後者が評価され、次に前者が評価されるような構造になっている とありますが、確認した限りでは別個に動作しているように見えます。PF on Mac OS Xは、2015年に作成された古いページではありますがこの辺の情報が大変よくまとめられており、socketfilterfw や pf に興味がある方は必見です。
pf.confで8000番ポートを開ける
さて、試行錯誤の結果 (もっとできる人なら一瞬なのかもしれませんが)、以下の2行を /etc/pf.confを修正し、
pass in proto tcp from 192.168.4.0/24 to any port 8000
pass out all keep state
その後、この設定ファイルを読み込ませてからpfを有効にすることで、
# 設定ファイルをpfに読み込ませる
% sudo pfctl -f /etc/pf.conf
pfctl: Use of -f option, could result in flushing of rules
present in the main ruleset added by the system at startup.
See /etc/pf.conf for further details.
No ALTQ support in kernel
ALTQ related functions disabled
# 設定が読み込まれていることを確認する
% sudo pfctl -s rules
No ALTQ support in kernel
ALTQ related functions disabled
scrub-anchor "com.apple/*" all fragment reassemble
anchor "com.apple/*" all
pass in inet proto tcp from 192.168.4.0/24 to any port = 8000 flags S/SA keep state
pass out all flags S/SA keep state
# pfを有効にする
% sudo pfctl -E
No ALTQ support in kernel
ALTQ related functions disabled
pf enabled
Token : 14305571672523093731
これで、同一NWにいる別の端末からMac mini上で動作しているSplunk Webにアクセスすることができるようになりました。
今度は無効化できない状態に….
しかし、不思議なことに一旦アクセスが可能になったら、今度は何をやってもアクセスを切ることができなくなってしまいました。少なくとも以下のいずれを実施しても、Splunk Webへのアクセスは有効なままでした。
- GUI版のファイアウォールを有効にする
- その上で、”外部からの接続を全てブロックする” を有効にする
- pfを停止する
- 上の二行を削除した (デフォルト状態の) pf.confを読み込ませてからpfを有効にする
ひょっとしたら再起動をすると挙動が変わるのかもしれませんが、所詮自宅NWに設置している機器の話なので、そこまで追求していません。