第 132 回関西 Debian 勉強会で ufw についての発表をしました。 その資料のファイル形式を変換したものです。

はじめに

ufw はバージョンアップに伴い、機能が追加されてできることが増えています。 そこで、現在の Debian の stable である stretch に入っている ufw 0.35-4 を元に基本的な機能やちょっと複雑なネットワークでの使用方法を紹介します。

ufw とは?

iptables のラッパーのようなもので、ファイアウォールの設定を簡単にできるようにするためのものです。 ちなみに名前の ufw は Uncomplicated Firewall の略で、Ubuntu Firewall ではありません。

使用開始

まず「ufw enable」で有効にします。 (「ufw disable」で戻せます。) 有効にするとすぐに反映されて、次回起動時からも有効になります。 ssh で接続している場合は、「ufw enable」の前に、そのポートを許可しておくと良いでしょう。 最近は大丈夫のようですが、昔は enable した直後に反応がなくなって切れてしまうことがあったので、再接続できるように許可しておいたり、他の接続手段も確保しておいたりしておく方が安全です。

$ sudo ufw allow 22/tcp
Rules updated
Rules updated (v6)
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

デフォルトの挙動

デフォルトでは外向きは許可、内向きは拒否という一般的に推奨される構成になっています。 許可などの設定は IP アドレスなどの指定がない場合、IPv4 と IPv6 の両方を同時に設定できるので、iptables と ip6tables を別々に設定して二度手間になるようなことがありません。

基本的な使い方

ポート番号のみを指定すると TCP/UDP 両方許可できます。 例えば DNS なら、以下のようになります。

$ sudo ufw allow 53
Rule added
Rule added (v6)

TCP のみ許可するには「ポート番号/tcp」と指定します。 例えば http なら、以下のようになります。

$ sudo ufw allow 80/tcp
Rule added
Rule added (v6)

UDP のみ許可するには「ポート番号/udp」と指定します。 ポート番号には「:」区切りで範囲を指定できます。 例えば mosh で使われる範囲を許可するなら、以下のようになります。

$ sudo ufw allow 60000:61000/udp
Rule added
Rule added (v6)

連続しないポート番号を「,」区切りでまとめて指定することもできます。 (「,」で区切られた中に範囲を指定することもできます。) 例えば SMTP などを許可するなら、以下のようになります。

$ sudo ufw allow 25,465,587/tcp
Rule added
Rule added (v6)

設定確認

「ufw status」で設定を確認できます。 「ufw status verbose」でデフォルトポリシーなどを含めた設定の確認ができます。 「ufw status numbered」で delete や insert で使う番号が確認できます。

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
53                         ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
60000:61000/udp            ALLOW       Anywhere
25,465,587/tcp             ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
53 (v6)                    ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
60000:61000/udp (v6)       ALLOW       Anywhere (v6)
25,465,587/tcp (v6)        ALLOW       Anywhere (v6)

$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
53                         ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
60000:61000/udp            ALLOW IN    Anywhere
25,465,587/tcp             ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)
53 (v6)                    ALLOW IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
60000:61000/udp (v6)       ALLOW IN    Anywhere (v6)
25,465,587/tcp (v6)        ALLOW IN    Anywhere (v6)

$ sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere
[ 2] 53                         ALLOW IN    Anywhere
[ 3] 80/tcp                     ALLOW IN    Anywhere
[ 4] 60000:61000/udp            ALLOW IN    Anywhere
[ 5] 25,465,587/tcp             ALLOW IN    Anywhere
[ 6] 22/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 7] 53 (v6)                    ALLOW IN    Anywhere (v6)
[ 8] 80/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 9] 60000:61000/udp (v6)       ALLOW IN    Anywhere (v6)
[10] 25,465,587/tcp (v6)        ALLOW IN    Anywhere (v6)

ルールの削除

「ufw delete 追加した時のルール」や「ufw delete ルール番号」でルールを削除できます。

