2017年8月4日金曜日

firewalld を使う!

CentOS/Redaht 7系から標準のOSファイヤーウォールがfirewalldになっています。
iptablesも今までどおり使えるけど、カスタマイズあされて色々セキュアになっている。。。らいし。
ベースはiptablesなのですが使い方が全く変わっている。
使ってみて、色々わかったのでメモ書き

インストール


インストールされていない場合はインストールして起動してみる。

# yum install firewalld
# systemctl start firewalld
# systemctl enable firewalld

NetworkManagerを利用している環境で後からfirewalldをインストールした場合、
NetworkManagerとの連携が上手く動かないことがあるため再起動しておく。

# systemctl restart NetworkManager

起動状態の確認

# firewall-cmd --state
running

firewalldはzoneというポリシーグループみたいな考え方があり、
それぞれのゾーンに役割や意味があります。
それぞれのゾーンについてはRedhatのマニュアルを読んでおきましょう。
https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/7/html/Security_Guide/sec-Using_Firewalls.html

現在、どのゾーンに所属しているのか確認

# firewall-cmd --get-active-zones
public
interfaces: eth0

現在publicというゾーンにeth0のNICインターフェースが登録されていることが分かります。
publicゾーンにどのようなポリシーがデフォルトで登録されているかというと、

# firewall-cmd --zone=public --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: dhcpv6-client ssh
ports:
protocols:
masquerade: no
forward-ports:
sourceports:
icmp-blocks:
rich rules:

デフォルトでipv6のdhcp通信とssh通信が許可されていることが分かります。

ゾーンの変更


サーバを配置している環境によってはdmzやtrustにゾーンを変更したい場合があるでしょう。
その場合は下記のようにして変更します。

# nmcli c modify "eth0" connection.zone public
# nmcli c up eth0
# nmcli -p con show "eth0"

ちなみにfirewalldコマンドからでもゾーンを変更できるのですが、
NetworkManager経由でNICを管理している場合エラーが出て怒られます。

# firewall-cmd --permanent --zone=public --change-interface=eth0
The interface is under control of NetworkManager, setting zone to 'public'.
success

ポリシーの登録方法


ポリシーの登録方法には大きく3つの方法があります。

・サービス、ポート単位でのアクセス制御定義
・リッチルールによるアクセス制御定義
・ダイレクトルールによるアクセス制御定義

サービス、ポート単位
サービス、ポート単位でのアクセス制御は簡単なのですが細かい制御はできません。
サービス、ポート単位でINの通信を許可するかしないかだけです。

リッチルール
リッチルールはiptablesの定義方法のようにアクセス制御を定義することができます。しかしINの通信のみです。

ダイレクトルール
リッチルール同様にiptablesの定義方法のようにアクセス制御定義をするこことができ、IN/OUT両方の通信を制御することができます。
しかしfirewalldのiptables定義を直接アタッチするため、コマンド実行時にポリリーが即時定義、反映される、ポリシーを壊すリスクがあります。
ここでは細かい制御を行えるダイレクトルールの設定を行います。

ダイレクトルールでの設定


まず前提でfirewalldはiptablesベースです。
firewalldをインストールし、起動した時点でデフォルトの定義が設定されています。

# iptables -nL
INPUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
INPUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_direct all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_IN_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_IN_ZONES all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_OUT_ZONES_SOURCE all -- 0.0.0.0/0 0.0.0.0/0
FORWARD_OUT_ZONES all -- 0.0.0.0/0 0.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0 ctstate INVALID
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target prot opt source destination
OUTPUT_direct all -- 0.0.0.0/0 0.0.0.0/0

Chain FORWARD_IN_ZONES (1 references)
target prot opt source destination
FWDI_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]
FWDI_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]

Chain FORWARD_IN_ZONES_SOURCE (1 references)
target prot opt source destination

Chain FORWARD_OUT_ZONES (1 references)
target prot opt source destination
FWDO_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]
FWDO_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]

Chain FORWARD_OUT_ZONES_SOURCE (1 references)
target prot opt source destination

Chain FORWARD_direct (1 references)
target prot opt source destination

Chain FWDI_public (2 references)
target prot opt source destination
FWDI_public_log all -- 0.0.0.0/0 0.0.0.0/0
FWDI_public_deny all -- 0.0.0.0/0 0.0.0.0/0
FWDI_public_allow all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0

Chain FWDI_public_allow (1 references)
target prot opt source destination

Chain FWDI_public_deny (1 references)
target prot opt source destination

Chain FWDI_public_log (1 references)
target prot opt source destination

Chain FWDO_public (2 references)
target prot opt source destination
FWDO_public_log all -- 0.0.0.0/0 0.0.0.0/0
FWDO_public_deny all -- 0.0.0.0/0 0.0.0.0/0
FWDO_public_allow all -- 0.0.0.0/0 0.0.0.0/0

Chain FWDO_public_allow (1 references)
target prot opt source destination

Chain FWDO_public_deny (1 references)
target prot opt source destination

Chain FWDO_public_log (1 references)
target prot opt source destination

Chain INPUT_ZONES (1 references)
target prot opt source destination
IN_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]
IN_public all -- 0.0.0.0/0 0.0.0.0/0 [goto]

Chain INPUT_ZONES_SOURCE (1 references)
target prot opt source destination

Chain INPUT_direct (1 references)
target prot opt source destination

Chain IN_public (2 references)
target prot opt source destination
IN_public_log all -- 0.0.0.0/0 0.0.0.0/0
IN_public_deny all -- 0.0.0.0/0 0.0.0.0/0
IN_public_allow all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0

Chain IN_public_allow (1 references)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 ctstate NEW

Chain IN_public_deny (1 references)
target prot opt source destination

Chain IN_public_log (1 references)
target prot opt source destination

