Firewall Management

Linux ファイアウォール管理 完全ガイド

目次

  1. はじめに
  2. ファイアウォールの基礎概念
  3. Netfilter アーキテクチャ
  4. iptables 詳細解説
  5. ip6tables(IPv6 ファイアウォール)
  6. nftables 詳細解説
  7. firewalld 詳細解説
  8. 実践シナリオ
  9. トラブルシューティング
  10. ベストプラクティス
  11. 比較表
  12. 参考文献

1. はじめに

Linux ファイアウォールは、ネットワークセキュリティの最前線であり、システム管理者にとって最も重要なスキルの一つである。本ガイドでは、Linux におけるファイアウォール管理の全体像を包括的に解説する。iptables、nftables、firewalld の3つの主要なファイアウォール管理ツールについて、基礎概念から実践的な構成例まで、網羅的にカバーする。

対象読者

  • Linux システム管理者
  • ネットワークエンジニア
  • セキュリティエンジニア
  • SRE(Site Reliability Engineer)

前提知識

  • TCP/IP ネットワーキングの基礎
  • Linux コマンドラインの操作
  • 基本的なネットワークサービス(HTTP、SSH、DNS 等)の理解

2. ファイアウォールの基礎概念

2.1 ファイアウォールとは

ファイアウォールは、ネットワークトラフィックを監視・制御し、事前に定義されたセキュリティルールに基づいてパケットの通過を許可または拒否するネットワークセキュリティシステムである。

2.2 パケットフィルタリングの種類

種類説明特徴
ステートレスフィルタリング個々のパケットを独立して評価高速だが柔軟性に欠ける
ステートフルフィルタリング接続状態を追跡して判断より高度なフィルタリングが可能
アプリケーション層フィルタリングL7 レベルでの検査深い検査が可能だが負荷が高い

2.3 Linux におけるファイアウォールの歴史

ipfwadm (Linux 2.0) → ipchains (Linux 2.2) → iptables (Linux 2.4+) → nftables (Linux 3.13+)

3. Netfilter アーキテクチャ

3.1 Netfilter フレームワーク

Netfilter は Linux カーネルに組み込まれたパケット処理フレームワークである。iptables と nftables はいずれも Netfilter のフロントエンドとして機能する。

3.2 フックポイント

Netfilter は、パケット処理パスの5つのポイントにフックを提供する。

                           ┌─────────────┐
                           │   PREROUTING │
                           └──────┬──────┘
                                  │
                           ┌──────▼──────┐
                           │   ルーティング  │
                           │   判定       │
                           └──┬───────┬──┘
                              │       │
                     ┌────────▼───┐ ┌─▼────────┐
                     │   INPUT    │ │  FORWARD  │
                     └────────┬───┘ └─┬────────┘
                              │       │
                     ┌────────▼───┐   │
                     │ ローカル    │   │
                     │ プロセス    │   │
                     └────────┬───┘   │
                              │       │
                     ┌────────▼───┐   │
                     │   OUTPUT   │   │
                     └────────┬───┘   │
                              │       │
                           ┌──▼───────▼──┐
                           │ POSTROUTING  │
                           └──────┬──────┘
                                  │
                              [出力]
フックポイント説明
PREROUTINGパケットがインターフェースに到着した直後(ルーティング前)
INPUTローカルプロセス宛のパケット
FORWARD転送されるパケット(ルーターとして動作時)
OUTPUTローカルプロセスが生成したパケット
POSTROUTINGパケットがインターフェースから出る直前

4. iptables 詳細解説

4.1 テーブルとチェイン

iptables は複数のテーブルで構成され、各テーブルには複数のチェインが含まれる。

テーブル一覧

テーブル用途含まれるチェイン
filterパケットフィルタリング(デフォルト)INPUT, FORWARD, OUTPUT
natネットワークアドレス変換PREROUTING, INPUT, OUTPUT, POSTROUTING
mangleパケットヘッダの変更全5チェイン
raw接続追跡の除外PREROUTING, OUTPUT
securitySELinux 用のセキュリティマーキングINPUT, FORWARD, OUTPUT

テーブルの確認

# filter テーブルのルール一覧(デフォルト)
$ sudo iptables -L -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

# nat テーブルのルール一覧
$ sudo iptables -t nat -L -n -v

# mangle テーブルのルール一覧
$ sudo iptables -t mangle -L -n -v

4.2 ルールの構文と記述方法

基本構文

iptables [-t テーブル] コマンド チェイン [マッチ条件] -j ターゲット

コマンド一覧

コマンド説明
-A (append)チェインの末尾にルールを追加
-I (insert)チェインの指定位置にルールを挿入
-D (delete)ルールを削除
-R (replace)ルールを置換
-F (flush)チェインの全ルールを削除
-Z (zero)カウンタをリセット
-N (new)カスタムチェインを作成
-X (delete-chain)カスタムチェインを削除
-P (policy)チェインのデフォルトポリシーを設定
-L (list)ルールを一覧表示