$ sudo ufw delete allow 25,465,587/tcp
Rule deleted
Rule deleted (v6)
$ sudo ufw delete allow 60000:61000/udp
Rule deleted
Rule deleted (v6)

ルールの表記方法

今まで使ってきた「ufw [–dry-run] [delete] [insert NUM] allow|deny|reject|limit [in|out] [log|log-all] [ PORT[/PROTOCOL] | APP‐NAME ] [comment COMMENT]」という省略記法の他に、「ufw [–dry-run] [rule] [delete] [insert NUM] allow|deny|reject|limit [in|out [on INTERFACE]] [log|log-all] [proto PROTOCOL] [from ADDRESS [port PORT | app APPNAME ]] [to ADDRESS [port PORT | app APPNAME ]] [comment COMMENT]」という細かく指定する書き方もあります。 IP アドレスを指定するには後者の表記方法を使う必要があります。 詳細は man を参照してください。

特定 IP アドレスのみ拒否

前述のように IP アドレスを指定するには「ポート番号/プロトコル」という指定の仕方では無理なので、細かく指定していきます。 また、許可より前に拒否するルールがないといけないので、「insert」 を使います。ここで先ほどの「ufw status numbered」の出力をみると 3 より前にあれば良いとわかるので、「insert 3」と指定します。 ポート番号を指定するときは IP アドレスの指定は必須なので、特に制限する必要がないときは「any」を使います。

$ sudo ufw insert 3 deny from 192.0.2.0/24 to any port 80 proto tcp
Rule inserted
$ sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere
[ 2] 53                         ALLOW IN    Anywhere
[ 3] 80/tcp                     DENY IN     192.0.2.0/24
[ 4] 80/tcp                     ALLOW IN    Anywhere
[ 5] 22/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 6] 53 (v6)                    ALLOW IN    Anywhere (v6)
[ 7] 80/tcp (v6)                ALLOW IN    Anywhere (v6)

$ sudo ufw delete deny from 192.0.2.0/24 to any port 80 proto tcp
Rule deleted
$ sudo ufw insert 3 deny from 192.0.2.0/24 to any port 80 proto tcp
Rule inserted
$ sudo ufw delete 3
Deleting:
 deny from 192.0.2.0/24 to any port 80 proto tcp
Proceed with operation (y|n)? y
Rule deleted

「from」で IPv4 アドレスを指定したので、ルールは自動的に IPv4 の方だけになって IPv6 には何も影響していません。

on INTERFACE

特定のネットワークインターフェイスを通るパケットだけ対象にしたい場合は「on INTERFACE」を使います。 例えばプロキシを必須にするなどで外部の 80,443 は直接繋がせない、とする場合は以下のようになります。 外部への通信なので「out」もつけています。

また、内部から外部への通信は「deny」で無視すると応答がなくなって、タイムアウト待ちなどでトラブルシューティングに時間がかかるので、すぐに拒否される「reject」を使うのがおすすめです。

インターフェイスは iptables と同様に「ppp+」で「ppp0」や「ppp1」などをまとめて指定できます。 そのため「enp0s3」だったり「ens3」だったりする stretch では「en+」でまとめて指定するとハードウェア構成に依存せずに設定を共有しやすくなると思います。

$ sudo ufw reject out on en+ to any port 80,443 proto tcp
Rule added
Rule added (v6)
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
53                         ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
53 (v6)                    ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)

80,443/tcp                 REJECT OUT  Anywhere on en+
80,443/tcp (v6)            REJECT OUT  Anywhere (v6) on en+

$ curl --head www.debian.org
curl: (7) Failed to connect to www.debian.org port 80: Connection refused
$ sudo ufw delete reject out on en+ to any port 80,443 proto tcp
Rule deleted
Rule deleted (v6)

deny だと応答がなくなったので Ctrl+C で止めました。

