Ubuntuサーバーを守る基本のセキュリティ対策 ― UFWとFail2banをやさしく解説
Webシステムを公開するとき、アプリケーションの機能だけでなく、サーバーそのものをどう守るかも重要です。
特にインターネット上にあるVPSやクラウドサーバーは、公開しただけでさまざまなアクセスを受けるようになります。
そこでUbuntuサーバーを運用するときに、基本的なセキュリティ対策としてよく利用されるのが、
- UFW
- Fail2ban
- SSHの公開鍵認証
- VPN・Tailscaleなどによるアクセス制限
といった仕組みです。
今回はその中でも、Ubuntuで使いやすい UFWとFail2ban を中心に、「何をしている仕組みなのか」「なぜ必要なのか」を初学者向けに紹介します。
そもそもサーバーの「ポート」とは?
まず理解しておきたいのが「ポート」です。
サーバーでは、用途ごとに通信の入口となる番号が使われています。
代表的なものでは、
| ポート | 主な用途 |
|---|---|
| 22 | SSH |
| 80 | HTTP |
| 443 | HTTPS |
| 5432 | PostgreSQL |
| 6379 | Redis |
などがあります。
Webサイトを公開するのであれば80番や443番は必要ですが、PostgreSQLを外部から直接利用しないのであれば、5432番をインターネットに公開する必要はありません。
セキュリティの基本的な考え方はシンプルで、
「必要のない入口は、最初から開けない」
というものです。
そこで利用するのがファイアウォールです。
UFWとは?
UFWは Uncomplicated Firewall の略で、Ubuntuでファイアウォールを扱いやすくするための仕組みです。
Ubuntu公式ドキュメントでも、Ubuntuの標準的なファイアウォール管理ツールとしてUFWが案内されています。
イメージとしては、
インターネット
↓
┌─────────┐
│ UFW │
│ 門番 │
└────┬────┘
↓
Ubuntuサーバー
です。
UFWで、
この通信は通してよい
この通信は通してはいけない
というルールを決めます。
基本は「全部閉じて、必要なものだけ開ける」
サーバーのファイアウォールでは、
外部からの通信は基本的に拒否し、必要なものだけ許可する
という考え方が分かりやすいです。
例えば、
sudo ufw default deny incoming
sudo ufw default allow outgoing
と設定します。
それぞれの意味は次の通りです。
deny incoming
sudo ufw default deny incoming
外部からサーバーに入ってくる通信を、原則として拒否します。
つまり、
明示的に許可していない通信は入れない
という設定です。
allow outgoing
sudo ufw default allow outgoing
サーバーからインターネットへ出ていく通信は許可します。
例えば、
- Ubuntuのアップデート
- 外部APIへのアクセス
- パッケージのダウンロード
などに必要です。
必要なポートだけ許可する
例えば一般的なWebサーバーであれば、
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
と設定します。
これは、
80 → HTTPを許可
443 → HTTPSを許可
という意味です。
そしてSSHをインターネット経由で利用する場合は、
sudo ufw allow 22/tcp
などを追加します。
Ubuntu公式ドキュメントでも、UFWを使って特定ポートの許可・拒否を設定する方法が案内されています。
UFWを有効にする
ルールを設定したら、
sudo ufw enable
でUFWを有効化します。
現在の状態は、
sudo ufw status verbose
で確認できます。
例えば、
Status: active
To Action
22/tcp ALLOW
80/tcp ALLOW
443/tcp ALLOW
となっていれば、
SSH
HTTP
HTTPS
だけを許可している状態です。
SSH接続中のUFW設定には注意
ここは非常に重要です。
SSHでサーバーへ接続している状態で、
sudo ufw enable
としてしまい、その前にSSHを許可していなければ、
自分自身のSSH接続まで遮断してしまう可能性があります。
そのため、
sudo ufw allow OpenSSH
あるいは、
sudo ufw allow 22/tcp
などでSSHを許可してからUFWを有効にします。
セキュリティ設定では、
「強くすれば強くするほどよい」わけではありません。
運用方法を考えながら、安全に変更することが大切です。
Fail2banとは?
UFWが「入口を管理する門番」だとすれば、Fail2banは、
怪しいアクセスを検知して追い出す警備員
のような存在です。
例えばSSHをインターネットに公開すると、自動化されたプログラムから、
root
admin
ubuntu
test
といったユーザー名で大量のログイン試行が行われることがあります。
そこでFail2banはログを監視します。
SSHログイン失敗
↓
SSHログイン失敗
↓
SSHログイン失敗
↓
Fail2ban
↓
「このIPは怪しい」
↓
BAN
という仕組みです。
UFWとFail2banは役割が違う
この2つは似ているように見えますが、役割が違います。
| UFW | Fail2ban | |
|---|---|---|
| 主な役割 | 通信の許可・拒否 | 不審なアクセスを検知 |
| 判断するもの | ポート・IPなど | ログ・失敗回数など |
| 例 | 443番は許可 | SSH失敗5回でBAN |
| ブルートフォース対策 | 補助的 | 得意 |
例えばSSHについて、
UFWは、
22番ポートへの通信は許可
します。
しかしFail2banは、
このIPから短時間に何度もログイン失敗している
と判断した場合、そのIPを一時的に遮断します。
つまり、
UFW
「SSHの入口自体は使っていい」
↓
Fail2ban
「でも、この人は怪しいので入れない」
という関係です。
Fail2banをインストールする
Ubuntuでは例えば、
sudo apt update
sudo apt install fail2ban
でインストールできます。
設定を変更するときは、配布されている jail.conf を直接変更するより、
/etc/fail2ban/jail.local
などの .local ファイルにカスタム設定を書く方法が推奨されています。
これにより、パッケージのアップデート時にも設定を管理しやすくなります。
SSHをFail2banで保護する
例えば、
[sshd]
enabled = true
port = ssh
maxretry = 5
findtime = 10m
bantime = 1h
のような設定があります。
意味を分解してみましょう。
enabled
enabled = true
この監視ルールを有効にします。
maxretry
maxretry = 5
何回失敗したらBAN候補にするかを設定します。
ここでは5回です。
findtime
findtime = 10m
どのくらいの時間内の失敗を数えるかを設定します。
ここでは10分です。
bantime
bantime = 1h
BANする時間です。
ここでは1時間です。
つまり、
10分以内に
↓
SSHログインを5回失敗
↓
そのIPを1時間BAN
という設定になります。
なお、適切な回数や時間はシステムの利用方法によって異なります。厳しすぎる設定にすると正規ユーザーまで遮断する可能性があるため、運用に合わせた調整が必要です。
Fail2banの状態を確認する
Fail2ban全体の状態は、
sudo fail2ban-client status
で確認できます。
SSHについて確認する場合は、
sudo fail2ban-client status sshd
などを利用します。
さらに重要なのがSSHそのものの設定
ただし、Fail2banを入れればSSHが安全になるわけではありません。
より重要なのは、
SSHそのものへの侵入を難しくすること
です。
代表的なのが公開鍵認証です。
パスワード認証
ユーザー名
+
パスワード
ではなく、
公開鍵認証
秘密鍵を持つPC
↓
SSHサーバー
という仕組みにします。
適切に公開鍵認証を準備したうえで、運用要件に応じてパスワードログインを無効化することで、パスワードの総当たり攻撃に対する耐性を高められます。
Fail2banの公式SSHフィルターでも、公開鍵認証を準備してからパスワード認証を無効化する考え方が説明されています。
そもそもSSHを一般公開しない方法もある
さらに一歩進めると、
SSHの22番ポートそのものをインターネットへ公開しない
という方法があります。
例えばTailscaleなどのVPNを利用します。
一般インターネット
443 HTTPS
↓
Ubuntu Server
管理者PC
↓
Tailscale
↓
SSH
↓
Ubuntu Server
この構成では、
Webサイト → インターネット公開
SSH → VPN内部だけ
と分離できます。
Fail2banで攻撃者をBANすることも大切ですが、
攻撃対象となる入口自体を公開しない
という考え方は、さらに基本的な防御になります。
「多層防御」で考える
サーバーセキュリティでは、一つの仕組みにすべてを任せるのではなく、複数の対策を組み合わせます。
例えば、
① 不要なサービスを公開しない
↓
② UFWで通信を制限
↓
③ SSH公開鍵認証
↓
④ Tailscaleなどで管理経路を限定
↓
⑤ Fail2banで不審アクセスを遮断
↓
⑥ OSやパッケージを更新
といった形です。
これを「多層防御」として考えると分かりやすいでしょう。
一つ突破されても、次の仕組みで防御する考え方です。
Dockerを使っている場合は特に注意
最近のWebシステムではDockerを利用するケースも多くあります。
ここで注意したいのがポート公開です。
例えば、
docker run -p 3000:3000 ...
のように実行すると、IPアドレスを指定していない場合、Dockerは標準ではホストのすべてのインターフェースにポートを公開します。
そのため、
UFWで3000番を許可していない
↓
だから外部からアクセスできないはず
と単純に考えるのは危険です。
Docker公式ドキュメントでも、Dockerが作成するファイアウォールルールによって、公開したコンテナポートへの通信がUFWの通常の処理を迂回する場合があることが説明されています。
特に、
PostgreSQL
Redis
管理画面
内部API
などをDockerで動かしている場合は注意が必要です。
内部サービスはlocalhostに限定する
外部から直接アクセスする必要がないサービスであれば、
-p 127.0.0.1:3000:3000
のようにlocalhostへ限定する方法があります。
Docker公式ドキュメントでも、127.0.0.1 を指定した場合はホスト自身からのアクセスに限定できることが案内されています。
例えば、
Internet
↓ 443
Nginx
↓
127.0.0.1:3000
↓
Webアプリ
という構成にすれば、3000番ポートへ直接アクセスさせず、Webサーバーを経由させることができます。
セキュリティで大切なのは「設定すること」ではなく「理由を理解すること」
ここまでさまざまな設定を紹介しましたが、
UFWを入れたから安全
Fail2banを入れたから安全
というわけではありません。
大切なのは、
何を守るための設定なのかを理解すること
です。
例えば、
UFW
→ 不要な通信を減らす
Fail2ban
→ 不審なアクセスを自動的に遮断する
SSH公開鍵認証
→ 認証を強化する
Tailscale
→ 管理用の入口を一般公開しない
Dockerのポート制御
→ 意図しないサービス公開を防ぐ
というように、それぞれ違う役割があります。
私たちがシステム開発で意識していること
Webシステムのセキュリティというと、
- SQLインジェクション
- XSS
- 認証・認可
- APIのアクセス制御
といったアプリケーション側の対策が注目されがちです。
しかし実際のシステム運用では、
アプリケーションだけでなく、その下にあるサーバーやネットワークまで含めて考える必要があります。
例えば、
アプリケーション
├─ 認証・認可
├─ 入力値検証
└─ セキュアなAPI
インフラ
├─ UFW
├─ SSH
├─ Fail2ban
├─ VPN
└─ Dockerネットワーク
運用
├─ アップデート
├─ ログ監視
├─ バックアップ
└─ 権限管理
というように、複数の層があります。
私たちもシステムを構築する際には、単に「画面が動く」「機能が完成した」だけではなく、
公開範囲・アクセス経路・認証・サーバー設定・コンテナ設定・運用方法まで含めて、安全に運用できる構成を考える
ことを大切にしています。
まとめ
Ubuntuサーバーの基本的な防御を整理すると、
UFW
必要な通信だけを許可する「門番」。
Fail2ban
不審なアクセスを検知して一時的に遮断する「警備員」。
SSH公開鍵認証
サーバー管理者の認証を強化する仕組み。
TailscaleなどのVPN
管理用の入口を一般のインターネットから分離する仕組み。
と考えると分かりやすいでしょう。
重要なのは、
攻撃されたら防ぐ
だけではありません。
まず、
不要なものを公開しない
そして、
必要なものだけ許可する
さらに、
怪しいアクセスを検知する
という順番で考えることです。
セキュリティには「これを入れれば絶対に安全」というものはありません。
だからこそ、一つひとつの仕組みの役割を理解し、複数の対策を積み重ねていくことが、安全なシステム運用につながります。