マッチ条件

# プロトコル指定
-p tcp
-p udp
-p icmp

# 送信元アドレス
-s 192.168.1.0/24
-s 10.0.0.1

# 宛先アドレス
-d 172.16.0.0/16

# インターフェース指定
-i eth0    # 入力インターフェース
-o eth1    # 出力インターフェース

# ポート指定(TCP/UDP)
--dport 80       # 宛先ポート
--sport 1024:65535  # 送信元ポート範囲
-m multiport --dports 80,443,8080  # 複数ポート

# 接続状態
-m conntrack --ctstate NEW,ESTABLISHED,RELATED

# MAC アドレス
-m mac --mac-source 00:11:22:33:44:55

基本的なルール例

# SSH(ポート22)を許可
$ sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 特定のIPからのSSHを許可
$ sudo iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -j ACCEPT

# HTTP/HTTPS を許可
$ sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# ICMP(ping)を許可
$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# ループバックインターフェースを許可
$ sudo iptables -A INPUT -i lo -j ACCEPT
$ sudo iptables -A OUTPUT -o lo -j ACCEPT

# 確立済み接続を許可
$ sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# デフォルトポリシーをDROPに設定
$ sudo iptables -P INPUT DROP
$ sudo iptables -P FORWARD DROP
$ sudo iptables -P OUTPUT ACCEPT

4.3 ターゲット(アクション)

ターゲット説明
ACCEPTパケットを許可
DROPパケットを無言で破棄
REJECTパケットを拒否し、エラーメッセージを返す
LOGパケット情報をログに記録(処理は継続)
SNAT送信元アドレスを変換
DNAT宛先アドレスを変換
MASQUERADE動的な送信元NAT
REDIRECTパケットをローカルにリダイレクト
RETURN現在のチェインから呼び出し元に戻る

REJECT の詳細

# TCP RST で拒否
$ sudo iptables -A INPUT -p tcp --dport 23 -j REJECT --reject-with tcp-reset

# ICMP port-unreachable で拒否(デフォルト)
$ sudo iptables -A INPUT -p tcp --dport 23 -j REJECT --reject-with icmp-port-unreachable

# ICMP host-unreachable で拒否
$ sudo iptables -A INPUT -j REJECT --reject-with icmp-host-unreachable

4.4 NAT(ネットワークアドレス変換)

SNAT(Source NAT)

送信元IPアドレスを変換する。通常、内部ネットワークからインターネットへのアクセスに使用する。

# 静的SNAT: 内部ネットワークからの通信の送信元を203.0.113.1に変換
$ sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.1

# 複数のIPアドレスでSNAT(ロードバランシング)
$ sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.1-203.0.113.10

MASQUERADE

動的なIPアドレス(DHCPなど)を持つインターフェースでの SNAT。

# マスカレード設定
$ sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# IP フォワーディングの有効化(必須)
$ sudo sysctl -w net.ipv4.ip_forward=1

# 永続化
$ echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf

DNAT(Destination NAT)

宛先IPアドレスを変換する。ポートフォワーディングやロードバランシングに使用する。

# ポートフォワーディング: 外部からのポート80を内部サーバー192.168.1.100:8080に転送
$ sudo iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 80 -j DNAT --to-destination 192.168.1.100:8080

# FORWARDチェインでも許可が必要
$ sudo iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 8080 -m conntrack --ctstate NEW -j ACCEPT
$ sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 複数サーバーへのロードバランシング
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100-192.168.1.103

REDIRECT

パケットをローカルマシンの別のポートにリダイレクトする。

# ポート80へのアクセスをポート8080にリダイレクト(透過プロキシ用)
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

4.5 接続追跡(Connection Tracking)

conntrack モジュール

# 接続追跡テーブルの確認
$ sudo conntrack -L
tcp      6 431999 ESTABLISHED src=192.168.1.10 dst=93.184.216.34 sport=54321 dport=80 src=93.184.216.34 dst=192.168.1.10 sport=80 dport=54321 [ASSURED] mark=0 use=1

# 接続数の確認
$ sudo conntrack -C
256

# 特定の接続をフラッシュ
$ sudo conntrack -D -s 192.168.1.10

# 接続追跡テーブルのサイズ確認・変更
$ cat /proc/sys/net/netfilter/nf_conntrack_max
65536

$ sudo sysctl -w net.netfilter.nf_conntrack_max=131072

接続状態

状態説明
NEW新しい接続の最初のパケット
ESTABLISHED確立済み接続に属するパケット
RELATED既存の接続に関連する新しい接続(例: FTP データ接続)
INVALID既知の接続に属さない、または不正なパケット
UNTRACKEDraw テーブルで NOTRACK としてマークされたパケット
# ステートフルファイアウォールの基本設定
$ sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
$ sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
$ sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
$ sudo iptables -P INPUT DROP

