CentOS7 で NAPT の備忘録です.今まで CentOS などの汎用 UNIX OS でやったこと無かったんですが,ファイヤーウォール (CentOS7 なら firewalld) で実現するんですね.知りませんでした.
色々なところに詳しい説明があるので,詳細についてはそれらのサイトを見て頂くとして,ここでは,ネットワークが2つ(eth0 と eth1 とする)用意されており,
- eth1 をグローバル側(インターネットに近い側)
- eth0 をローカル側
- ローカルにつながる機器からグローバルへは自由に通信可能 (NAPT 利用)
- グローバル側からはローカルへは特定の通信のみ可能
というある意味最も単純な構成にする手順のみです.これだけなのに意外と情報が分散していて調べにくかったって言うのが備忘録にする理由です.まずは,必要なソフトウェアのインストールからスタートです.
事前準備
前提として,「CentOS-7-x86_64-Minimal-1511」から,ほぼ以下のページの通りにインストールを済ませているとしておきます.要するに最低限のものしか入っていない状態です.
ただし,今回は,eth1 がグローバル側,eth0 がローカル側に接続されており,eth1には DHCP でアドレスが割り当てられているという状態です.ネットワークの状態は以下の通り.
インターフェースの状態は以下の通り.
# nmcli d DEVICE TYPE STATE CONNECTION eth1 ethernet connected eth1 eth0 ethernet connecting (getting IP configuration) eth0 lo loopback unmanaged --
IP アドレスとルーティングの状態は以下の通り.eth1 側はインターネット(に近い)側で,DHCP でアドレス(192.168.100.109)等の割当が行われていますが,eth0 側は何も設定されていません.
# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 00:15:5d:64:02:18 brd ff:ff:ff:ff:ff:ff 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 00:15:5d:64:02:19 brd ff:ff:ff:ff:ff:ff inet 192.168.100.109/24 brd 192.168.100.255 scope global dynamic eth1 valid_lft 690994sec preferred_lft 690994sec inet6 fe80::215:5dff:fe64:219/64 scope link valid_lft forever preferred_lft forever # ip route show default via 192.168.100.15 dev eth1 proto static metric 100 192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.109 metric 100
まずは,eth0 に IP アドレス(192.168.0.1)を割り当てます.今回は nmcli を使いましたが,グラフィカルなツールである nmtui を使っても良いと思います.
# nmcli c modify eth0 ipv4.method manual # nmcli c modify eth0 ipv4.addresses 192.168.0.1/24 # nmcli c down eth0; nmcli c up eth0 Connection 'eth0' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/9) Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/10) # ip addr show eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 00:15:5d:64:02:18 brd ff:ff:ff:ff:ff:ff inet 192.168.100.1/24 brd 192.168.100.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::215:5dff:fe64:218/64 scope link valid_lft forever preferred_lft forever
firewalld のインストールと起動
このままでも iptables が使えるので,やろうと思えば今回の目標は達成できるのだろうとは思いますが,CentOS7 の標準は firewalld です.しかし何故か最小インストールだと firewalld は入っていません.従って,次の通りインストールします.
# yum -y install firewalld .... ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: firewalld noarch 0.3.9-14.el7 base 476 k Installing for dependencies: ebtables x86_64 2.0.10-13.el7 base 122 k libselinux-python x86_64 2.2.2-6.el7 base 247 k python-slip noarch 0.4.0-2.el7 base 30 k python-slip-dbus noarch 0.4.0-2.el7 base 31 k Transaction Summary ================================================================================ Install 1 Package (+4 Dependent packages) ....
追加で依存する4つのパッケージがインストールされます./etc/firewalld 以下に設定ファイルが配置され,これを変更しても良いのですが,どうも色々なところをみると,Windows の様にまずは動かし,その後,コマンドで設定を変更していく流れが一般の様です.
この方針に従い,再起動時自動立ち上げとなる設定と,起動設定を行っておきます.
# systemctl enable firewalld.service # systemctl start firewalld.service
ゾーンの設定
firewalld は Windows と同様に,ネットワークをゾーンという単位で管理します.Windows だと,プライベート,パブリック,ドメインの3種類が標準ですが,firewalld の場合は,block, dmz, drop, external, home, internal, public, trusted, work の8種類です.違いは名付け方から想像できる通りですが,
にある一覧表が分かり易いです(このページは firewalld の設定方法について非常に分かり易く網羅的に解説してくれています).
何も設定されていない場合は,全てのネットワークが public に所属となります.これは以下の様に active な zone を全て表示させると分かります.
# firewall-cmd --list-all public (default, active) interfaces: eth0 eth1 sources: services: dhcpv6-client ssh ports: masquerade: no forward-ports: icmp-blocks: rich rules:
見ての通り,public は,ssh と dhcpv6-client の通信のみが許可となっており,かなり厳しめの設定であることが分かります.
そして,今回は,eth1 を external に,eth0 を trusted に設定すれば目的を達成できます.
# nmcli c mod eth1 connection.zone external # nmcli c mod eth0 connection.zone trusted # reboot # firewall-cmd --get-active-zone external interfaces: eth1 trusted interfaces: eth0
firewall-cmd で所属ゾーンを変えることもできますが,これは再起動すると元に戻ってしまいます.元に戻らないようにするには nmcli で変更する必要があります.それぞれの詳しい状態は以下の通りです.
# firewall-cmd --list-all --zone=external external (active) interfaces: eth1 sources: services: ssh ports: masquerade: yes forward-ports: icmp-blocks: rich rules: # firewall-cmd --list-all --zone=trusted trusted (active) interfaces: eth0 sources: services: ports: masquerade: no forward-ports: icmp-blocks: rich rules:
eth1 は ssh のみ通り,masquerade が yes となっていますので,NAPT 状態であることが分かります.eth0 には何もサービスが書かれていないので,全て拒否のように見えますが,そうではなく,全て許可という状態です.これは /usr/lib/firewalld/zone にある external.xml と trusted.xml を見ればわかります.
# cat /usr/lib/firewalld/zones/trusted.xml <?xml version="1.0" encoding="utf-8"?> <zone target="ACCEPT"> <short>Trusted</short> <description>All network connections are accepted.</description> </zone>
通信許可の設定その1(サービス)
特定の通信を許可する設定は,サービスとして定義されているものとされていないものに分けて考える必要があります.サービスとして定義されているもの一覧は,
# firewall-cmd --get-service RH-Satellite-6 amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns freeipa-ldap freeipa-ldaps freeipa-replication ftp high-availability http https imaps ipp ipp-client ipsec iscsi-target kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind rsyncd samba samba-client smtp ssh telnet tftp tftp-client transmission-client vdsm vnc-server wbem-https
とすれば分かりますが,これは /usr/lib/firewalld/services にその設定があります.
http の場合は,
# cat /usr/lib/firewalld/services/http.xml <?xml version="1.0" encoding="utf-8"?> <service> <short>WWW (HTTP)</short> <description>HTTP is the protocol used to serve Web pages. If you plan to make your Web server publicly available, enable this option. This option is not required for viewing pages locally or developing Web pages.</description> <port protocol="tcp" port="80"/> </service>
のようになっていますので,この例を参考にして自分でサービスを定義し,firewalld に組み込むことも可能です.ただし,そのシステム特有のサービスの設定は /etc/firewalld/services に保存します.例えば,リモートデスクトップだと,tcp/3389ですので,
# vi /etc/firewalld/service/rdp.xml <?xml version="1.0" encoding="utf-8"?> <service> <short>RDP</short> <description>Microsoft RemoteDesktop Service</description> <port protocol="tcp" port="3389"/> </service>
のようなファイルを準備し,firewalld の設定を再読み込みすることで,rdp サービスが定義できます.
# systemctl reload firewalld # firewall-cmd --get-service .... rdp ....
サービスのゾーンへの適用は,firewall-cmd で行います.ただし,–permanent を付けないと一時的な即時適用として設定され,–permanent を付けると再起動後適用となることに注意が必要です.
# firewall-cmd --add-service=rdp --zone=external success # firewall-cmd --add-service=rdp --zone=external --permanent success # firewall-cmd --list-all --zone=external external (active) interfaces: eth1 sources: services: rdp ssh ports: masquerade: yes forward-ports: icmp-blocks: rich rules:
逆にサービス削除する場合は,
# firewall-cmd --remove-service=rdp --zone=external success # firewall-cmd --remove-service=rdp --zone=external --permanent success # firewall-cmd --list-all --zone=external external (active) interfaces: eth1 sources: services: ssh ports: masquerade: yes forward-ports: icmp-blocks: rich rules:
の様にすれば良いことになります.
通信許可の設定その2(直接指定)
同じことはポートを直接指定することでも実現できます.リモートデスクトップだと次の様になります.
# firewall-cmd --add-port=3386/tcp --zone=external success # firewall-cmd --add-port=3386/tcp --zone=external --permanent success # firewall-cmd --list-all --zone=external external (active) interfaces: eth1 sources: services: ssh ports: 3386/tcp masquerade: yes forward-ports: icmp-blocks: rich rules: # firewall-cmd --remove-port=3386/tcp --zone=external success # firewall-cmd --remove-port=3386/tcp --zone=external --permanent success # firewall-cmd --list-all --zone=external external (active) interfaces: eth1 sources: services: ssh ports: masquerade: yes forward-ports: icmp-blocks: rich rules:
ポートの転送
ポートの転送例は以下の通りです.tcp/3389 を tcp/13389 に転送しています.
# firewall-cmd --zone=external --add-forward-port=port=3389:proto=tcp:toport=13389 success # firewall-cmd --zone=external --add-forward-port=port=3389:proto=tcp:toport=13389 --permanent success
また,ポートだけでなく,他の端末(例は 192.168.0.2 に転送)に転送する例は以下の通り.いわゆるファイアーウォールの穴あけと呼ばれる作業ですね.
# firewall-cmd --zone=external --add-forward-port=port=3389:proto=tcp:toport=13389:toaddr=192.168.0.2 success # firewall-cmd --zone=external --add-forward-port=port=3389:proto=tcp:toport=13389:toaddr=192.168.0.2 --permanent success
まとめ
これだけできれば市販のルーターの基本機能とほぼ変わらないと思います.あと足りないのは UPnP への対応位でしょうか.もちろん最近のものはすごく多機能なので,あくまで「基本機能」だけなんですけどね.
UNIX 系の場合,設定ファイルを書き換えて再読み込みがこれまでの基本であり,決まり切った設定だと,設定ファイルの必要部分だけ書き換えるというのは合理的なんですが,ネットワーク周りだけはこれだと使い難いです.
最近は遠隔地にあるサーバの管理を行わないといけないことも増えてきました.ネットにつなぐ以上,ファイアーウォールの設定は厳しめでなければならず,でも,UNIX 系だと色々な設定を行うには ssh で接続できないといけない.だから,標準として適用されるファイヤーウォールのゾーンが public なのだと思います.
そして,運用を始めると,ファイヤーウォールの設定を変更しなければならないことは当然あり得る.でも,これをしくじると,ssh でも接続できなくなりかねない.この場合は指定した時間の後に再起動するよう設定してから,–permanent を付けずにファイヤーウォールの設定を変更し,想定通り動くかどうか確かめれば良い.
失敗しても指定時間が来れば再起動して再び再設定できますし,正しければ再起動を取り消してから(shutdown コマンドだとオプション -c で可能),改めて –permanent を付けた設定を行えば良い訳です.
私の場合も,遠隔地のサーバの設定をしくじった結果,結局現地に行かざるを得なくなった経験がありますので,少しでもこういう危険が避けられる実装はとてもありがたいと思います.