UbuntuでのIPアドレス・ポート制限

## はじめに
Ubuntuのファイアウォールの設定をしたことがなかったので、想定通りの挙動になるのかコマンドの確認を行った。

## 環境
【ホストOS】
　・Ubuntu 18.04 LTS（GCP上）


## IPアドレス・ポート制限の設定方法

１．ローカルPCから各ポートへの接続確認
２．`ufw`コマンドを使ったファイアウォール設定
３．`/etc/hosts.allow`と`/etc/hosts.deny`を使った接続制限

## １．ローカルPCから各ポートへの接続確認

まずはローカルPCから各サービスにアクセスできる様にしておく。


　・SSH接続（デフォルトport:22）
　　　※GCPのVMインスタンスへのSSH接続は[こちら](https://qiita.com/smiler5617/items/34626dfd74c5eefcd885)を参考に
　・httpアクセス（port:80）

**※事前準備**
・GCP上のファイアウォール設定からローカルPCのグローバルIPに対する上記ポート接続を許可する。
・httpアクセス確認のために、以下を実行。

```shell:
# パッケージ管理ツールを最新にアップデート
$ sudo apt update
$ sudo apt -y upgrade

# Apacheのインストール
$ sudo apt install -y apache2
```



## ２．`ufw`コマンドを使ったファイアウォール設定

デフォルトのファイアウォールの状態を確認

```shell:
$ sudo ufw status
Status: inactiveufw status
```

　⇒デフォルトでは非アクティブとなっている。


まず、SSHの接続は許可して、ファイアウォールを有効化してみる。

```shell:
$ sudo ufw allow ssh
Rule added
Rule added (v6)
# sudo ufw allow 22　← こちらのコマンドでも同じ

$ sudo ufw enable
Rule added

$ sudo ufw status
Status: active
To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
22/tcp (v6)                ALLOW       Anywhere (v6) 
```
※デフォルトは`all deny`になっているため、何もIPやポートの設定をしないで有効化してしまうと入れなくなる可能性があるので注意。

この状態でhttpにアクセスしようとすると、もちろんできなくなっている。

再起動を行うと、この設定は効いたままになるのか？

```shell:
# 再起動後にステータス確認
$ sudo ufw status
Status: active
To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
22/tcp (v6)                ALLOW       Anywhere (v6)         
```
再起動してもルールがなくなってしまうという事はなさそう。

特定のIPアドレスのみ通信を許可する書き方。

```shell:
$ sudo ufw allow from xxx.xxx.xxx.xxx to any port 22
Rule added

$ sudo ufw reload
Firewall reloaded

$ sudo ufw status
Status: active
To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
22/tcp                     ALLOW       xxx.xxx.xxx.xxx        
22/tcp (v6)                ALLOW       Anywhere (v6) 
```

ルール削除の書き方。

```shell:
$ sudo ufw delete allow from xxx.xxx.xxx.xxx to any port ssh
# ネットワークレベルで許可したい場合は、[from xxx.xxx.xxx.0/24 to] の様な書き方でOK。 
Rule deleted

$ sudo ufw status
Status: active
To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
22/tcp (v6)                ALLOW       Anywhere (v6) 
```

## ３．`/etc/hosts.allow`と`/etc/hosts.deny`を使った接続制限


基本的にはスーパーデーモン（xinetd）経由で起動されるデーモンへのアクセス制御をするため、TCP Wrapper（tcpdデーモン）がクライアントのサービス接続許可情報を確認するのに`/etc/hosts.allow`と`/etc/hosts.deny`のホストアクセスファイルを参照している。
しかし、「sshd」などスーパーデーモンを経由しないものでもアクセス制御を行えるものがある。

※inetd（xinetd）が各デーモンを呼び出す前にアクセス許可と不許可とのリスト（/etc/hosts.allow、/etc/hosts.denyファイル)を参照し、許可されていれば該当デーモンを起動させている。
inted自体はアクセス制御の機能を持っていないので、このtcpdと組み合わせてアクセス制御を行っていた。ただし、tcpdのアクセス制御は、接続先のIPアドレスのみによるものであり、さらに、inetd経由で使用されるTCPポートしか監視することはできなかった。
そのため、tcpdのアクセス制御はかなり限定されており、よりきめ細かな設定を行うことができるスーパーサーバとして、xinetdが利用されるようになってきた。

　

ルールは以下の感じらしい。

**（１） `/etc/hosts.allow` に記述されたホストからのアクセスを許可
（２）１に該当しなかった場合、`/etc/hosts.deny`に記述されたホストからのアクセスを拒否
（３）１にも２にも該当しなかった場合、アクセスはすべて許可**


#### SSH接続

試しにSSHの接続設定を以下の様にしたら、ローカルPCから接続できなくなるのか確認。

```shell:/etc/hosts.allow
ALL  127.0.0.1
```

```shell:/etc/hosts.deny
sshd : 【ローカルPCのグローバルIP】

# Webサービスは接続できない状態の記述イメージ
httpd : ALL
apache2 : ALL
```
特にサービスや**システムの再起動なく**、ローカルPCからの接続ができなくなった。
　※ファイアウォールで切られているわけではないので、ユーザ入力やパスフレーズ入力まではいくが、その後接続の確立が上手くいかない。


以下の様に`/etc/hosts.allow`を編集したら、ローカルPCから接続できる様になるのか確認。

```shell:/etc/hosts.allow
ALL  127.0.0.1
sshd :【ローカルPCのグローバルIP】
```

想定通り、SSH接続はできる様になった。


#### http接続

上記設定の状態でhttp接続も同じように確認してみると、こちらは見れる状態となっている。

理由は、TCP Wrapper が制御対象とするサービスは「TCP でラップしたサービス」であり、httpサービスはそこに含まれていないため。

（参考１）https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-tcp_wrappers_and_xinetd-tcp_wrappers_configuration_files

（参考２）https://nwengblog.com/rhel-tcpwrapper/


#### 補足

TCPでラップされているサービスは以下の様に調べる事が可能。

```shell:
# sshd サービスについて確認する場合
$ ldd /usr/sbin/sshd | grep libwrap
        libwrap.so.0 => /lib/x86_64-linux-gnu/libwrap.so.0 (0x00007f0cb589d000)

# apache2 サービス(http)について確認する場合
$ ldd /usr/sbin/apache2 | grep libwrap
  # 出力なし。
```

　※ライブラリ毎に設定しているため、一覧として確認することは難しそう。