4.6 レート制限

limit モジュール

# SSH接続のレート制限(1分間に3回まで、バースト5)
$ sudo iptables -A INPUT -p tcp --dport 22 -m limit --limit 3/minute --limit-burst 5 -j ACCEPT
$ sudo iptables -A INPUT -p tcp --dport 22 -j DROP

# ICMP のレート制限
$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/second --limit-burst 4 -j ACCEPT
$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

# ログのレート制限
$ sudo iptables -A INPUT -m limit --limit 5/minute -j LOG --log-prefix "iptables-dropped: " --log-level 4

hashlimit モジュール(送信元IPごとのレート制限)

# 送信元IPごとにSSH接続を制限
$ sudo iptables -A INPUT -p tcp --dport 22 -m hashlimit \
    --hashlimit-name ssh_limit \
    --hashlimit-above 4/minute \
    --hashlimit-burst 5 \
    --hashlimit-mode srcip \
    -j DROP

recent モジュール(ブルートフォース対策)

# SSH ブルートフォース攻撃対策
$ sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSH
$ sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP

4.7 ロギング

# 全てのドロップされたパケットをログに記録
$ sudo iptables -A INPUT -j LOG --log-prefix "IPT-DROP-INPUT: " --log-level 4

# 特定のトラフィックをログ
$ sudo iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "IPT-SSH: " --log-level info

# ログの確認
$ sudo dmesg | grep "IPT-DROP"
$ sudo journalctl -k | grep "IPT-DROP"

# rsyslog でファイアウォールログを専用ファイルに出力
$ cat /etc/rsyslog.d/iptables.conf
:msg, contains, "IPT-" /var/log/iptables.log
& stop

# NFLOG ターゲット(ulogd2 と連携)
$ sudo iptables -A INPUT -j NFLOG --nflog-prefix "firewall: " --nflog-group 1

4.8 ルールの永続化

iptables-persistent(Debian/Ubuntu)

# インストール
$ sudo apt install iptables-persistent

# ルールの保存
$ sudo netfilter-persistent save

# ルールの復元
$ sudo netfilter-persistent reload

# 手動での保存と復元
$ sudo iptables-save > /etc/iptables/rules.v4
$ sudo ip6tables-save > /etc/iptables/rules.v6
$ sudo iptables-restore < /etc/iptables/rules.v4

iptables-services(RHEL/CentOS)

# インストール
$ sudo yum install iptables-services

# サービスの有効化
$ sudo systemctl enable iptables
$ sudo systemctl start iptables

# ルールの保存
$ sudo service iptables save
# または
$ sudo iptables-save > /etc/sysconfig/iptables

# ルールの復元
$ sudo iptables-restore < /etc/sysconfig/iptables

iptables-save/restore の出力形式

$ sudo iptables-save
# Generated by iptables-save v1.8.7 on Thu Apr 10 10:00:00 2026
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
COMMIT

5. ip6tables(IPv6 ファイアウォール)

5.1 基本概念

ip6tables は iptables の IPv6 版であり、構文はほぼ同一だが IPv6 固有の機能がある。

5.2 IPv6 固有の考慮事項

# ICMPv6 は IPv6 の動作に必須(NDP: Neighbor Discovery Protocol)
# 以下のICMPv6タイプは必ず許可する必要がある

# Router Solicitation
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type router-solicitation -j ACCEPT
# Router Advertisement
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT
# Neighbor Solicitation
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-solicitation -j ACCEPT
# Neighbor Advertisement
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbour-advertisement -j ACCEPT

# Echo Request/Reply
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT
$ sudo ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT

5.3 IPv6 ファイアウォールの基本設定

# ポリシー設定
$ sudo ip6tables -P INPUT DROP
$ sudo ip6tables -P FORWARD DROP
$ sudo ip6tables -P OUTPUT ACCEPT

# ループバック許可
$ sudo ip6tables -A INPUT -i lo -j ACCEPT

# 確立済み接続を許可
$ sudo ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 必須 ICMPv6 を許可
$ sudo ip6tables -A INPUT -p icmpv6 -j ACCEPT

# リンクローカルアドレスからの通信を許可
$ sudo ip6tables -A INPUT -s fe80::/10 -j ACCEPT

# SSH を許可
$ sudo ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT

# HTTP/HTTPS を許可
$ sudo ip6tables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

6. nftables 詳細解説

6.1 nftables の概要と利点

nftables は iptables の後継として開発されたパケットフィルタリングフレームワークである。

iptables と nftables の比較

項目iptablesnftables
カーネルサポートLinux 2.4+Linux 3.13+
IPv4/IPv6別々のコマンド (iptables/ip6tables)統一された構文
ルール変更ルール毎にカーネルコールアトミック操作が可能
構文コマンドライン引数ベース独自の構文言語
パフォーマンス線形ルール評価セット/マップによる高速マッチ
テーブル固定(filter, nat, mangle, raw)ユーザー定義
デフォルトルールなし(全テーブルに全チェインが存在)必要なものだけ作成

