富士通クラウドダイレクトブログ

初心者エンジニア向けTechBlog

富士通クラウドダイレクトブログ

初心者エンジニア向けTechBlog

サーバー管理の基本 SSHのセキュリティについて知ろう

こんにちは。日本仮想化技術株式会社の水野です。

今回は、サーバーのリモート操作に使われている「SSH」について、運用において注意すべきセキュリティ面にフォーカスしてお話してみたいと思います。

SSHってなに?

サーバールームやデータセンターに置かれているサーバーは、PCとは違って直接触れることができません。いえ、もちろんデータセンターに入館してコンソールを繋げば可能ではあるのですが、よほどの緊急時を除けば、オフィスのPCからリモート接続で操作するのが基本ですよね。特にクラウド上の仮想サーバーは、どう頑張っても物理的に触れないため、リモート操作がマストです。

そして、サーバーのリモート操作に使われているのが「Secure Shell」、通称「SSH」です。その中でもオープンソースな実装である「OpenSSH」を使うケースが多いでしょう。OpenSSHクライアントは、Linuxはもちろん、macOSやWindowsにも標準で用意されているため、別途ツールをインストールする必要もなく便利です*1

なおSSHの概要については、2023年11月29日のニフクラエンジニアミートアップ「サーバー管理者のためのセキュリティ超入門」の宮原さんのセッションのスライドも参照してください。

www.slideshare.net

やっておきたいSSHのセキュリティ対策

一般的なSSHサーバーというのはその用途的に、以下のような問題を抱えています。

  • 外部からの接続を受け付ける必要がある
  • 認証に成功するとサーバーのシェルを取れる

誰がどう見ても、認証を突破されるとヤバいですよね。

後述するように、SSHを使わずに済むのであれば、それに越したことはありません。 ですが、そうもいかないのが現実でしょう。

そこでSSHを運用するにあたって、やっておくべきセキュリティ対策を紹介します。少なくとも、パスワード認証が可能な状態のSSHサーバーを、インターネットに対して晒すようなことは、絶対にしないでください。

公開鍵認証

まず最初にやっておきたいのが、パスワード認証を禁止し、公開鍵認証に切替えることです。公開鍵認証は、パスワードのように総当たりによる突破が現実的に困難です。先日のセミナーのおさらいになりますが、鍵ペアの作成は、ssh-keygenコマンドで行います。

$ ssh-keygen -t 鍵タイプ -C 鍵コメント

鍵タイプは、セキュリティ的にはed25519がお勧めです。ですがまだ、この形式に対応していないアプリやWebサービスも存在するため、互換性を重視するのであればrsaを選択するとよいでしょう。ただしrsaの場合は-bオプションで長めのビット長を指定しておいた方がよいかもしれません。現在のデフォルトは3072ビットです。

作成した公開鍵は、ログインするサーバーの~/.ssh/authorized_keysというファイルに登録する必要があります。このファイルをテキストエディタで直接編集してもよいのですが、もしも誤編集してしまうと、サーバーにログインできなくなってしまうかもしれません。そこで専用のコマンドである、ssh-copy-idを使うとよいでしょう。

$ ssh-copy-id -i 公開鍵ファイル サーバーのアドレス

ですがこの方法で公開鍵をサーバーに登録するには、登録対象の鍵以外の方法でログインできる必要があります。そのためパスワード認証が禁止されており、鍵がひとつも登録されていないサーバーには、ユーザー自信で鍵を登録することができません。現実的には、サーバー管理者に鍵を登録してもらうことになるでしょう。

サーバー管理者向けの鍵登録コマンドが、ssh-import-idです。これはログイン対象のサーバー上で実行するコマンドで、GitHubLaunchpadから指定したユーザーの公開鍵を取得して登録します。例えばGitHubのuser1ユーザーの公開鍵を登録するには、以下のように実行します。

$ ssh-import-id gh:user1

どちらのコマンドも、詳しい使い方はmanページを参照してください。

なおUbuntuサーバーでは、GitHubからの公開鍵のインポートと、パスワードによるSSHログインの禁止は、インストーラーで設定することができます。SSHによるログインを許可する予定があるのであれば、可能な限りOSのインストール時に行うことをお勧めします。

スマホアプリを使った2要素認証

公開鍵による認証は、それだけで十分な効果があるのですが、実運用においては問題もあります。やはり大きいのは、公開鍵認証に馴染みのないユーザーに、鍵の作成や安全な管理を求めるのが難しいという点です。新人さんに「サーバーにアカウントを作るので、手順書に従って公開鍵を作って送ってください」とお願いしても、なかなか理解してもらえなかったり、秘密鍵を速攻で紛失する人が出たり、なぜか秘密鍵が送られてきたり、といった経験をした情シス担当の方もいるのではないでしょうか。

UbuntuのSSHサーバーでは、パスワードとTOTPによる2要素認証が使えます。スマホアプリを使ったワンタイムパスワードは、Webサービスでもお馴染みですから、IT初心者でもとっつきやすいのではないでしょうか。ここではUbuntu 22.04での設定例を紹介します。なおパスワードとの2要素認証となるため、パスワード認証を禁止している場合は、許可するようサーバーの設定を変更しておいてください。

まずサーバーにlibpam-google-authenticatorパッケージをインストールします。

$ sudo apt install -y libpam-google-authenticator 

