ラズパイにファイアウォールを設定する(ufw)

# ufwをインストール
Debian系だと、`iptables`や`firewalld`ではなく、`ufw`を使ってファイアウォール設定をするようである。
以下のコマンドでインストール。
```
# apt -y install ufw
```
ufwが死んだ状態になってること。まだ起動させない。
```
# systemctl status ufw
● ufw.service - Uncomplicated firewall
     Loaded: loaded (/lib/systemd/system/ufw.service; enabled; vendor preset: enabled)
     Active: inactive (dead) since Tue 2023-01-03 15:15:28 JST; 3s ago
       Docs: man:ufw(8)
    Process: 15328 ExecStart=/lib/ufw/ufw-init start quiet (code=exited, status=0/SUCCESS)
    Process: 15754 ExecStop=/lib/ufw/ufw-init stop (code=exited, status=0/SUCCESS)
   Main PID: 15328 (code=exited, status=0/SUCCESS)
        CPU: 15ms
```
自動起動設定を確認。デフォルトでenabledになっていた。
```
# systemctl is-enabled ufw
enabled
```


# ファイアウォールを設定する
ufwはコマンドで許可・遮断の設定を入れていくみたい。

受信パケットをすべて遮断。
まず、一旦すべて遮断させてから、公開するものだけ開けていく。
```
# ufw default deny incoming
Default incoming policy changed to 'deny'
(be sure to update your rules accordingly)
```
送信パケットはすべて許可。
```
# ufw default allow outgoing
Default outgoing policy changed to 'allow'
(be sure to update your rules accordingly)
```
ssh(22)のみ許可。
```
# ufw allow ssh
Rules updated
Rules updated (v6)
```
`ufw allow 22/tcp`でも良さそう。
sshポートを変更している場合は、22を別のポート番号に変えてあげればよし。
sshに限らず、同じようにポート単位で許可させていく。

ちなみに、設定は`user.rules`に追記されていくようである。
```
# cat /etc/ufw/user.rules 
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
### tuple ### allow tcp 22 0.0.0.0/0 any 0.0.0.0/0 in
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
```

# 設定を反映させる（プロセスの起動も）
プロセスを起動させる。
```
# systemctl start ufw
# systemctl status ufw
● ufw.service - Uncomplicated firewall
     Loaded: loaded (/lib/systemd/system/ufw.service; enabled; vendor preset: enabled)
     Active: active (exited) since Tue 2023-01-03 15:24:24 JST; 3s ago
       Docs: man:ufw(8)
    Process: 16505 ExecStart=/lib/ufw/ufw-init start quiet (code=exited, status=0/SUCCESS)
   Main PID: 16505 (code=exited, status=0/SUCCESS)
        CPU: 9ms

 1月 03 15:24:24 raspberrypi systemd[1]: Starting Uncomplicated firewall...
 1月 03 15:24:24 raspberrypi systemd[1]: Finished Uncomplicated firewall.
```
設定を有効にする。
```
# ufw enable 
Firewall is active and enabled on system startup
```
設定を確認する。
`verbose`をつけると、Defaultを見てたりするので、つけておけば良さそう。
```
# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere                  
22/tcp (v6)                ALLOW IN    Anywhere (v6)      
```
なお、プロセス起動していた場合は、`ufw reload`で設定反映できるようである。

# SSH接続できることを確認
```
% ssh k-natsume@192.168.0.254 -i id_ecdsa
```

# 設定を削除する
deleteで削除できる。
```
# ufw delete allow 22/tcp
Rule deleted
Rule deleted (v6)
```
消えていることを確認。
```
# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
```

# 指定して削除する
１つ１つの設定に番号が割り振られているので、それを指定して削除する方法。
まず、設定の番号を確認する。
```
# ufw status numbered 
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere                  
[ 2] 22                         ALLOW IN    192.168.0.0/24            
[ 3] 22/tcp (v6)                ALLOW IN    Anywhere (v6)             
```
2番目の設定を削除する。
```
# ufw delete 2
Deleting:
 allow from 192.168.0.0/24 to any port 22
Proceed with operation (y|n)? y       
Rule deleted
```
削除されたことを確認。
```# ufw status numbered 
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    Anywhere                  
[ 2] 22/tcp (v6)                ALLOW IN    Anywhere (v6)             
```

# セグメントを指定して許可させる
```
# ufw allow from 192.168.0.0/24 to any port 22
Rule added
```
セグメント単位で許可できた。
```
# ufw status numbered 
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22                         ALLOW IN    192.168.0.0/24  
```

# 総当り攻撃(ブルートフォース攻撃)対策
総当り攻撃を対策するため、試行回数に制限をかける。
デフォルトだと30秒に６回になっているらしい。
```
# ufw limit 22/tcp
Rule updated
Rule updated (v6)
```
設定を確認。ActionがLIMITに変わっていることが分かる。
```
# ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT       Anywhere                  
22/tcp (v6)                LIMIT       Anywhere (v6)  
```
こちらもセグメントを指定させることもできる。
```
# ufw limit from 192.168.0.0/24 to any port 22
Rule updated
# ufw status numbered 
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22                         LIMIT IN    192.168.0.0/24   
```

# ICMP拒否
バックアップを取ってから編集する。
```
# cp -p /etc/ufw/before.rules /etc/ufw/before.rules.org
# vi /etc/ufw/before.rules 
```
```diff:
# ok icmp codes for INPUT
- #-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
- #-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
- #-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
- #-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT

# ok icmp code for FORWARD
- #-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT
- #-A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT
- #-A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT
- #-A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT
# ok icmp codes for INPUT
+ -A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP
+ -A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP
+ -A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP
+ -A ufw-before-input -p icmp --icmp-type echo-request -j DROP

# ok icmp code for FORWARD
+ -A ufw-before-forward -p icmp --icmp-type destination-unreachable -j DROP
+ -A ufw-before-forward -p icmp --icmp-type time-exceeded -j DROP
+ -A ufw-before-forward -p icmp --icmp-type parameter-problem -j DROP
+ -A ufw-before-forward -p icmp --icmp-type echo-request -j DROP
```
設定変更したら、設定反映。
```console
# ufw reload
Firewall reloaded
```