6.2 基本構文

nft コマンドの基本操作

# ルールセット一覧
$ sudo nft list ruleset

# テーブル一覧
$ sudo nft list tables

# 特定のテーブルの内容
$ sudo nft list table inet filter

# ルールセットのクリア
$ sudo nft flush ruleset

ファミリー

ファミリー説明
ipIPv4 のみ
ip6IPv6 のみ
inetIPv4 と IPv6 の両方
arpARP
bridgeブリッジ
netdevネットワークデバイス

6.3 テーブルとチェイン

# テーブルの作成
$ sudo nft add table inet filter

# ベースチェインの作成(入力)
$ sudo nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }

# ベースチェインの作成(転送)
$ sudo nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }

# ベースチェインの作成(出力)
$ sudo nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }

# ルールの追加
$ sudo nft add rule inet filter input iif lo accept
$ sudo nft add rule inet filter input ct state established,related accept
$ sudo nft add rule inet filter input ct state invalid drop
$ sudo nft add rule inet filter input tcp dport 22 accept
$ sudo nft add rule inet filter input tcp dport { 80, 443 } accept
$ sudo nft add rule inet filter input ip protocol icmp accept
$ sudo nft add rule inet filter input ip6 nexthdr icmpv6 accept

nftables 設定ファイル

# /etc/nftables.conf
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        # ループバックインターフェース
        iif lo accept

        # 確立済み接続
        ct state established,related accept

        # 不正なパケットを破棄
        ct state invalid drop

        # ICMPv4
        ip protocol icmp accept

        # ICMPv6
        ip6 nexthdr icmpv6 accept

        # SSH
        tcp dport 22 accept

        # HTTP/HTTPS
        tcp dport { 80, 443 } accept

        # ログしてドロップ
        log prefix "nft-drop: " counter drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

# NAT テーブル
table inet nat {
    chain prerouting {
        type nat hook prerouting priority -100;
    }

    chain postrouting {
        type nat hook postrouting priority 100;
        # マスカレード
        oif "eth0" masquerade
    }
}

6.4 セットとマップ

名前付きセット

# IPアドレスセットの作成
$ sudo nft add set inet filter allowed_ips { type ipv4_addr \; }

# セットに要素を追加
$ sudo nft add element inet filter allowed_ips { 192.168.1.10, 192.168.1.20, 10.0.0.0/24 }

# セットをルールで使用
$ sudo nft add rule inet filter input ip saddr @allowed_ips accept

# ポートセットの作成
$ sudo nft add set inet filter web_ports { type inet_service \; }
$ sudo nft add element inet filter web_ports { 80, 443, 8080, 8443 }
$ sudo nft add rule inet filter input tcp dport @web_ports accept

匿名セット(インラインセット)

# インラインで複数のポートを指定
$ sudo nft add rule inet filter input tcp dport { 22, 80, 443 } accept

# インラインで複数のIPを指定
$ sudo nft add rule inet filter input ip saddr { 192.168.1.0/24, 10.0.0.0/8 } accept

タイムアウト付きセット(動的セット)

# タイムアウト付きのブラックリストセット
$ sudo nft add set inet filter blacklist { type ipv4_addr \; timeout 1h \; }

# 動的にIPを追加(ルールから)
$ sudo nft add rule inet filter input tcp dport 22 ct state new meter ssh_bruteforce { ip saddr limit rate over 3/minute burst 5 packets } add @blacklist { ip saddr } drop

マップ

# DNAT マップの作成
$ sudo nft add map inet nat dnat_map { type inet_service : ipv4_addr \; }
$ sudo nft add element inet nat dnat_map { 80 : 192.168.1.100, 443 : 192.168.1.101, 8080 : 192.168.1.102 }

# マップをルールで使用
$ sudo nft add rule inet nat prerouting dnat to tcp dport map @dnat_map

# バーディクト(verdict)マップ
$ sudo nft add map inet filter port_policy { type inet_service : verdict \; }
$ sudo nft add element inet filter port_policy { 22 : accept, 80 : accept, 443 : accept }
$ sudo nft add rule inet filter input tcp dport vmap @port_policy

6.5 iptables からの移行

iptables-translate コマンド

# iptables ルールを nftables に変換
$ iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
nft add rule ip filter INPUT tcp dport 22 counter accept

$ iptables-translate -A INPUT -s 192.168.1.0/24 -p tcp --dport 80 -j ACCEPT
nft add rule ip filter INPUT ip saddr 192.168.1.0/24 tcp dport 80 counter accept

$ iptables-translate -t nat -A POSTROUTING -o eth0 -j MASQUERADE
nft add rule ip nat POSTROUTING oifname "eth0" counter masquerade

# ルールセット全体を変換
$ iptables-save | iptables-restore-translate > /etc/nftables.conf