Chain OUTPUT_direct (1 references)
target prot opt source destination

大分細かくチェインが切られ管理されていることが分かります。
定義されているルールはデフォルトとゾーンに基づくルールでしょう。

細かくは見ていきませんが、
「***_public」がサービス、ポート単位の操作で設定するチェイン。
_public_」の内容をインクルードしてルールを構築しています。

さらにそれらのゾーンチェインに定義されたルールを
「***_IN_ZONE」でインクルードし、「INPUT」「FORWARD」チェインにインクルードしている。
これを見るとOUTが制御できない理由が分かります。

ダイレクトルールは「***_direct」チェインに設定されます。
ダイレクト用のチェインは多層的ではなくすぐ「INPUT」「OUTPUT」にインクルードされ、定義がダイレクトに反映されているのが分かります。
※ダイレクトルールの場合、チェインを自分で定義することもできます。

ダイレクトルールの定義は下記コマンド構文で定義することができます。

# 追加
# firewall-cmd [--permanent] --direct --add-rule {ipv4|ipv6|eb} <テーブル> <チェイン> <優先順位> <引数>

# 削除
# firewall-cmd [--permanent] --direct --remove-rule {ipv4|ipv6|eb} <テーブル> <チェイン> <優先順位> <引数>

が、ハッキリ言って分かりにくいし、
昔のiptables定義のようにスクリプトで管理したいです。

実はダイレクトルールは他の定義方法と違い、XML形式で定義ファイルを作成し、それをfirewalldに読み込ませて反映させることができます。

今までのiptables定義スクリプト同様間違ったら即アウトの方法ですが、
管理上も管理しやすく、定義の仕方もコマンドよりは分かりやすいです。

XMLでのダイレクトルール定義


XMLファイルは「direct.xml」というファイル名で定義します。
定義を記載した「direct.xml」を「/etc/firewalld」ディレクトリ配下に配置し、firewalldコマンドで反映させることができます。

XMLは下記構文で記載していきます。
例えば特定のFROM IPからSSH許可を定義したい場合。

<?xml version="1.0" encoding="utf-8"?>
<direct>
<rule priority="1" table="filter" ipv="ipv4" chain="INPUT_direct">-s 192.168.1.1 -p tcp -m state --state NEW --dport 22 -j ACCEPT</rule>
</direct>

「priority」は定義が処理される優先順位となり、数字が若いものが先に処理されます。
「chain」は利用するチェインを定義します。ここは任意のチェインを作成、指定することもできますが、せっかくデフォルトで構成されているものがあるのでそちらを利用。
後はiptablesの定義同様にタグ内にポリシーを定義します。

例えばpriorityを利用して、ポリシーにマッチしない通信はログに出す、という事も今までどおり設定できます。
下記ではOUTの通信は全てDROPし、ポリシーにマッチしないものがあった場合はログに出力されます(多分)。

<?xml version="1.0" encoding="utf-8"?>
<direct>
<!-- SSH -->
<rule priority="1" table="filter" ipv="ipv4" chain="INPUT_direct">-s 192.168.1.1 -p tcp -m state --state NEW --dport 22 -j ACCEPT</rule>
<rule priority="2" table="filter" ipv="ipv4" chain="OUTPUT_direct">-j DROP</rule>
<!-- log -->
<rule priority="1" table="filter" ipv="ipv4" chain="INPUT_direct">-j LOG --log-prefix 'INPUT : ' --log-level=warning</rule>
<rule priority="1" table="filter" ipv="ipv4" chain="OUTPUT_direct">-j LOG --log-prefix 'OUTPUT : ' --log-level=warning</rule>
</direct>

またXML形式なのでコメントも書けるのがいいところ!

上記のようなポリシー定義を書いたXMLを作成し、配置。
firewakkdコマンドで反映させます。

# firewall-cmd --reload
sucsess

上手く設定できれば下記コマンドで確認できます。

# firewall-cmd --direct --get-all-rules

最後に、ダイレクトルールを設定し通信、ポリシー上問題ないことが分かったら
デフォルトでゾーンポリシーに定義されている通信ポリシーを削除しておきましょう。
iptablesコマンドで確認してわかるように、各ポリシーの定義はそれぞれ両方有効です。
管理が煩雑にならないよう、デフォルトのポリシーは削除しておきます。

# firewall-cmd --remove-service=ssh --permanent

最後に


ダイレクトルールで管理しようとすれば下記のような感じでスクリプトで管理できた。

#!/bin/bash
CONFIG_FILE=/opt/scripts/conf/direct.xml
ROOT_DIR=/etc/firewalld/
if [ ! -f "$CONFIG_FILE" ]; then
log_messages "file not found"
exit
fi

log_messages "WARNING: change firewalld rule"
firewall-cmd --lockdown-off
if [ -f "$ROOT_DIR/direct.xml" ]; then
cp -p "$ROOT_DIR/direct.xml" "$ROOT_DIR/direct.xml.$DATE"
cp "$CONFIG_FILE" "$ROOT_DIR"
else
cp "$CONFIG_FILE" "$ROOT_DIR"
fi

firewall-cmd --reload
iHANTEI="$?"
if [ "$iHANTEI" = 0 ]; then
log_messages "complete change firewalld"
firewall-cmd --reload
firewall-cmd --direct --get-all-rules
firewall-cmd --lockdown-on
echo "more checke messages!!"
else
log_messages "ERROR firewalld change"
cp -p "$ROOT_DIR/direct.xml.$DATE_TIME03" "$ROOT_DIR/direct.xml"
firewall-cmd --reload
firewall-cmd --direct --get-all-rules
firewall-cmd --lockdown-on
echo "more checke messages!!"
fi

0 コメント:

コメントを投稿