$ sudo ufw deny out on en+ to any port 80,443 proto tcp
Rule added
Rule added (v6)
$ curl --head www.debian.org
^C
$ sudo ufw delete deny out on en+ to any port 80,443 proto tcp
Rule deleted
Rule deleted (v6)

アプリケーションで指定

「/etc/ufw/applications.d/」にアプリケーション名で設定するための情報が入っていて、「sudo ufw app list」で一覧できます。

$ sudo ufw app list
Available applications:
  AIM
  Bonjour
  CIFS
  DNS
  Deluge
  IMAP
  IMAPS
  IPP
  KTorrent
  Kerberos Admin
  Kerberos Full
  Kerberos KDC
  Kerberos Password
  LDAP
  LDAPS
  LPD
  MSN
  MSN SSL
  Mail submission
  NFS
  OpenSSH
  POP3
  POP3S
  PeopleNearby
  SMTP
  SSH
  Socks
  Telnet
  Transmission
  Transparent Proxy
  VNC
  WWW
  WWW Cache
  WWW Full
  WWW Secure
  XMPP
  Yahoo
  qBittorrent
  svnserve
$ ls /etc/ufw/applications.d/
openssh-server  ufw-chat             ufw-dnsserver   ufw-loginserver  ufw-printserver  ufw-webserver
ufw-bittorent   ufw-directoryserver  ufw-fileserver  ufw-mailserver   ufw-proxyserver
$ cat /etc/ufw/applications.d/openssh-server
[OpenSSH]
title=Secure shell server, an rshd replacement
description=OpenSSH is a free implementation of the Secure Shell protocol.
ports=22/tcp
$ cat /etc/ufw/applications.d/ufw-webserver
[WWW]
title=Web Server
description=Web server
ports=80/tcp

[WWW Secure]
title=Web Server (HTTPS)
description=Web Server (HTTPS)
ports=443/tcp

[WWW Full]
title=Web Server (HTTP,HTTPS)
description=Web Server (HTTP,HTTPS)
ports=80,443/tcp

[WWW Cache]
title=Web Server (8080)
description=Web Server (8080)
ports=8080/tcp

アプリ名をポート番号とプロトコルの組み合わせの代わりに使うことができます。 スペースが入っているアプリ名の場合はシェルで引数が分割されないようにクォートする必要があるので、注意が必要です。

$ sudo ufw reject out OpenSSH
Rule added
Rule added (v6)
$ sudo ufw reject out to 10.0.0.0/8 app 'WWW Full'
Rule added
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
53                         ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
53 (v6)                    ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)

OpenSSH                    REJECT OUT  Anywhere
10.0.0.0/8 WWW Full        REJECT OUT  Anywhere
OpenSSH (v6)               REJECT OUT  Anywhere (v6)
$ sudo ufw delete reject out to 10.0.0.0/8 app WWW Full
ERROR: Wrong number of arguments
$ sudo ufw delete reject out to 10.0.0.0/8 app 'WWW Full'
Rule deleted
$ sudo ufw delete reject out OpenSSH
Rule deleted
Rule deleted (v6)

limit

拒否の仕方に deny と reject があるのと似た感じで、許可の方にも allow と limit の2種類があります。 limit は brute force attack の緩和に使えます。 30 秒間に 6 回までしか新規接続ができない、という設定になるようです。 正常な接続かどうかに関わらず、iptables の層で拒否してしまうので、例えば構成管理ツールなどで自分が短時間に頻繁に接続する可能性がある場合は避けた方が良いです。

$ sudo ufw limit 22/tcp
Rule updated
Rule updated (v6)
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT       Anywhere
53                         ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
22/tcp (v6)                LIMIT       Anywhere (v6)
53 (v6)                    ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)

「/etc/ufw/user.rules」に設定されている内容は以下の通りです。

### tuple ### limit tcp 22 0.0.0.0/0 any 0.0.0.0/0 in
-A ufw-user-input -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
-A ufw-user-input -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 30 --hitcount 6 -j ufw-user-limit
-A ufw-user-input -p tcp --dport 22 -j ufw-user-limit-accept