移行時の注意点

# 1. iptables の互換レイヤーを確認
$ sudo iptables -V
iptables v1.8.7 (nf_tables)  # nf_tables バックエンド使用中

# 2. xtables-nft-multi の確認
$ ls -la /usr/sbin/iptables
lrwxrwxrwx 1 root root 26 Apr 10 10:00 /usr/sbin/iptables -> /etc/alternatives/iptables

# 3. 互換レイヤーの切り替え
$ sudo update-alternatives --config iptables

7. firewalld 詳細解説

7.1 ゾーンの概念

firewalld はゾーンベースのファイアウォール管理ツールである。各ネットワークインターフェースはゾーンに割り当てられる。

デフォルトゾーン

ゾーン説明デフォルト動作
drop全ての受信パケットを無言で破棄送信のみ許可
block全ての受信パケットを拒否(icmp-host-prohibited)送信のみ許可
public信頼されないネットワーク向けSSH, DHCPv6-client
externalマスカレード有効のNAT向けSSH
dmzDMZ サーバー向けSSH
work職場ネットワーク向けSSH, DHCPv6-client
homeホームネットワーク向けSSH, mDNS, Samba, DHCPv6-client
internal内部ネットワーク向けhome と同等
trusted全ての接続を許可全て許可

ゾーン管理コマンド

# デフォルトゾーンの確認
$ sudo firewall-cmd --get-default-zone
public

# アクティブゾーンの確認
$ sudo firewall-cmd --get-active-zones
public
  interfaces: eth0
internal
  interfaces: eth1

# 全ゾーンの一覧
$ sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work

# ゾーンの詳細情報
$ sudo firewall-cmd --zone=public --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: dhcpv6-client ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

# インターフェースのゾーン変更
$ sudo firewall-cmd --zone=internal --change-interface=eth1

# デフォルトゾーンの変更
$ sudo firewall-cmd --set-default-zone=public

# ソースベースのゾーン割り当て
$ sudo firewall-cmd --zone=trusted --add-source=192.168.1.0/24 --permanent

7.2 サービス管理

# 利用可能なサービス一覧
$ sudo firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client amqp amqps ... ssh ...

# サービスの追加(一時的)
$ sudo firewall-cmd --zone=public --add-service=http
success

# サービスの追加(永続的)
$ sudo firewall-cmd --zone=public --add-service=http --permanent
success

# 複数サービスの追加
$ sudo firewall-cmd --zone=public --add-service={http,https,dns} --permanent

# サービスの削除
$ sudo firewall-cmd --zone=public --remove-service=http --permanent

# ポート番号での追加
$ sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
$ sudo firewall-cmd --zone=public --add-port=5000-5100/tcp --permanent

# 設定のリロード
$ sudo firewall-cmd --reload

# カスタムサービスの作成
$ sudo firewall-cmd --permanent --new-service=myapp
$ sudo firewall-cmd --permanent --service=myapp --set-description="My Application"
$ sudo firewall-cmd --permanent --service=myapp --add-port=9090/tcp
$ sudo firewall-cmd --permanent --service=myapp --add-port=9091/tcp
$ sudo firewall-cmd --reload

カスタムサービス定義ファイル

<!-- /etc/firewalld/services/myapp.xml -->
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>MyApp</short>
  <description>My Custom Application</description>
  <port protocol="tcp" port="9090"/>
  <port protocol="tcp" port="9091"/>
  <port protocol="udp" port="9092"/>
</service>

7.3 リッチルール

リッチルールは、firewalld でより複雑なルールを定義するための機能である。

# 基本構文
# rule [family="ipv4|ipv6"]
#   [source address="address[/mask]" [invert="true"]]
#   [destination address="address[/mask]" [invert="true"]]
#   [service name="service"]
#   [port port="port" protocol="protocol"]
#   [log [prefix="prefix"] [level="level"] [limit value="rate/duration"]]
#   [audit]
#   [accept|reject|drop|mark]

# 特定IPからのSSHを許可
$ sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept' --permanent

# 特定IPからのアクセスを拒否
$ sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.100" drop' --permanent

# レート制限付きのSSH許可
$ sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" service name="ssh" accept limit value="3/m"' --permanent

# ログ付きのルール
$ sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="http" log prefix="HTTP-ACCESS: " level="info" accept' --permanent

# ポートフォワーディング
$ sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" forward-port port="80" protocol="tcp" to-port="8080" to-addr="192.168.1.100"' --permanent

# リッチルールの一覧
$ sudo firewall-cmd --zone=public --list-rich-rules

7.4 ダイレクトルール

ダイレクトルールは、firewalld を通じて iptables/nftables ルールを直接挿入する機能である。

# ダイレクトルールの追加
$ sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9999 -j ACCEPT

# 永続的なダイレクトルール
$ sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9999 -j ACCEPT

# ダイレクトルールの一覧
$ sudo firewall-cmd --direct --get-all-rules

