CentOS 7 firewalld よく使うコマンド

CentOS 7ではファイアウォール(以下、FW)のサービスが `iptables` から `firewalld` に変わりました。
FWの設定は `firewall-cmd` コマンドを利用して行います。よく使うコマンドをまとめます。


<!-- ================================================================= -->
# サービスの起動／停止
`systemctl` コマンドを利用します。
サービス名は「bash-completion」がインストール済みの場合、[Tab]キーで補完可能です。
「.service」は省略可能です。

```console:サービスの起動
systemctl start firewalld.service
```
```console:サービスの停止
systemctl stop firewalld.service
```
```console:サービスの状態確認(systemctlの場合)
systemctl status firewalld.service
```
```console:サービスの状態確認(firewall-cmdの場合)
firewall-cmd --state
```


<!-- ================================================================= -->
# サービス自動起動の有効化／無効化
こちらも `systemctl` コマンドを利用します。
サービス名は「bash-completion」がインストール済みの場合、[Tab]キーで補完可能です。
「.service」は省略可能です。

```console:自動起動の有効化
systemctl enable firewalld.service
```
```console:自動起動の無効化
systemctl disable firewalld.service
```
```console:自動起動設定の状態確認
systemctl is-enabled firewalld.service
```


<!-- ================================================================= -->
# FWの用語


## インバウンド通信／アウトバウンド通信
FWには、インバウンドとアウトバウンドの概念があります。
インバウンド通信(以下、INPUT)とは、外部から内部への通信のことです。(外から来る通信)
アウトバウンド通信(以下、OUTPUT)とは、内部から外部への通信のことです。(外に出る通信)


## ゾーン
`firewalld`は、ゾーンという概念があります。
ゾーンがあることで、NICごとにFWの設定ができるようになります。
ゾーンごとにFWの設定を行い、NICに対してそのゾーンを割り当てて管理します。
ゾーンは標準で9つ用意されており、任意のゾーンを追加することも可能です。

そのため、FWの設定内容を確認する際は、ゾーンを指定する必要があります。
(指定しない場合は、デフォルト値となります。)

※`firewalld`では、ゾーンに対してはINPUTの設定となるため、OUTPUTの設定は行えません。
　そのため、OUTPUTの設定はダイレクトルールを利用する必要があります。


## ダイレクトルール
`firewalld`を介さずに`iptables`に設定値を直接書き込むためのルールです。
(`firewalld`も裏では`iptables`で動作しています。)

主にOUTPUTの設定を行う場合に利用します。
ゾーンに対しては、INPUTの設定のみでOUTPUTの設定を行うことができないためです。
ダイレクトルールで設定された内容は、ゾーンに関係なく適用されます。


## リッチルール
複雑なルールを設定する場合はリッチルールを利用します。
例えば、接続元IPアドレスとポート番号の組み合わせで制御したい場合等に利用します。
(例：接続元IP「192.168.11.2」のTCPポート80番(HTTP)へのアクセスを許可したい等)
リッチルールは、ゾーンに対しての設定となるため、INPUTの設定しかできません。


<!-- ================================================================= -->
# FW設定の状態確認


## ゾーンの割り当て状態

### アクティブゾーン
`--get-active-zones`オプションを指定することで、現在割り当てられているゾーン(以下、アクティブゾーン)を確認できます。

```console:アクティブゾーンの確認
# firewall-cmd --get-active-zones
public
  interfaces: ens160
```
上記の例では、「public」ゾーンが、NIC「ens160」に、割り当てられていることが確認できます。

### デフォルトゾーン
`--get-default-zone`オプションを指定することで、デフォルトで割り当てられるゾーン(以下、デフォルトゾーン)を確認できます。
NICに対して特にゾーンの割り当てがない場合は、デフォルトゾーンが割り当てられます。
また、コマンドでゾーンの指定が明示的に存在しない場合、デフォルトゾーンの値が利用されます。

```console:デフォルトゾーンの確認
# firewall-cmd --get-default-zone
public
```
特に何も設定をしなければ「public」がデフォルトゾーンかつアクティブゾーンとなります。


## FWの設定内容

`--list-all`オプションを指定することで現在のFW設定を確認できます。

### デフォルトゾーン
ゾーンを明示的に指定しない場合は、デフォルトゾーンの設定が出力されます。