コマンドラインで指定できない設定を入れる方法

「/etc/ufw/before.rules」と「/etc/ufw/before6.rules」が ufw のルールの前に読み込まれる iptables-restore と ip6tables-restore のルールファイルになっているので、 IPsec の ESP の許可などの ufw コマンドで設定できないルールはこのファイルを直接編集すれば良いでしょう。 ufw で設定したルールより後に読み込まれる「after.rules」と「after6.rules」もあるので、用途によってはこちらを使っても良いでしょう。

NAT 設定

ちょっと複雑なネットワークだと、例えば POSTROUTING の MASQUERADE 設定はよく使うと思うのですが、「ufw」のコマンドラインでは nat テーブルの設定はできないので、「before.rules」などに追加することになります。

以下のような設定を「*filter」より上 (または COMMIT より下) に追加すると NAT の設定ができます。 反映させるには「ufw reload」を実行する必要があります。 また、「-F」の行が重要で、入れていないと「ufw reload」を実行するたびに nat テーブルの設定が増えていくことになります。

# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
-F
# Allow traffic from OpenVPN client to enp0s3
-A POSTROUTING -s 192.168.10.0/24 -o en+ -j MASQUERADE
# Allow traffic from 192.168.1.0/24 (server's LAN subnet) to OpenVPN client
-A POSTROUTING -s 192.168.1.0/24 -o tun0 -j MASQUERADE
COMMIT

iptables-restore で直接設定したものになるので、確認は「sudo iptables -t nat -nL」になります。

$ sudoedit /etc/ufw/before.rules
(-F がない場合)
$ sudo ufw reload
Firewall reloaded
$ sudo ufw reload
Firewall reloaded
$ sudo iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  192.168.10.0/24      0.0.0.0/0
MASQUERADE  all  --  192.168.1.0/24       0.0.0.0/0
MASQUERADE  all  --  192.168.10.0/24      0.0.0.0/0
MASQUERADE  all  --  192.168.1.0/24       0.0.0.0/0
$ sudoedit /etc/ufw/before.rules
(-F を追加)
$ sudo ufw reload
Firewall reloaded
$ sudo iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  192.168.10.0/24      0.0.0.0/0
MASQUERADE  all  --  192.168.1.0/24       0.0.0.0/0

routed の有効化