# ダイレクトチェインの追加
$ sudo firewall-cmd --permanent --direct --add-chain ipv4 filter CUSTOM_CHAIN
$ sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -j CUSTOM_CHAIN
$ sudo firewall-cmd --permanent --direct --add-rule ipv4 filter CUSTOM_CHAIN 0 -s 192.168.1.0/24 -j ACCEPT

注意: ダイレクトルールは非推奨となりつつあり、リッチルールまたはポリシーの使用が推奨される。

7.5 firewall-cmd コマンド体系

主要コマンド一覧

# 状態確認
$ sudo firewall-cmd --state
running

# 設定リロード
$ sudo firewall-cmd --reload

# 完全リロード(接続も切断)
$ sudo firewall-cmd --complete-reload

# パニックモード(全通信遮断)
$ sudo firewall-cmd --panic-on
$ sudo firewall-cmd --panic-off
$ sudo firewall-cmd --query-panic

# マスカレード
$ sudo firewall-cmd --zone=external --add-masquerade --permanent

# ポートフォワーディング
$ sudo firewall-cmd --zone=external --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=192.168.1.100 --permanent

# ICMP ブロック
$ sudo firewall-cmd --zone=public --add-icmp-block=echo-request --permanent

# ランタイムからパーマネントへの移行
$ sudo firewall-cmd --runtime-to-permanent

8. 実践シナリオ

8.1 Web サーバーのファイアウォール構成

iptables での構成

#!/bin/bash
# Web サーバー用ファイアウォール設定スクリプト

# ルールのクリア
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

# デフォルトポリシー
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# ループバック
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# 確立済み接続
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

# SSH(管理ネットワークからのみ)
iptables -A INPUT -p tcp -s 10.0.0.0/8 --dport 22 -m conntrack --ctstate NEW -j ACCEPT

# HTTP/HTTPS
iptables -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW -j ACCEPT

# ICMP(制限付き)
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 4 -j ACCEPT

# SYN Flood 対策
iptables -A INPUT -p tcp --syn -m limit --limit 25/s --limit-burst 50 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

# HTTP スローロリス対策
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 50 -j DROP
iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 50 -j DROP

# ログ
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "IPT-DROPPED: " --log-level 4

# 保存
iptables-save > /etc/iptables/rules.v4

nftables での構成

#!/usr/sbin/nft -f
# Web サーバー用 nftables 設定

flush ruleset

