はじめに
前回の続き。Linuxサーバ運用上の注意を述べましたが、更に難易度が上がり
「このLinuxサーバをインターネットで公開するとき」
の心構えについて述べます。
絶対的な違い:「インターネット上サーバの理不尽な非対称性」
そもそも、ローカル環境とインターネットにこれを公開するというのは
- 技術
- 倫理観
- 運用の手間
が何もかも違います。その中で一番気をつけなければならないのは
「自分自身が加害者になってしまうこと」
です。これはもっと具体的に言うと
「管理者権限を乗っ取られ、自分のサーバが攻撃ツールのフロントエンド/バックエンドとして機能すること」
を意味します。攻撃者は自分自身が表立って行動することを嫌います。そのため、
- 管理の甘いサーバ
- 脆弱性があるサービス
などにつけ込み侵入を試み、それを自らの配下として利用します。これは、先に述べた
- システムダウン
- バックアップ不備による切り戻し不可
とは何もかもレベルが違うリスクです。
ぶっちゃけ、自分自身が運営しているサーバの瓦解は自分が泣けばそれで済む話ではありますが、自分が管理しているサーバが攻撃に関与したというのは、法的/金銭的/社会的な失墜が絡む大問題。
この、理不尽なまでの非対称性が絡むということを最初に意識してインターネット上サーバでの運営を意識しましょう。
趣味/勉強の範疇での最低限の手段
とはいえ、趣味や勉強の範囲でインターネット接続環境でもLinuxサーバを立ち上げたいという方はいるかと思います。
ここからは、メソロドジーから一歩踏み込み、「より具体的な手段」について述べます。
想定する環境
- とりあえずLinuxサーバをvpsで立ち上げた。
- 様々な環境から接続をするから確固たる固定IPを持っていない
- それでもWebサーバを立ち上げたい
ちょっとした茨の道を進みたい方向けです。
※ ここからは筆者の過去記事から「特に必要な設定」を抜き出し、加筆編集を加えた記事です。※
話の前に筆者環境
- Ubuntu 24.04
- apt/aptitudeのパッケージ管理システム
を用います。つまり、makeやリビルドなどは発生しない、再現性の高い環境でのステップバイステップです。
メンテナンス用のユーザを作成する
この作業は極めて重要です。というのも、先に示したとおり、攻撃者が真っ先に/そして最終的に狙うのは管理者権限。つまり、(root)です。
rootへのネットワークを介したログインを禁止すると同時に、メンテナンス用のユーザを作成し、NW上からは、ここから接続することを厳命します。
- (コンソールを利用して)ユーザ作成
adduser [メンテナンス用ユーザ]
※[メンテナンス用ユーザ]
は英数字です。その後、パスワード設定などを対話式で求められるので、指示に従って入力します。
- ログイン確認
exit
物理コンソール/VPSのWebシリアルコンソールから抜けます。
メンテナンス用のユーザ作成確認(メンテナンス用のユーザ)
- 作成したユーザでログイン確認
Webコンソールで、作成したユーザ名とパスワードでログインできることを確認。
whoami
で、設定したアカウントであることを確認します。
- rootに昇格できないことを確認
sudo su -
としても、rootに昇格することはできません。なので、一度
exit
でコンソールを抜け、rootでログインし直します。
メンテナンス用のユーザのroot昇格設定(root)
- メンテナンス用のユーザにsudoを追加
rootでログイン後、
usermod -aG sudo [メンテナンス用ユーザ]
で、sudo
グループにこのユーザを加えます。
- sudo追加確認
id -a [メンテナンス用ユーザ]
で、以下のように表示されることを確認します。
uid=1000(hoge) gid=1000(hoge) groups=1000(hoge),27(sudo),100(users)
修正したユーザのグループに、27(sudo)
と表示されることがポイントです。
確認後、
exit
で更にrootを抜け、今度はメンテナンス用のユーザでログインします。
rootのロック (メンテナンス用のユーザ)
- root昇格
メンテナンス用のユーザでログイン後、
sudo su -
で、rootに昇格できることを確認します。
whoami
でroot
表示されることも確認します。
- rootロック
passwd -l root
として、rootそのものをロックします。
- rootのロック確認
exit
を2回行い、Webコンソールから抜けます。
rootロック確認
- メンテナンス用のユーザ→Webコンソールでログイン可能
- root→Webコンソールでログイン不可能を確認します。
これ以降はメンテナンス用のユーザで作業を行います。
SSH設定
Ubuntu Desktop系と違い、Ubuntu Serverではsshdがデフォルトでインストールされていない場合があります。
sudo apt install ssh
で、sshdをインストールします。
インストール後、
ssh -V
でバージョンが表示されることを確認し、
systemctl status ssh.service
で、running
とenabled
を確認します。
このSSHは鍵認証でログインできるようにします。この鍵認証のセキュリティ強度はパスワードと段違い。
鍵交換認証にする理由
- パスワードが送信されない
- パスワード認証では、パスワード自体がネットワーク上を流れるため盗聴リスクがあります。
- 鍵認証では、秘密鍵が署名を生成し、署名のみが送信されるため、秘密情報が直接送られることはありません。
- 総当たり攻撃に強い
- パスワードは文字数が少ないと短時間で破られる可能性があります。
- 鍵認証では、2048ビット以上の鍵が使われることが多く、現在の一般的なサーバの計算能力では事実上破ることが不可能です。
- 盗聴されても再利用できない
- 鍵認証では毎回異なるチャレンジに対して署名を行うため、録音や再送信による攻撃(リプレイ攻撃)が通用しません。
- フィッシング耐性が高い
- パスワード認証は偽サイトに入力してしまうリスクがあります。
- 鍵認証では秘密鍵がローカルに保管されており、外部に送信されないためフィッシングに強いです。
SSH鍵ペア作成
ssh-keygen -t ed25519
- 鍵の格納場所は空Enter。(/home/hoge/.ssh/
- パスワードを設定します。
SSH鍵ペア作成確認
- 鍵格納ディレクトリに移動
cd .ssh
- ファイルの内容確認
ls -l
以下のファイルを確認します。
- id_ed25519
- id_ed25519.pub ※これらのファイルはscp等で自分のクライアントにコピーします。
鍵の設定変更
公開鍵をauthorized_keysに変更し、パーミッションを厳密にします。
- ファイル名変更
cat id_ed25519.pub >> authorized_keys
- パーミッション設定
chmod 600 authorized_keys
秘密鍵の保存
この秘密鍵(id_ed25519
)は、サーバー全体のアクセス権を持つ、言葉通りの意味でのマスターキーです。
この秘密鍵を奪われることは、サーバーの全権限を奪われることと同義です。 そのため、管理は厳密に、そして自分だけがアクセスできる安全な手段(パスワードマネージャーや暗号化されたストレージなど)で、必ずバックアップをこの段階で行ってください。
その後、適切なターミナルクライアントでこの秘密鍵を登録。接続を確認できたという確証が取れて、初めて実機の前から解放されます。
UFWとFail2banの設定
- ファイアウォール(ufw)の設定: 不要な通信をすべて拒否し、必要な通信(SSH, HTTP/S)のみを許可する、基本的な防御壁を構築します。
- 不正アクセスの自動検知・ブロック(fail2ban): ログファイルを常時監視し、不審なアクセス元を検知すると、ufwと連携してそのIPアドレスからのアクセスを動的に、そして恒久的にブロックします。
- SSHへのログイン失敗(3回)
- ufwがブロックした通信(1回)
Fail2banとは?
fail2ban
は、サーバーのログファイルを監視し、設定されたパターンに一致する不審なアクセス(パスワード総当たり攻撃など)を検知すると、そのアクセス元のIPアドレスを自動的にファイアウォールの拒否リストに追加する、侵入防止ソフトウェアです。
一度設定すれば、アンインストールしない限りは有効化し続けます。
まず、サーバーの玄関となるファイアウォールufw
を設定します。
0-1. システム全体のバックアップ(vpsや仮想サーバの場合)
UFWとfail2banは基本的である分、設定に極めて忠実です。そのため、設定をミスして自分自身のアクセスを禁止した場合、そこに入るための手段はなくなります。
そのため、vps/仮想サーバと言った物理的なログイン手段を持たない場合は、スナップショットやディスクイメージ全体のバックアップを行い、「失敗したときのリカバリー」を行えるようにします。
現に、筆者は、これを怠ったばかりにサーバを作り直したことが3回ほどあります。
0-2. 実機でログインできる準備をしておく(物理サーバの場合)
物理サーバで、サーバ室やデータセンターなどの場合は、この設定が終わるまでは実機の前にいるべきです。
1.1 デフォルトのポリシーを設定
最初に「入ってくる通信は原則すべて拒否、出ていく通信はすべて許可」という基本方針を設定します。これが最も安全な基本設定です。
- 入ってくる通信を全拒否
sudo ufw default deny incoming
- 出てくる通信を全許可
sudo ufw default allow outgoing
- ufw.logの有効化
sudo ufw logging on
これを行わないと、後述するfail2banのアクセスがうまくいきません。
1.2 必要な通信を許可する
次に、必要なサービスへの通信を個別に許可します。SSHの接続を許可する前にufwを有効化すると、サーバーから締め出されてしまうので、必ず先に設定してください。
- SSH接続を許可(ポート22番)
sudo ufw allow ssh comment 'Allow SSH connections'
- WebサーバーへのHTTP接続を許可(ポート80番)
sudo ufw allow http comment 'Allow HTTP traffic'
- WebサーバーへのHTTPS接続を許可(ポート443番)
sudo ufw allow https comment 'Allow HTTPS traffic'
comment
オプションで、後からルールを見返したときに分かりやすいようにコメントを付与できます。
これはもちろん基本的な構成です。他のポートを開放・閉じる場合は必要に応じて行います。
1.4 UFWを有効化
ルールを設定したら、ufwを有効化します。
sudo ufw enable
実行すると、「この操作は既存のSSH接続を切断する可能性があります」という警告が出ますが、ステップ1.2でSSHを許可していれば問題ありません。y
を入力して実行します。
1.5 設定状態の確認
最後に、設定が正しく反映されているか確認します。
sudo ufw status verbose
Status: active
と表示され、許可したルールが一覧に出ていれば成功です。
1.6 ufw有効化確認
SSHターミナルで
telnet localhost 22
と行ってみます。
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
と通信が可能です。逆に、通信を許可されていないポートでは
telnet localhost 23
Trying 127.0.0.1...
telnet: Unable to connect to remote host: 接続を拒否されました
として、接続することはできません。
手順2:Fail2banのインストールと設定
次に、fail2ban
をインストールし、ufwと連携させる設定を行います。
2.1 Fail2banのインストール
- パッケージリストを更新
sudo aptitude update
- fail2banをインストール
sudo aptitude install fail2ban
筆者の好みでaptitude
を用いていますが、apt
でも同様です。
2.2 設定ファイルの仕組み(.conf と .local)
Fail2banの設定は、/etc/fail2ban/
ディレクトリにあります。重要なルールとして、jail.conf
のような.conf
ファイルを直接編集してはいけません。
代わりに、jail.local
のように.local
という拡張子のファイルを作成し、変更したい項目だけを記述します。.local
ファイルの内容が.conf
の内容を上書きする仕組みになっており、これにより、将来Fail2banがアップデートされても、自分が行ったカスタム設定が消えてしまうのを防げます。
2.3 jail.localの作成と解説
教義・信仰に沿ったエディタで、/etc/fail2ban/jail.local
というファイル名で新規作成し、以下の内容を記述します。
# SSHへの総当たり攻撃を監視・ブロックする設定
[sshd]
enabled = true # このsshd用の設定を有効にする
maxretry = 3 # 3回試行を失敗したら
bantime = -1 # 無期限にBANする
logpath = /var/log/auth.log # この認証ログファイルを監視する
ignoreip = 127.0.0.1/8 ::1 【ここに自分のIPアドレスを追加】
# ignoreipには、絶対にBANしたくない自分のIPアドレスなどをスペース区切りで指定
# UFWがブロックしたログを監視・ブロックする設定
[ufw]
enabled = true
filter = ufw-aggressive
action = iptables-allports
logpath = /var/log/ufw.log
maxretry = 1 # 1回でもUFWの拒否ログに記録されたら
bantime = -1 # 無期限にBANする
ignoreip = 127.0.0.1/8 ::1 【ここに自分のIPアドレスを追加】
2.4 カスタムフィルターの作成(ufw-aggressive)
上記の[ufw]
セクションで指定したufw-aggressive
というフィルターは、自分で作成する必要があります。これは、ufw.log
から攻撃元IPアドレスを抜き出すためのルールです。
/etc/fail2ban/filter.d/ufw-aggressive.conf
というファイル名で新規作成し、以下の内容を記述します。
[Definition]
failregex = [UFW BLOCK].+SRC=<HOST>
ignoreregex =
failregex
: この正規表現パターンに一致するログ行を探し、<HOST>
の部分を攻撃元IPアドレスとして認識します。
手順3:設定の反映と動作確認
- Fail2banサービスを有効化・起動します。
- fail2banの有効化(サーバ再起動でも自動的に起動するようにする)
sudo systemctl enable fail2ban
- fail2banの起動
sudo systemctl start fail2ban
- サービスの稼働状態を確認します。
sudo systemctl status fail2ban
active (running)
と表示されていれば成功です。
- ジェイル(監視)の状態を確認します。
sudo fail2ban-client status
Jail list:
に、sshd
とufw
が表示されていれば、監視が開始されています。
これで、不審なアクセスは次回以降、有無を言わせずブロックされる設定となりました。
BANされたIPアドレスは sudo fail2ban-client status sshd
や sudo fail2ban-client status ufw
で確認できます。
まとめ「大いなる力には……」
Linuxの学習で実機を触った方(特にRocky/AlmaなどのRHEL系ディストリビューション)で
sudo su -
を実行したとき、以下のような文言を見かけるのではないでしょうか。
あなたはシステム管理者から通常の講習を受けたはずです。
これは通常、以下の3点に要約されます:
#1) 他人のプライバシーを尊重すること。
#2) タイプする前に考えること。
#3) 大いなる力には大いなる責任が伴うこと。
この#3
の「with great power there must also come -- great responsibility」は特に重要です。
少なくとも、Linuxサーバのインターネット公開という「1つの世界」を「他の世界と接続する」行為を試みた者は、この言葉を言葉ではなく魂で理解していきましょう。
余談(という名の本題)
なお、これを力説するのは「筆者が加害者になりかけたことがある」からです。上記の設定などを全く理解せず、rootの意味/覚悟を知らぬままLinuxサーバを自宅から運用するということを行ってしまったため……
たちまちのうちに制御を乗っ取られ、「善意の第三者からの通報」により阻止されたという苦い思いがあります。
この経験は15年もの間、Linuxと筆者を遠ざけ、趣味で触ってもローカル環境で運用するというトラウマとなりました。
ようやく、このトラウマから脱却できつつあるので、初心に立ち返る意味でもこの文章を残します。
コメントを残す