セキュアなSSHポートフォワード管理サーバーを構築

SSHポートフォワードで、踏み台サーバーを設定することがあると思います。最近では新型コロナウィルスの対策でテレワークが推奨されていることもあり、ますますその機会は増えているかと思います。そこで今回は、SSHポートフォワードを安全に利用するための設定を紹介したいと思います。

今回紹介するのは以下です。

  1. SSHサーバーの設定
    1. 公開鍵暗号方式のみを利用
    2. root ログインを不許可
  2. ポートフォワード用のユーザシェルは /sbin/nologin
  3. ポートフォワードされたらメールを送信
本サイトでは、CentOS 7 で「最小構成インストール」を実施しています。
スポンサーリンク

SSHサーバーの設定

今回の主役となるSSHサーバーですが、SSHサーバー自体をセキュアに仕上げておく必要があります。CentOSではインストール直後、パスワード認証になっていたり、rootでのログインが可能になっていますのでこの設定を変更します。

どちらも、/etc/ssh/sshd_config の設定になります。

公開鍵暗号方式を利用

デフォルトの設定ファイルでは、 PasswordAuthentication yes となっていると思います。これをコメントアウトし、no とします。

#PasswordAuthentication yes
PasswordAuthentication no

rootログインを不許可

デフォルトの設定ファイルでは、 #PermitRootLogin yes のようにコメントアウトされていると思います。これはデフォルトで root のログインを許可している状態ですので、以下のように記載しrootログインを許可しないようにします。

#PermitRootLogin yes
PermitRootLogin no
root とグインを許可していると便利ですが、ユーザ名を root で固定したブルートフォースアタックなどの攻撃に弱くなります。また、/root/ 直下の .ssh/ にRSA公開鍵を置くトロイの木馬型の攻撃もあるようです。

rootユーザやパスワード認証でのSSHログインできなくなるため、ログイン・メンテナンスするユーザに公開鍵を登録します。

ログイン・メンテナンスを行うするユーザで公開鍵は以下のようにして作成します。

$ ssh-keygen -t rsa

鍵のパスワードを2回入れて完成です。(※ 空でエンターを入力するとパスワードなしの鍵ができます。)

Generating public/private rsa key pair.
Enter file in which to save the key (/home/sshuser/.ssh/id_rsa):
Created directory '/home/sshuser/.ssh'.
Enter passphrase (empty for no passphrase):(パスワード入力)
Enter same passphrase again:(パスワード入力)
Your identification has been saved in /home/sshuser/.ssh/id_rsa.
Your public key has been saved in /home/sshuser/.ssh/id_rsa.pub.

~/.ssh/ に、id_rsa と id_rsa.pub が生成されます。id_rsa が秘密鍵、id_rsa.pub が公開鍵になります。id_rsa は人に渡してはいけません。~/.ssh/id_rsa.pub を ~/.ssh/authorized_keys という名前変更し、~/.ssh/id_rsa をWindowsなどのクライアントにセキュアにコピーします。

本来SSHログインするクライアント側で鍵(秘密鍵)を生成すべきですが、クライアントによっては、鍵生成が面倒なので、このようにしています。

設定ファイルを変更したら、以下のコマンドでSSHサーバーを再起動します。

# systemctl restart sshd
sshd の再起動後、新たな SSH 接続では、root ユーザやパスワード認証でのログインができません。現在のセッションを終了する前に入念に確認します。

ポートフォワード用のユーザシェルは /sbin/nologin

メンテナンスユーザとは違って、ポートフォワードをするためだけに作成したユーザは、シェルを /sbin/nologin に設定します。ユーザの作成時に以下のように、adduser コマンドを実行します。

# useradd -s /sbin/nologin ユーザー名

既に存在するユーザを変更したい場合は、/etc/password の該当ユーザの行を以下のように変更します。1000:1000 はユーザーID/グループIDです。

(変更前)
user:x:1000:1000::/home/user:/bin/bash
(変更後)
user:x:1000:1000::/home/user:/sbin/nologin

ポートフォワードされたらメールを送信

今回の記事のキモの部分です。SSHサーバーにログイン(フォワード実行)があったら、指定されたメールアドレスにメールを飛ばすように設定します。ここでは、gmailで任意のアドレスにメールを送信する方法を紹介します。