初期状態では disabled になっていますが、「/etc/ufw/sysctl.conf」でも「/etc/sysctl.conf」でも「/etc/sysctl.d/*.conf」でも良いので、カーネルの設定を有効にすると「disabled」ではなくなります。

$ sudo ufw status verbose | grep Default
Default: deny (incoming), allow (outgoing), disabled (routed)
$ sudo tee /etc/sysctl.d/50-local.conf
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
$ sudo sysctl -p /etc/sysctl.d/50-local.conf
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
$ sudo ufw status verbose | grep Default
Default: deny (incoming), allow (outgoing), deny (routed)

FORWARD チェインの設定

「ufw route」で iptables の FORWARD チェインの設定もできます。 「ufw route」は changelog によると ufw 0.34 から追加されているので、Debian だと jessie の 0.33-2 だと使えなくて stretch の 0.35-4 から使えるようです。

iptables の FORWARD チェインに対する設定になる以外は INPUT や OUTPUT チェインに対する操作と変わりません。

$ sudo ufw route allow from 192.168.10.0/24 to 10.0.0.0/8 port 80 proto tcp
Rule added
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT       Anywhere
53                         ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
22/tcp (v6)                LIMIT       Anywhere (v6)
53 (v6)                    ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)

10.0.0.0/8 80/tcp          ALLOW FWD   192.168.10.0/24
$ sudo ufw route delete allow from 192.168.10.0/24 to 10.0.0.0/8 port 80 proto tcp
Rule deleted

デフォルトポリシーの変更

ufw [--dry-run] default allow|deny|reject [incoming|outgoing|routed] 」でチェーンのデフォルトのポリシーを変更できます。

stretch の ufw では、「default reject」は「 ufw*-reject-* 」チェーンで reject していて、FORWARD チェインなどの指定した組み込みのチェーンの policy が REJECT に変わるわけではないようです。

$ sudo ufw status verbose | grep Default
Default: deny (incoming), allow (outgoing), deny (routed)
$ grep FORWARD /etc/default/ufw
DEFAULT_FORWARD_POLICY="DROP"
$ sudo iptables -nL | grep FORWARD
Chain FORWARD (policy DROP)
$ sudo iptables -nL | grep -A2 'Chain.*reject-forward'
Chain ufw-reject-forward (1 references)
target     prot opt source               destination

$ sudo ufw default reject routed
Default routed policy changed to 'reject'
(be sure to update your rules accordingly)
$ grep FORWARD /etc/default/ufw
DEFAULT_FORWARD_POLICY="REJECT"
$ sudo iptables -nL | grep FORWARD
Chain FORWARD (policy DROP)
$ sudo ufw status verbose | grep Default
Default: deny (incoming), allow (outgoing), reject (routed)
$ sudo iptables -nL | grep -A2 'Chain.*reject-forward'
Chain ufw-reject-forward (1 references)
target     prot opt source               destination
REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-port-unreachable
$ sudo ufw default deny routed
Default routed policy changed to 'deny'
(be sure to update your rules accordingly)

コメント

今の ufw のルールにはコメントがつけられるようになっています。 コメントは ufw のルールに紐づいていて、 iptables の方には特に何も影響はないようです。

$ sudo ufw allow 60000:61000/udp comment "mobile shell"
Rule added
Rule added (v6)
$ sudo ufw status | grep 60000
60000:61000/udp            ALLOW       Anywhere                   # mobile shell
60000:61000/udp (v6)       ALLOW       Anywhere (v6)              # mobile shell
$ sudo grep 60000 /etc/ufw/user*.rules
/etc/ufw/user6.rules:### tuple ### allow udp 60000:61000 ::/0 any ::/0 in comment=6d6f62696c65207368656c6c
/etc/ufw/user6.rules:-A ufw6-user-input -p udp -m multiport --dports 60000:61000 -j ACCEPT
/etc/ufw/user.rules:### tuple ### allow udp 60000:61000 0.0.0.0/0 any 0.0.0.0/0 in comment=6d6f62696c65207368656c6c
/etc/ufw/user.rules:-A ufw-user-input -p udp -m multiport --dports 60000:61000 -j ACCEPT

ufw show REPORT

ufw の man の REPORTS セクションで紹介されているように、「ufw show REPORT」で設定状態などを表示できます。 「sudo ufw show listening」は実際に待ち受けしているポートを ufw の設定状況と一緒に一覧できるので、便利そうです。

  • sudo ufw show raw
  • sudo ufw show builtins
  • sudo ufw show before-rules
  • sudo ufw show user-rules
  • sudo ufw show after-rules
  • sudo ufw show logging-rules
  • sudo ufw show listening
  • sudo ufw show added
$ sudo ufw show listening
tcp:
  111 * (rpcbind)
  22 * (sshd)
   [ 1] allow 22/tcp

tcp6:
  111 * (rpcbind)
  22 * (sshd)
   [ 2] allow 22/tcp

udp:
  1015 * (rpcbind)
  111 * (rpcbind)
  68 * (dhclient)
udp6:
  1015 * (rpcbind)
  111 * (rpcbind)

ログレベル

デフォルトだと拒否された時のログが rate limit 付きで /var/log/ufw.log などに残りますが、「 ufw [--dry-run] logging on|off|LEVEL 」で、どのくらいログを残すのか設定できます。

設定できるのは on, off, low, medium, high, full のようです。 詳細は man を参照してください。

Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published