```console:デフォルトゾーンのFW設定確認
firewall-cmd --list-all
```
<font color="OrangeRed">※デフォルトゾーンとアクティブゾーンが異なる場合はアクティブゾーンの設定を見るように促す注意書きが出力されます。
　現在の設定内容を確認する場合は、アクティブゾーンを明示的に指定する必要があります。
　他のコマンドを実行する際も同様に注意書きが出力されます。
</font>

```console:デフォルトゾーンが「home」
# firewall-cmd --get-default-zone
home
```

```console:アクティブゾーンが「public」
# firewall-cmd --get-active-zones
public
  interfaces: ens160
```

```console:注意書きが出力される
# firewall-cmd --list-all
You're performing an operation over default zone ('home'),
but your connections/interfaces are in zone 'public' (see --get-active-zones)
You most likely need to use --zone=public option.

home
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client mdns samba-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules: 
```

上記は、デフォルトゾーンが「home」、アクティブゾーンが「public」の例です。
現在の設定内容はアクティブゾーンである「public」を確認すべきであるため、注意書きが出力されています。

### 任意のゾーンのFW設定確認
`--zone`オプションを指定することで任意のゾーンのFW設定を確認できます。

```console:任意のゾーンのFW設定確認(homeの例)
# firewall-cmd --list-all --zone=home
home
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client mdns samba-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules: 
```

### すべてのゾーンのFW設定確認
`--list-all-zones`オプションを指定することですべてのゾーンのFW設定を確認できます。

```console:すべてのゾーンのFW設定を確認
firewall-cmd --list-all-zones
```


## 恒久的なFW設定の確認
`--permanent`オプションを指定することで、恒久的な設定を確認できます。
恒久的な設定とは、FW再読み込み、FW再起動、OS再起動後でも反映する設定のことです。
設定ファイルに記載する設定値のイメージです。
他のコマンドでも`--permanent`オプションの効果は同様です。

<font color="OrangeRed">※一時的に追加となった設定は確認できません。</font>

```console:デフォルトゾーンのFW設定確認(恒久的な設定のみ)
firewall-cmd --list-all --permanent
```
```console:任意のゾーンのFW設定確認(恒久的な設定のみ)
firewall-cmd --list-all --zone=home --permanent
```
```console:すべてのゾーンのFW設定確認(恒久的な設定のみ)
firewall-cmd --list-all-zones --permanent
```


<!-- ================================================================= -->
# FWの設定(INPUT)
ゾーンに対しての設定はINPUTの設定となります。


## サービス
ゾーンにサービスを追加することで、そのサービス用のFW設定が反映されます。

### サービスの定義ファイル
サービスのFW設定は、XMLファイルで定義されており、以下の場所に格納されています。
`/usr/lib/firewalld/services/`

例えば、以下は、ftpサービスの設定内容です。

```console:/usr/lib/firewalld/services/ftp.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>FTP</short>
  <description>FTP is a protocol used for remote file transfer. If you plan to make your FTP server publicly available, enable this option. You need the vsftpd package installed for this option to be useful.</description>
  <port protocol="tcp" port="21"/>
  <module name="nf_conntrack_ftp"/>
</service>
```
上記のXMLファイルの定義より、ftpサービスには以下の2つの設定が含まれていることが確認できます。

* TCP21番ポートへの通信許可
`<port protocol="tcp" port="21"/>`

* 「nf_conntrack_ftp」モジュールの有効化
`<module name="nf_conntrack_ftp"/>`

FTPは、上記のモジュールがないと動作しない場合があるため、ftpサービスとして追加する必要があります。

