SELinuxとFirewallを有効にしたまま443でsshを受けるように設定する

# 1. はじめに
443ポートを使ってssh接続したいことがある。クライアント側はSSHクライアントソフトウェアでポート変更するだけでよいが、サーバ側は手順が複雑になる。少なくともGUIツール上でポート番号を変えるだけと言うことはない。

また、SELinuxやFirewall（ここではfirewalldやiptablesなどのソフトウェア実装を指している）がデフォルトで有効になっている。SELinuxやFirewallを有効にするかどうかは別の議論として、有効にして難易度が高くなったときの手段を知っていて損はないだろう。そこで今回は共に有効にしたまま設定する方法を説明する。

なおSELinuxやFirewallを有効にするかべきかは、別エントリに書いた。

* [SELinuxやFirewallは正義か？](https://qiita.com/yamada-hakase/items/02c7ede6c8c0dd31a0b5)

### 1-1. 利用環境

* RHEL5/6/7/8/9および互換ディストリビューション

### 1-2. 設定手順
設定する手順は以下の通り。6系と7系以降で操作が異なるところは別に説明している。

1. SELinuxを設定する
2. Firewallを設定する
3. sshdを設定する

# 2. SELinuxを設定する

**参考資料**

* [8系: SELinuxの使用](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/using_selinux/index)
* [7系: SELinux ユーザーおよび管理者のガイド ](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/)
* [6系: RHEL 
Security-Enhanced Linuxマニュアル](https://access.redhat.com/site/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Security-Enhanced_Linux/index.html)

### 2-1. SELinuxが有効化されているか確認する
現在のステータスを確認すると```Enforcing```なのでSELinuxは有効になっている。無効のときは```Permissive```もしくは```Disabled```だ。

```shell-session
# getenforce
Enforcing
```

こちらのコマンドを使うと、もっと細かい情報を表示できる。

```shell-session
# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      31
```

当然設定ファイルの内容も```enforcing```になっている。

```shell-session
$ grep ^SELINUX= /etc/selinux/config
SELINUX=enforcing
```

**ヒント**
SELinuxのモードを永続的に変更するにはOSを再起動する必要がある。しかし```setenforce　0```を使うと、動的にpermissiveモードに変更できる。ベアメタルサーバなどOSの再起動に時間のかかるときには便利だ。ただし永続的に変更するには設定ファイル`/etc/selinux/config`も変更する必要がある。

### 2-2. SELinuxのポート設定を確認する

SELinuxで443ポートがどのように設定されているか確認する。```http_port_t```になっているので、Webサーバ（httpd）用に設定されている。

```shell-session
# semanage port -l | grep 443
http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000★
pki_ca_port_t                  tcp      829, 9180, 9701, 9443-9447
pki_kra_port_t                 tcp      10180, 10701, 10443-10446
pki_ocsp_port_t                tcp      11180, 11701, 11443-11446
pki_tks_port_t                 tcp      13180, 13701, 13443-13446
```

### 2-3. 443ポートをsshd用に変更する
443ポートをsshd用に変更する。

```shell-session
# semanage port -m -t ssh_port_t -p tcp 443
```

確認するとsshd用に設定が変更されている。

```shell-session
# semanage port -l | grep 443

http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000
pki_ca_port_t                  tcp      829, 9180, 9701, 9443-9447
pki_kra_port_t                 tcp      10180, 10701, 10443-10446
pki_ocsp_port_t                tcp      11180, 11701, 11443-11446
pki_tks_port_t                 tcp      13180, 13701, 13443-13446
ssh_port_t                     tcp      443, 22 ★追加された
```

次にFirewallの設定をする。

# 3. Firewallを設定する

RHEL5/6系とRHEL7/8/9系では、Firewallの設定方法がまったく違うので、それぞれ説明する。

**参考資料：**

* [7系: ファイアウォールの使用](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/security_guide/sec-using_firewalls)
* [6系: IPTABLES の使用](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-firewalls-using_iptables)


### 3-1. RHEL7/8/9系（firewalld）の場合

#### firewalldの設定を確認する
firewalldが起動していることを確認する。```active```なので有効化されている。

```shell-session
# systemctl is-active firewalld
active
```

設定を確認すると、いくつかのポートが開いていることがわかる。しかしhttps/443は開いていない。

```shell-session
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources:
  services: ssh dhcpv6-client ★
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
```

#### firewalldの443ポートを開ける
開いていないので443ポートを開ける。ここでは`--add-port=443/tcp`でポートを開けている。`--add-service=https`でも結果は同じだが、ポート番号がわかりやすく応用も利くポート番号指定にした。

```shell-session
# firewall-cmd --add-port=443/tcp  --permanent --zone=public
```

:::note info
`--add-service`で指定できるサービスのリストは`firewall-cmd --get-list`コマンドで表示できる。また、サービス名に対するポート番号は
`cat /usr/lib/firewalld/services/ssh.xml`
のようにXMLファイルで確認できる。sshの部分を他のサービス名に置き換えればよい。

:::


リロードして設定を有効化する。

```shell-session
# firewall-cmd --reload
success
```

再び設定を確認すると443ポートが空いていることがわかる。次はsshdの設定だ。

```shell-session
# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources:
  services: ssh dhcpv6-client
  ports: 443/tcp ★これ
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
```

### 3-2. RHEL5/6（iptables）の場合

#### iptablesの設定を確認する

iptablesが起動していることを確認する。このようにズラッと表示されれば起動している。

```shell-session
# service iptables status
テーブル: filter
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
2    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
★以下省略
```

iptablesの設定を確認する。重要なINPUTチェーンだけを表示すると、icmpと22ポートだけが開いていて、443ポートは開いていない。

```shell-session
# iptables -L INPUT --line-number
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
2    ACCEPT     icmp --  anywhere             anywhere
3    ACCEPT     all  --  anywhere             anywhere
4    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
5    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited
★以下省略
```

#### iptablesの443ポートを開ける
開いていないので443ポートを開ける。

```shell-session
# iptables -I INPUT 5 -p tcp --dport 443 -j ACCEPT
```

再び設定を確認すると、INPUTチェーンの最後から2行目に設定が追加され、https/443ポートが開いていることがわかる。

```shell-session
# iptables -L INPUT --line-number
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
2    ACCEPT     icmp --  anywhere             anywhere
3    ACCEPT     all  --  anywhere             anywhere
4    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
5    ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:https★
6    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited
```

変更内容を保存する。すると設定は```/etc/sysconfig/iptables```に保存される。以上でiptablesは終了である。

```shell-session
# service iptables save
```

# 4. sshdを設定する

### 4-1. sshdのリスニングポートを追加する
デフォルトでは22ポートをリスニングしているので、443ポートも追加する。その前に設定ファイルをバックアップする。

```shell-session
# cp -f /etc/ssh/sshd_config /etc/ssh/sshd_config-`date +%Y%m%d`
# sed -i -e "s/\#*Port 22/Port 22\nPort 443/" /etc/ssh/sshd_config
```

次のように表示されれば、リスニングポートとして22と443が設定されている。

```shell-session
# grep ^Port /etc/ssh/sshd_config
Port 22
Port 443
```

### 4-2. sshdを再起動して有効化する

sshdを再起動して設定を有効化する。

* RHEL7/8/9系の場合

```shell-session
# systemctl restart sshd
```

* RHEL5/6系の場合

```shell-session
# service sshd restart
```

以上で設定はすべて終了した。実際にsshクライアントから接続できるか確認してほしい。

# 5. まとめバージョン
コピペで一括実行できるように、まとめバージョンも紹介する。

### RHEL7/8/9系

```shell-session
# 443/tcpをssh用に変更
semanage port -m -t ssh_port_t -p tcp 443

# 443ポートを開放
firewall-cmd --add-port=443/tcp  --permanent --zone=public

# firewalldの設定を有効化
firewall-cmd --reload

# sshdのリスニングポートに443を追加。元ファイルは.bakを付けてバックアップ
sed -i".bak" -e "s/\#*Port 22/Port 22\nPort 443/" /etc/ssh/sshd_config

# sshdを再起動して443ポートを有効化
systemctl restart sshd
```


### RHEL5/6系

```shell-session
# 443/tcpをssh用に変更
semanage port -m -t ssh_port_t -p tcp 443

# 443ポートを開放
iptables -I INPUT 5 -p tcp -m state --state NEW --dport 443 -j ACCEPT

# iptablesの設定を保存
service iptables save

# sshdのリスニングポートに443を追加。元ファイルは.bakを付けてバックアップ
sed -i".bak" -e "s/\#*Port 22/Port 22\nPort 443/" /etc/ssh/sshd_config

# sshdを再起動して443ポートを有効化
service sshd restart
```