続いて/etc/pam.d/sshdをテキストエディタで開き、@include common-authの直下にauth required pam_google_authenticator.soという行を追加してください。

@include common-auth
auth required pam_google_authenticator.so             # ← この行を追加

SSHサーバーの設定も変更します。/etc/ssh/sshd_configをテキストエディタで開き、62行目付近のKbdInteractiveAuthentication noの、noyesに書き換えます。またその下にChallengeResponseAuthentication yesという行を追加します。また86行目付近にUsePAM yesと書かれた行があることを確認します。デフォルトでこの設定となっているはずですので、ここは通常変更する必要はありません。

(...略...)

KbdInteractiveAuthentication yes        # ← この行をnoからyesに変更
ChallengeResponseAuthentication yes     # ← この行を追加

(...略...)

UsePAM yes                              # ← この行があることを確認する

最後に、SSHサーバーを再起動します。

$ sudo systemctl restart sshd.service

続いて、ログインするユーザーごとの設定を行います。この操作は管理者権限ではなく、各ユーザーの権限で行ってください。google-authenticatorコマンドをすると、認証コードを時刻ベースにするかどうか訊かれますので、yと入力してEnterキーを押します。するとターミナルにQRコードが表示されますので、これをスマホのトークンアプリに読み込ませてください。その後、確認のため認証コードの入力を促されますので、スマホの画面に表示された6桁の数字を入力してください。

google-authenticatorコマンドを実行すると、ターミナル画面にQRコードが表示されるので、スマホに登録しよう。

その後、いくつかの質問が表示されますが、基本はすべてyを選択して構いません。以後はSSH接続を行うと、パスワードの入力を求められた後に、認証コードの入力を求められるようになります。なお本設定は公開鍵認証と併用することができ、公開鍵を登録している場合は、2要素認証をバイパスしてログイン可能です。

パスワードの入力後に、Verification codeの入力を求められる。ここに6桁の数字を入力すればいい。

ファイアウォールによる防御

ファイアウォールによる防御も有効です。SSHが使っているポートをパブリックに解放してしまうのではあまり意味がありませんが、利用するユーザーの接続元を限定できるのであれば、ソースIPアドレスで制限をかけてもよいでしょう。ですがリモートワークが一般的となった現在、ソースIPアドレスによる制限は難しいこともあるでしょう。そこで便利なのが、Ubuntuのファイアウォールにあるlimit機能です。ufwパッケージをインストールした後に、以下のようにルールを投入します。

$ sudo apt install -y ufw
$ sudo ufw enable
$ sudo ufw limit ssh

limitは同一のIPアドレスからの接続を、30秒間に5回まで許可し、6回目以降をブロックします。つまりこの設定で、SSHサーバーに対するブルートフォース攻撃をある程度防御することが可能になります。どうしてもパスワード認証を使わなければならない場合などは、力技で認証を突破されないためにも、こうした防御策を検討してください。なおファイアウォールについて詳しくは、UFWのマニュアルを参照してください。

SSHサーバーのポート変更

SSHサーバーに対する攻撃は、22番ポートを対象に行われます。そこでサーバーが待ち受けるポートを変更すれば、大部分の攻撃を回避できます。なお変更の際には、20228022といった「SSHだと推測されやすい」ポートは避け、完全にランダムなポートを採用することが重要です。

待ち受けるポート番号は、/etc/ssh/sshd_configで設定されています。このファイルを編集し、Port行に書かれている番号を変更してください。また他のサーバーとのバッティングを避けるため、/etc/servicesに記載されていない番号を選ぶようにするとよいでしょう。

Port 22
↓
Port 27365     # ← 22番ポートから推測しにくいポート番号に変更する

ポートを変更したら、SSHサーバーを再起動してください。

なおUbuntu 22.10以降のバージョンでは、SSHサーバー自身が接続を待ち受けるのではなく、systemdのSocket-Based Activation経由でサーバーが起動されるように変更されました。そのため待ち受けポートはsshd_configではなく、systemdのUnitファイルで設定する必要があります。以下のコマンドを実行すると、設定を上書きするためのテキストエディタが開きます。

$ sudo systemctl edit ssh.socket

例えばポートを27365番に変更するには、以下のように記述します。ListenStream=という値が空の行を挟むことで、22番ポートで待ち受ける設定をクリアしているため、この行は省略しないでください。

[Socket]
ListenStream=
ListenStream=27365

ファイルを保存したら、ssh.socketを再起動してください。

$ sudo systemctl restart ssh.socket

そもそもSSHを使わないという選択肢

ニフクラをはじめとする多くのクラウドサービスでは、Webからサーバーのコンソールを使うことができます。この方法であれば、セキュリティホールになりうるSSHサーバーをインターネットに公開する必要はありません。また現在では、IaCによるサーバー構築の自動化や、immutable infrastructureの概念も一般的になってきており、そもそもサーバーに直接ログインするのがアンチパターンという考え方もあります。

ニフクラのWebからサーバーのコンソールにログインした例。

セキュリティ対策を考えるのは当然なのですが、その前段階として、本当に古典的なSSHの口をインターネットに公開する必要があるのか、もう一度考えてみてもよいのではないでしょうか。

*1:意外と知らない人もいるようですが、最近のWindowsはデフォルトでPowerShellからssh.exeを実行することができます。