また、サービスは独自に作成することも可能です。
詳細は「[サービスの新規作成](#サービスの新規作成)」の章をご参照ください。

### 利用可能なサービスの確認
`--get-services`オプションを指定することで利用可能なサービス名一覧を確認できます。

```console:利用可能なサービスの確認
firewall-cmd --get-services
```

### 設定の確認
`--list-services`オプションを指定することでサービスの設定内容を確認できます。
※`--zone`オプションを省略した場合、デフォルトゾーンの設定が表示されます。
　ただし、アクティブゾーンとデフォルトゾーンが異なる場合は、注意書きが出力されます。

```console:現在の設定の確認
firewall-cmd --list-services --zone=public
```
```console:恒久的な設定の確認(現在設定されているとは限らない)
firewall-cmd --list-services --zone=public --permanent
```

### 許可サービスの追加
`--add-service`オプションを指定することで許可サービスを追加できます。
※`--zone`オプションを省略した場合、デフォルトゾーンに追加されます。

#### 一時的な設定
```console:許可サービスの追加(publicゾーンに対して、ftpサービスを追加する例)
firewall-cmd --add-service=ftp --zone=public 
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:許可サービスの追加(恒久的な設定)
firewall-cmd --add-service=ftp --zone=public --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```

### 許可サービスの削除
`--remove-service`オプションを指定することで許可サービスを削除できます。
※`--zone`オプションを省略した場合、デフォルトゾーンから削除されます。

#### 一時的な設定
```console:許可サービスの削除(publicゾーンに対して、ftpサービスを削除する例)
firewall-cmd --remove-service=ftp --zone=public
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:許可サービスの削除(恒久的な設定)
firewall-cmd --remove-service=ftp --zone=public --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```


## ポート番号

### ポート番号と名前の紐づけ定義ファイル
ポート番号は、サービス名で指定することができます。
サービス名とポート番号の紐付けは`/etc/services`に記載されています。

```console:/etc/services(postgresqlの例)
cat /etc/services | grep postgres
postgres        5432/tcp        postgresql      # POSTGRES
postgres        5432/udp        postgresql      # POSTGRES
```

### 設定の確認
`--list-ports`オプションを指定することでポート番号の設定内容を確認できます。
※`--zone`オプションを省略した場合、デフォルトゾーンの設定が表示されます。
　ただし、アクティブゾーンとデフォルトゾーンが異なる場合は、注意書きが出力されます。

```console:現在の設定の確認
firewall-cmd --list-ports --zone=public
```
```console:恒久的な設定の確認(現在設定されているとは限らない)
firewall-cmd --list-ports --zone=public --permanent
```

### 許可ポート番号の追加
`--add-port`オプションを指定することで許可ポート番号を追加できます。
※`--zone`オプションを省略した場合、デフォルトゾーンに追加されます。

#### 一時的な設定
```console:許可ポート番号の追加(TCP5432番、UDP60000番を追加する例)
firewall-cmd --add-port=postgres/tcp --add-port=60000/udp
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:許可ポート番号の追加(恒久的な設定)
firewall-cmd --add-port=postgres/tcp --add-port=60000/udp --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```

### 許可ポート番号の削除
`--remove-port`オプションを指定することで許可ポート番号を削除できます。
※`--zone`オプションを省略した場合、デフォルトゾーンから削除されます。

#### 一時的な設定
```console:許可ポート番号の削除(TCP5432番、UDP60000番を追加する例)
firewall-cmd --remove-port=postgres/tcp --remove-port=60000/udp
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:許可ポート番号の削除(恒久的な設定)
firewall-cmd --remove-port=8080/tcp --remove-port=60000/udp --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```


## IPアドレス

### 設定の確認
`--list-sources`オプションを指定することでIPアドレスの設定内容を確認できます。
※`--zone`オプションを省略した場合、デフォルトゾーンの設定が表示されます。
　ただし、アクティブゾーンとデフォルトゾーンが異なる場合は、注意書きが出力されます。

```console:現在の設定の確認
firewall-cmd --list-sources --zone=public
```
```console:恒久的な設定の確認(現在設定されているとは限らない)
firewall-cmd --list-sources --zone=public --permanent
```

### 許可IPアドレスの追加
`--add-source`オプションを指定することで許可IPアドレスを追加できます。
※`--zone`オプションを省略した場合、デフォルトゾーンに追加されます。

#### 一時的な設定
```console:許可IPアドレスの追加(publicゾーンに対して、192.168.0.0/24からのアクセスを許可する例)
firewall-cmd --add-source=192.168.0.0/24 --zone=public
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:許可IPアドレスの追加(恒久的な設定)
firewall-cmd --add-source=192.168.0.0/24 --zone=public --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```

### 拒否IPアドレスの追加
「drop」ゾーンに対してIPアドレスを追加することで拒否IPアドレスとなります。

#### 一時的な設定
```console:拒否IPアドレスの追加(192.168.11.0/24からのアクセスを拒否する例)
firewall-cmd --add-source=192.168.11.0/24 --zone=drop
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:拒否IPアドレスの追加(恒久的な設定)
firewall-cmd --add-source=192.168.11.0/24 --zone=drop --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```

### 許可/拒否IPアドレスの削除
`--remove-source`オプションを指定することで許可/拒否IPアドレスを削除できます。
※`--zone`オプションを省略した場合、デフォルトゾーンから削除されます。

#### 一時的な設定
```console:拒否IPアドレスの削除(192.168.11.0/24を削除する例)
firewall-cmd --remove-source=192.168.11.0/24 --zone=drop
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:拒否IPアドレスの削除(恒久的な設定)
firewall-cmd --remove-source=192.168.11.0/24 --zone=drop --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```


## リッチルール
IPアドレス、ポート番号の組み合わせで制御する場合は、リッチルールを利用します。

### リッチルールの書式
Red Hatのマニュアルがわかりやすいため、そちらをご参照ください。
[5.15. 「リッチ言語」構文を使用した複雑なファイアウォールルールの設定](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/security_guide/configuring_complex_firewall_rules_with_the_rich-language_syntax)

### 設定の確認
`--list-rich-rule`オプションを指定することでリッチルールの設定内容を確認できます。
※`--zone`オプションを省略した場合、デフォルトゾーンの設定が表示されます。
　ただし、アクティブゾーンとデフォルトゾーンが異なる場合は、注意書きが出力されます。

```console:現在の設定の確認
firewall-cmd --list-rich-rule --zone=public
```
```console:恒久的な設定の確認(現在設定されているとは限らない)
firewall-cmd --list-rich-rule --zone=public --permanent
```

### リッチルールの追加
`--add-rich-rule`オプションを指定することでリッチルールを追加できます。
※`--zone`オプションを省略した場合、デフォルトゾーンに追加されます。

#### 一時的な設定
```console:リッチルールの追加(192.168.11.2からTCP5432番へのアクセスを許可する例)
firewall-cmd --zone=public --add-rich-rule="rule family=ipv4 source address=192.168.11.2/24 port protocol=tcp port=postgres accept"
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:リッチルールの追加(恒久的な設定)
firewall-cmd --zone=public --add-rich-rule="rule family=ipv4 source address=192.168.11.2/24 port protocol=tcp port=postgres accept" --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```


<!-- ================================================================= -->
# FWの設定(OUTPUT)

ゾーンに対してはINPUTの設定となるため、OUTPUTの設定は行えません。
そのため、OUTPUTの設定はダイレクトルールを利用する必要があります。
ダイレクトルールはゾーンに関係なく適用されます。

## ダイレクトルール
`--direct`オプションを指定することでダイレクトルールの設定ができます。

### ダイレクトルールの書式
Red Hatのマニュアルがわかりやすいため、そちらをご参照ください。
[5.14. ダイレクトインターフェースの使用](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/security_guide/using_the_direct_interface)

また、`man`コマンドにてマニュアルをご参照ください。

```console:マニュアルの確認
man firewalld.direct
```

### 設定の確認
`--get-all-rules`オプションを指定することでダイレクトルールの設定内容を確認できます。

```console:現在の設定の確認
firewall-cmd --direct --get-all-rules
```
```console:恒久的な設定の確認(現在設定されているとは限らない)
firewall-cmd --direct --get-all-rules --permanent
```

恒久的なダイレクトルールの設定は以下のファイルにも書き込まれます。
`/etc/firewalld/direct.xml`

### ダイレクトルールの追加
`--add-rule`オプションを指定することでダイレクトルールを追加できます。

#### 一時的な設定
```console:ダイレクトルールの追加(192.168.11.2へのアクセスを遮断する例)
firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -m state --state NEW -d 192.168.11.2 -j DROP
```

※DROP：送信元にエラーを通知しない
　REJECT：送信元にエラーを通知する

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
`--add-rule`オプションよりも前に指定する必要があります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:ダイレクトルールの追加(恒久的な設定)
firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -m state --state NEW -d 192.168.11.2 -j DROP
```
```console:設定の再読み込み
firewall-cmd --reload
```

### ダイレクトルールの削除
`--remove-rule`オプションを指定することでダイレクトルールを削除できます。

#### 一時的な設定
```console:ダイレクトルールの削除
firewall-cmd --direct --remove-rule ipv4 filter OUTPUT 0 -m state --state NEW -d 192.168.11.2 -j DROP
```

#### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
`--remove-rule`オプションよりも前に指定する必要があります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:ダイレクトルールの削除(恒久的な設定)
firewall-cmd --permanent --direct --remove-rule ipv4 filter OUTPUT 0 -m state --state NEW -d 192.168.11.2 -j DROP
```
```console:設定の再読み込み
firewall-cmd --reload
```


<!-- ================================================================= -->
# ゾーンの変更


## アクティブゾーンの変更
`--change-interface`オプションを指定することでアクティブゾーンを変更できます。

### 一時的な設定
```console:アクティブゾーンの変更(ens160に対する割り当てをhomeに変更する例)
firewall-cmd --zone=home --change-interface=ens160
```

### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:アクティブゾーンの変更(恒久的な設定)
firewall-cmd --zone=home --change-interface=ens160 --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```


## デフォルトゾーンの変更
` --set-default-zone`オプションを指定することでデフォルトゾーンを変更できます。

### 一時的な設定
```console:デフォルトゾーンの変更(homeゾーンに変更する例)
firewall-cmd --set-default-zone=home
```

### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:デフォルトゾーンの変更(恒久的な設定)
firewall-cmd --set-default-zone=home --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```


## アクセス元IPアドレスのゾーンの変更
`--change-source`オプションを指定することで、すでに登録済みのIPアドレスのゾーンを変更できます。
`--get-zone-of-source`オプションを指定することで、アクセス元IPアドレスのゾーンを確認できます。

### 一時的な設定
```console:アクセス元IPアドレスに割り当てられているゾーンの変更(dropゾーンに変更の例)
firewall-cmd --change-source=192.168.11.0/24 --zone=drop
```
```console:アクセス元IPアドレスに割り当てられているゾーンの確認
# firewall-cmd --get-zone-of-source=192.168.11.0/24
drop
```

### 恒久的な設定
`--permanent`オプションを指定することで恒久的な設定となります。
ただし、反映には再読み込み(`--reload`オプション)が必要です。

```console:アクセス元IPアドレスに割り当てられているゾーンの変更(恒久的な設定)
firewall-cmd --change-source=192.168.11.0/24 --zone=drop --permanent
```
```console:設定の再読み込み
firewall-cmd --reload
```


<!-- ================================================================= -->
# サービスの新規作成

サービスは独自に作成することも可能です。
詳しくは、firewall-cmdのマニュアル(`man firewalld-cmd`)をご参照ください。
`--permanent` オプションは必須です。

`--new-service`オプションを指定するとサービスの設定ファイル(xml)が作成されます。
作成される場所は `/etc/firewalld/services/` の配下です。

```console:hogeサービス作成の例
# firewall-cmd --permanent --new-service hoge

# cat /etc/firewalld/services/hoge.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
</service>
```
※`/etc/firewalld/services/hoge.xml`が作成されます。

```console:既存のxmlファイルから作成する場合
# firewall-cmd --permanent --new-service-from-file=[filename] --name=[別名をつける場合]
```

```console:hogeサービスの説明文追加
# firewall-cmd --permanent --service=hoge --set-description=[説明文]
# firewall-cmd --permanent --service=hoge --set-short=[短い説明文]
```

```console:hogeサービスにFW設定追加の例
# firewall-cmd --permanent --service=hoge --add-port=2020/tcp
# firewall-cmd --permanent --service=hoge --add-source-port=60000-65000/udp
# firewall-cmd --permanent --service=hoge --set-destination=ipv4:192.168.0.1/24

# cat /etc/firewalld/services/hoge.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>[短い説明文]</short>
  <description>[説明文]</description>
  <port protocol="tcp" port="2020"/>
  <source-port protocol="udp" port="60000-65000"/>
  <destination ipv4="192.168.0.1/24"/>
</service>
```

```console:設定の再読み込み
# firewall-cmd --reload
```

```console:hogeサービスの削除
# firewall-cmd --permanent --delete-service=hoge
```