失敗ログイン (lastb) の IP アドレスを一括拒否

CentOS 7 で `btmp` (`lastb`) のログから一括で IP 制限をかける方法のまとめ。

なお、 `tcp_wrappers` は RHEL 7.5 から非推奨化された。 [^tcp_wrappers]

[^tcp_wrappers]: ["tcp_wrappers パッケージが非推奨となりました。" - 第40章 非推奨の機能 - Red Hat Customer Portal](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/7.5_release_notes/chap-red_hat_enterprise_linux-7.5_release_notes-deprecated_functionality#idm140470062061648)

## 失敗ログインの試行回数通知メッセージ
```
最後の正しいログインの後に N 回の失敗ログインの試行があります
```
```
There was N failed login attempt since the last successful login.
```
失敗ログインの試行があると、ログイン時に上記のメッセージが表示される。

## 不正アクセスの試行ユーザー名ランキング
```bash
lastb -i \
| head --lines=-2 \
| awk '{print $1}' \
| sort \
| uniq --count \
| sort --reverse \
| less
```
```:出力例
    987 admin
    654 user
    321 www
```
SCP 接続等を許可していた場合など、誤って正規の失敗ログインの IP アドレスを拒否してはいけないので、失敗ログインの試行ユーザーを確認する。

### 各コマンドの解説

#### `lastb`
```bash
lastb -i
```
```:出力例
admin    ssh:notty    192.0.2.1     Mon Jul  1 00:00 - 00:00  (00:00)
user     ssh:notty    198.51.100.1  Mon Jul  1 00:00 - 00:00  (00:00)
www      ssh:notty    203.0.113.1   Mon Jul  1 00:00 - 00:00  (00:00)

wtmp begins Thu Jun 1 00:00:00 1970
```
すべての不正なログイン試行が含まれる `/var/log/btmp` ファイルのログをデフォルトで表示する。それ以外は `last` コマンドと同じである。

#### `head --lines=-2`
`head` コマンドはファイルの最初の部分を出力する。

`--lines=` または `-n` オプションを指定すると出力する行数を制限できる。マイナス値を指定するとファイルの最後からの行数を減らせる。

上述の通り `lastb` コマンドは最後にログの開始日時が出力されてしまうため、 `--lines=-2` を指定することで最後の2行を除去する。

#### `awk '{print $1}'`
1列目を抽出する。

#### `sort`
`uniq` コマンドで集計する際に事前に並び替えする必要がある。

#### `uniq --count`
`--count` または `-c` オプションにより同一の行をカウントして数を出力する。

#### `sort --reverse`
`--reverse` または `-r` オプションを指定すると降順になる。

#### `less`

## 不正アクセスの IP アドレスランキング
```bash
lastb -i \
| head --lines=-2 \
| awk '{print $3}' \
| sort \
| uniq --count \
| sort --reverse \
| less
```
```:出力例
    987 192.0.2.1
    654 198.51.100.1
    321 203.0.113.1
```

## 失敗ログインの IP アドレスの一括拒否設定

[5.12. firewalld を使用した IP セットの設定および制御 - Red Hat Customer Portal](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/security_guide/sec-setting_and_controlling_ip_sets_using_firewalld)

### 新しい IP セットの作成
```bash
firewall-cmd --permanent --new-ipset=blacklist --type=hash:net
```
```:出力例
success
```
`hash:ip` は `hash:net` に包含されるので指定しない。

### IP セットの一覧
```bash
firewall-cmd --permanent --get-ipsets
```
```:出力例
blacklist
```

### IP セットの詳細
```bash
firewall-cmd --permanent --info-ipset=blacklist
```
```:出力例
blacklist
  type: hash:net
  options:
  entries:
```

### 拒否する IP アドレス一覧ファイルの作成
```bash
lastb -i | head --lines=-2 | awk '{print $3}' | sort | uniq | sort --numeric-sort > /etc/firewalld/ipsets/blacklist
```

### 拒否する IP アドレス一覧ファイルの登録
```bash
firewall-cmd --permanent --ipset=blacklist --add-entries-from-file=/etc/firewalld/ipsets/blacklist
```
設定は `/etc/firewalld/ipsets/<ipset>.xml` に保存される。

### IP セットの詳細の再確認
```bash
firewall-cmd --permanent --info-ipset=blacklist
```
```:出力例
blacklist
  type: hash:net
  options:
  entries: 192.0.2.1 198.51.100.1 203.0.113.1
```

### IP セットによる拒否設定
```bash
firewall-cmd --permanent --zone=public --add-rich-rule='rule source ipset=blacklist drop'
```
```:出力例
success
```

### リロードと反映確認
```bash
firewall-cmd --reload && \
firewall-cmd --list-rich-rules
```
```:出力例
success
rule source ipset="blacklist" drop
```