Postfixの設定

CentOS7を最小構成でインストールしてもデフォルトで入っている、postfixを利用して任意のgmailアドレスから、任意のメールアドレス(社内のメールアドレス)へメールを送る設定をします。事前に gmail のアカウント(gmailアドレス)を獲得しておいてください。

gmail の SMTP認証に必要なソフトをインストールします。

yum -y install cyrus-sasl cyrus-sasl-plain mailx

以下で、gmailをリレーするように、/etc/postfix/main.c を修正します。必要に応じてファイルをバックアップしておきます。

relayhost = [smtp.gmail.com]:587

smtp_use_tls = yes
smtp_tls_CApath = /etc/pki/tls/certs/ca-bundle.crt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/smtp_auth
smtp_sasl_mechanism_filter = plain
smtp_sasl_tls_security_options = noanonymous
デフォルトの /etc/postfix/main.c 内の記述の = より前のパラメータが「有る」ものは修正、「無い」ものは行ごと追加してください。

事前に取得した gmail のメールアドレスを exsample@gmail.com そのパスワードを Passw0rd としたときに、SMTP-Auth の設定として以下のようにします。

# echo "[smtp.gmail.com]:587 exsample@gmail.com:Passw0rd" >/etc/postfix/smtp_auth
# chmod 600 /etc/postfix/smtp_auth
# postmap /etc/postfix/smtp_auth

最後に、Postfixを再起動します。

# systemctl restart postfix

これで、任意のメールアドレス宛のメールを exsample@gmail.com を利用して送信する設定が完了しました。以下のコマンドで、メールが送れることを確認しましょう。

echo "finished mail setup." | mail -s "test mail" 任意のメールアドレス
メールが届かない場合、迷惑メールフィルタの確認や、サーバーのログファイル:/var/log/maillog の確認をします。

ポートフォワード用のログインを監視

これが一番苦労しました。はじめ、/etc/sshrc や ~/.ssh/rc などが使えるだろうと考えていましたが、シェルが /sbin/nologin や /bin/false で設定されているユーザではこれが使えませんでした。最悪、/sbin/nologin を 普通のシェルにすることも考えましたが、ログを残すためにセキュリティレベルを下げるのも本末転倒です。試行錯誤の末、/sbin/nologin のユーザがフォワードするために張ったセッションでも、/var/log/secure に記録されていることに目を付けました。PAM が使えそうです。

今回は、ssh のログインセッションのみを監視するため、/etc/pam.d/sshd を修正します。以下を /etc/pam.d/sshd の最終行に追加します。これにより、SSH のセッションの開始/終了時などに、スクリプト(/usr/bin/notify-login.sh)が実行されるようになります。

session     optional      pam_exec.so /usr/bin/notify-login.sh

/usr/bin/notify-login.sh を以下のように作成しました。残念ながらセッションの終了に関してはメールが送信できませんでした。テキストの書き出しはできたので、セッションの開始のみをメールでリアルタイムに通知し、開始と終了をログに記録することにしました。

#!/bin/bash
export LC_CTYPE=ja_JP.UTF-8

FROMADDR=exsample@gmail.com (準備したgmailアドレス)
TOADDR=notify@exsample.com  (任意のメールアドレス:会社のアドレスなど)

if [ "$PAM_TYPE" = "open_session" ] ;then
    if [ "$TOADDR" != "" ] ;then
        {
        echo "リモートセッションが開始されました。"
        echo "日時    : `date`"
        echo "ユーザ  : $PAM_USER"
        echo "接続元IP: $PAM_RHOST"
        echo ""
        echo "本メールは、SSH サーバー(`hostname`)から自動送信されています。"
        }|mail -s "$PAM_USER でセッション開始" -r $FROMADDR $TOADDR
    fi
    echo "[`date "+%m/%d %H:%M:%S"`] $PAM_USER rhost=$PAM_RHOST START" >> /root/sshfw-`date +%Y%m`.log
elif [ "$PAM_TYPE" = "close_session" ] ;then
    echo "[`date "+%m/%d %H:%M:%S"`] $PAM_USER rhost=$PAM_RHOST FINISH" >> /root/sshfw-`date +%Y%m`.log
fi