table inet webserver {
    set admin_networks {
        type ipv4_addr
        flags interval
        elements = { 10.0.0.0/8 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        # ループバック
        iif lo accept

        # 確立済み接続
        ct state established,related accept
        ct state invalid drop

        # ICMPv4/v6
        ip protocol icmp limit rate 1/second burst 4 packets accept
        ip6 nexthdr icmpv6 accept

        # SSH(管理ネットワークのみ)
        tcp dport 22 ip saddr @admin_networks ct state new accept

        # HTTP/HTTPS
        tcp dport { 80, 443 } ct state new accept

        # SYN Flood 対策
        tcp flags syn limit rate 25/second burst 50 packets accept
        tcp flags syn drop

        # 接続数制限
        tcp dport { 80, 443 } ct count over 50 drop

        # ログ
        limit rate 5/minute log prefix "nft-drop: " counter drop
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

8.2 データベースサーバーのファイアウォール構成

#!/usr/sbin/nft -f
# データベースサーバー用 nftables 設定

flush ruleset

table inet dbserver {
    set app_servers {
        type ipv4_addr
        flags interval
        elements = {
            192.168.10.10,
            192.168.10.11,
            192.168.10.12
        }
    }

    set admin_networks {
        type ipv4_addr
        flags interval
        elements = { 10.0.0.0/24 }
    }

    set monitoring_servers {
        type ipv4_addr
        elements = { 10.0.1.50, 10.0.1.51 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        iif lo accept

        ct state established,related accept
        ct state invalid drop

        # SSH(管理ネットワークのみ)
        tcp dport 22 ip saddr @admin_networks accept

        # MySQL/MariaDB(アプリサーバーのみ)
        tcp dport 3306 ip saddr @app_servers accept

        # PostgreSQL(アプリサーバーのみ)
        tcp dport 5432 ip saddr @app_servers accept

        # MongoDB(アプリサーバーのみ)
        tcp dport 27017 ip saddr @app_servers accept

        # Redis(アプリサーバーのみ)
        tcp dport 6379 ip saddr @app_servers accept

        # 監視(SNMP, Node Exporter)
        udp dport 161 ip saddr @monitoring_servers accept
        tcp dport 9100 ip saddr @monitoring_servers accept

        # ICMP(管理ネットワークのみ)
        ip protocol icmp ip saddr @admin_networks accept

        # ログ
        log prefix "db-drop: " counter drop
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

8.3 マルチティアアーキテクチャのファイアウォール構成

[インターネット]
      │
  ┌───▼───┐
  │ FW-1  │ (フロントエンドファイアウォール)
  └───┬───┘
      │
  ┌───▼───────────┐
  │  DMZ 層        │ Web サーバー (192.168.1.0/24)
  │  nginx/Apache  │
  └───┬───────────┘
      │
  ┌───▼───┐
  │ FW-2  │ (内部ファイアウォール)
  └───┬───┘
      │
  ┌───▼───────────┐
  │  APP 層        │ アプリケーションサーバー (192.168.10.0/24)
  │  Java/Python   │
  └───┬───────────┘
      │
  ┌───▼───┐
  │ FW-3  │ (バックエンドファイアウォール)
  └───┬───┘
      │
  ┌───▼───────────┐
  │  DB 層         │ データベースサーバー (192.168.20.0/24)
  │  MySQL/PgSQL   │
  └─────────────┘

フロントエンドファイアウォール(FW-1)

#!/usr/sbin/nft -f
# FW-1: フロントエンドファイアウォール

flush ruleset

table inet fw1 {
    chain input {
        type filter hook input priority 0; policy drop;
        iif lo accept
        ct state established,related accept
        ct state invalid drop

        # 管理SSH
        tcp dport 22 ip saddr 10.0.0.0/24 accept

        # ICMP
        ip protocol icmp limit rate 2/second accept
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
        ct state invalid drop

        # インターネット → DMZ (HTTP/HTTPS のみ)
        iif "eth0" oif "eth1" tcp dport { 80, 443 } ct state new accept

        # DMZ → APP (特定ポートのみ)
        iif "eth1" oif "eth2" ip saddr 192.168.1.0/24 ip daddr 192.168.10.0/24 tcp dport { 8080, 8443 } accept

        # ログ
        log prefix "fw1-drop: " counter drop
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }

    # NAT
    chain prerouting {
        type nat hook prerouting priority -100;
        # 外部からの HTTP/HTTPS を Web サーバーに転送
        iif "eth0" tcp dport 80 dnat to 192.168.1.10:80
        iif "eth0" tcp dport 443 dnat to 192.168.1.10:443
    }

    chain postrouting {
        type nat hook postrouting priority 100;
        oif "eth0" masquerade
    }
}

内部ファイアウォール(FW-2)

#!/usr/sbin/nft -f
# FW-2: 内部ファイアウォール

flush ruleset

table inet fw2 {
    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
        ct state invalid drop

        # DMZ → APP (アプリケーションポートのみ)
        ip saddr 192.168.1.0/24 ip daddr 192.168.10.0/24 tcp dport { 8080, 8443 } accept

        # APP → DB (データベースポートのみ)
        ip saddr 192.168.10.0/24 ip daddr 192.168.20.0/24 tcp dport { 3306, 5432, 6379 } accept

        # APP → 外部 (API コール用)
        ip saddr 192.168.10.0/24 oif "eth0" tcp dport { 80, 443 } accept

        # DMZ からDB層への直接アクセスは禁止(暗黙のdrop)

        log prefix "fw2-drop: " counter drop
    }
}

9. トラブルシューティング

9.1 一般的な問題と対処法

ルールが効かない場合

# ルールの順序を確認(上から順に評価される)
$ sudo iptables -L -n -v --line-numbers
$ sudo nft list ruleset

# パケットカウンタを確認してルールにヒットしているか確認
$ sudo iptables -L -n -v | grep -i "dport 80"
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80

# カウンタが0の場合、ルールにマッチしていない

接続が切れる場合

# conntrack テーブルの確認
$ sudo conntrack -L | grep "dport=22"

# conntrack テーブルのサイズ確認
$ cat /proc/sys/net/netfilter/nf_conntrack_count
$ cat /proc/sys/net/netfilter/nf_conntrack_max

# conntrack テーブルが満杯の場合の対処
$ sudo sysctl -w net.netfilter.nf_conntrack_max=262144

NAT が動作しない場合

# IP フォワーディングの確認
$ cat /proc/sys/net/ipv4/ip_forward
0  # 0 の場合は無効

# 有効化
$ sudo sysctl -w net.ipv4.ip_forward=1

# NAT ルールの確認
$ sudo iptables -t nat -L -n -v
$ sudo nft list table inet nat

# FORWARD チェインのポリシー確認
$ sudo iptables -L FORWARD -n -v

9.2 デバッグツール

# パケットのトレース(TRACE ターゲット)
$ sudo iptables -t raw -A PREROUTING -p tcp --dport 80 -j TRACE
$ sudo iptables -t raw -A OUTPUT -p tcp --dport 80 -j TRACE

# ログの確認
$ sudo dmesg | tail -50
$ sudo journalctl -k -f

# nftables のカウンター
$ sudo nft list ruleset | grep -A2 "counter"

# tcpdump でパケットを確認
$ sudo tcpdump -i eth0 -n port 80
$ sudo tcpdump -i any -n host 192.168.1.100

# ss/netstat でリスニングポートを確認
$ sudo ss -tlnp
$ sudo netstat -tlnp

9.3 firewalld のトラブルシューティング

# firewalld のログレベルを上げる
$ sudo firewall-cmd --set-log-denied=all
# unicast, broadcast, multicast, off も指定可能

# firewalld のバックエンドを確認
$ grep FirewallBackend /etc/firewalld/firewalld.conf
FirewallBackend=nftables

# firewalld が生成したルールを確認
$ sudo nft list ruleset
# または(iptables バックエンドの場合)
$ sudo iptables -L -n -v

# firewalld のリロード
$ sudo firewall-cmd --reload

# firewalld の完全再起動
$ sudo systemctl restart firewalld

10. ベストプラクティス

10.1 一般的なセキュリティ原則

  1. 最小権限の原則: デフォルトで全てを拒否し、必要なものだけを許可する
  2. 深層防御: 複数のセキュリティ層を重ねる
  3. 監査可能性: 適切なロギングを設定し、定期的にレビューする
  4. 変更管理: ファイアウォールルールの変更は文書化し、テスト環境で検証する

10.2 iptables/nftables ベストプラクティス

# 1. デフォルトポリシーは DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP

# 2. ステートフルルールを最初に配置(パフォーマンス向上)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

# 3. ループバックを必ず許可
iptables -A INPUT -i lo -j ACCEPT

# 4. 頻繁にマッチするルールを上位に配置

# 5. カスタムチェインで整理
iptables -N SSH_RULES
iptables -A SSH_RULES -s 10.0.0.0/8 -j ACCEPT
iptables -A SSH_RULES -j DROP
iptables -A INPUT -p tcp --dport 22 -j SSH_RULES

# 6. スプーフィング対策
iptables -A INPUT -s 127.0.0.0/8 ! -i lo -j DROP
iptables -A INPUT -s 0.0.0.0/8 -j DROP
iptables -A INPUT -s 169.254.0.0/16 -j DROP
iptables -A INPUT -s 224.0.0.0/4 -j DROP
iptables -A INPUT -s 240.0.0.0/5 -j DROP

10.3 運用ベストプラクティス

  1. ルールのバックアップ: 変更前に必ず現在のルールをバックアップする
  2. リモートアクセスの保護: ファイアウォール変更時は at コマンドでルールリセットをスケジュール
  3. テスト手順: 変更後は必ず接続テストを実施
  4. 自動化: Ansible や Puppet 等の構成管理ツールでファイアウォールルールを管理する
  5. 監視: ファイアウォールログを SIEM に集約し、異常を検知する
# リモート作業時のセーフガード
# 5分後にルールをリセットするスケジュール
$ echo "iptables -F; iptables -P INPUT ACCEPT" | at now + 5 minutes

# ファイアウォールルールの変更を実施
$ sudo iptables -P INPUT DROP
# ...ルール追加...

# 接続が維持されていることを確認後、atジョブをキャンセル
$ atrm <job_number>

11. 比較表

11.1 iptables vs nftables vs firewalld

機能iptablesnftablesfirewalld
対象バージョンLinux 2.4+Linux 3.13+RHEL 7+ / Fedora 18+
IPv4/IPv6別コマンド統一統一
構文CLI引数独自言語CLI / GUI
セット機能ipset(別ツール)ネイティブゾーン/サービス
アトミック操作非対応対応対応
バックエンドnetfilternetfilteriptables/nftables
パフォーマンス線形評価最適化ありバックエンド依存
学習曲線中程度やや高い低い
柔軟性高い非常に高い中程度
推奨用途レガシー環境新規構築RHEL系サーバー

11.2 DROP vs REJECT

特性DROPREJECT
応答なし(無言で破棄)ICMPエラーまたはTCP RST
クライアント挙動タイムアウトまで待機即座にエラー
ポートスキャン対策filtered として表示closed として表示
帯域消費低い応答分の帯域が必要
推奨場面外部向け内部ネットワーク

12. 参考文献

  1. Netfilter プロジェクト公式: https://www.netfilter.org/
  2. nftables wiki: https://wiki.nftables.org/
  3. firewalld 公式ドキュメント: https://firewalld.org/documentation/
  4. iptables man page: man iptables, man iptables-extensions
  5. nftables man page: man nft
  6. Red Hat ファイアウォールガイド: https://access.redhat.com/documentation/
  7. Arch Linux Wiki - nftables: https://wiki.archlinux.org/title/Nftables
  8. Debian Wiki - nftables: https://wiki.debian.org/nftables
  9. CIS Benchmarks: https://www.cisecurity.org/cis-benchmarks
  10. NIST SP 800-41 Rev.1 - ファイアウォールとファイアウォールポリシーに関するガイドライン

本ドキュメントは 2026年4月時点の情報に基づいて作成されています。