2017/08/04

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 コメント:

コメントを投稿