Linux サーバー:SSH 設定(2024年7月更新)
何度繰り返すことになっても、必ずあなたを守ってみせる。 ── 暁美ほむら
ㅤ
⚠ 足りない設定や推奨設定あったらコメントで教えてください。設定用スクリプトに追記します。みんなで楽しましょう。
SSH とは
Secure SHell の略。サーバーのシェルにリモートから安全にアクセスするための仕組み。安全にとは、
- 鍵を持たない第三者はアクセスできない
- 第三者は通信を盗み見ることができない
ということを意味する。scp
コマンドや sftp
コマンドを用いて SSH 接続を介した安全なファイル送信も可能であり、リモート作業で非常に重宝する。
環境
- サーバー:Ubuntu 20.04 LTS
- クライアント:なんか適当なシェル
方針
- ED25519公開鍵暗号を用いた SSH 通信
- SSH のポートを変更してファイアウォールの設定もする
- ファイアウォールの設定方針は
- デフォルトですべての incoming を deny
- SSH で用いるポートのみ allow
自動化スクリプトも用意するが、そこまでやるくらいなら Ansible とか検討したほうがいいかもしれない。
表記
どのシェルでの作業か自明な場合は
$ echo 'Hello, World!'
のように表記する。クライアントかサーバーかわかりにくいところでは
client$ echo 'Hello'
server$ echo 'World'
のように先頭にどちらでの作業かを示す。また root ユーザーでの作業は $
の代わりに '#' を用いて
server# 'Hello, World!'
のように示す。
クライアント側
0. キーの生成
ED25519 は RSA よりも強固で高速らしいので、新たに設定するならば ED25519 を使うほうがよいだろう。鍵の生成は以下のコマンドで行う。
$ ssh-keygen -t ed25519
鍵が作成される場所は ~/.ssh
。名前はデフォルトでは
- 秘密鍵:
~/.ssh/id_ed25519
- 公開鍵:
~/.ssh/id_ed25519.pub
である。秘密鍵は絶対に誰にも見せてはいけない。見られたら設定し直しである。
Linux に慣れていない人に伝えておくと、~/
はホームディレクトリ($ cd
コマンドに何も引数を与えずに実行したときに移動するディレクトリ)を指す省略記号である。.ssh
のようにドット記号から始まる名前は隠しファイル/ディレクトリなので通常の $ ls
では表示されず、$ ls -a
のようにオプションをつけて実行することで表示される。隠しディレクトリにも通常のディレクトリと同じように $ cd
コマンドで移動できる。
$ cd
$ ls -a
. .. .bashrc .config .ssh
$ cd .ssh
$ ls
authorized_keys config id_ed25519 id_ed25519.pub known_hosts
パスフレーズ
パスフレーズを設定しておくと、仮に管理用 PC が悪意ある第三者の手によって陥落しても、パスフレーズが特定されるまでの間は SSH の不正利用を防ぐことができる(サーバー側を守ることができる)。
そもそも管理用 PC の管理者アカウントを他人に触らせるという状況は考えづらいので、必要ないと思えば利便性の観点から設定しなくてもよい。
パスフレーズは、設定するならば、決して他に使用したことがないパスフレーズを使用すること。
なぜならばパスフレーズがセキュリティとして機能する段階では、管理用 PC 自体が陥落しているので、そこから PC 内外のメモ書きやクラウドキーチェーンなどを辿って使い回しのパスワードは真っ先に試されるからである。
1. SSH サーバー初期状態でのアクセス方法
サーバー側で SSH サーバーが起動されており、何も設定が変更されていなければ
$ ssh username@hostname
# あるいは直接 IP アドレスを指定して
$ ssh username@192.168.XXX.XXX
のようにユーザー名とホスト名(または IP アドレス)を指定してパスワードログインが可能である。
2. SSH サーバー設定完了後でのアクセス方法
~/.ssh/config
を作成して以下のように編集する。
Host sandbox
HostName 192.168.XXX.XXX
Port 2222
IdentityFile ~/.ssh/id_ed25519
User username
- Host
- アクセス先につける名前
- Hostname
- アクセス先のサーバーのホスト名または IP アドレス
- Port
- SSH ポートの番号(デフォルト 22 )
- IdentityFile
- SSH 接続に用いる鍵
-
ssh-keygen
で生成したやつ
- User
- アクセス先のサーバーのアクセスしたいユーザー名
設定ファイルを作成しておくことで、Host に設定した名前でアクセスできる。
$ ssh sandbox
Linux サーバー側
締め出し上等。
0. SSH サーバーのインストールと root での作業(必要な場合)
SSH サーバーのインストール方法はディストリビューションによるので各自検索すること。サーバー用 OS なら大抵最初から入っている。Ubuntu 20.04 LTS Desktop では
server$ sudo apt -y install openssh-server
でインストールできる。SSH サーバーの状態はサーバーのコンソールから
server$ systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2021-02-26 23:25:24 JST; 1h 51min ago
のように確認できる。止まっていたら $ systemctl restart ssh
なり、サーバーを再起動するなりすればよい。SSH サーバーが起動した時点で、クライアント側からは
client$ ssh username@hostname
# あるいは直接 IP アドレスを指定して
client$ ssh username@192.168.XXX.XXX
のようにユーザー名とホスト名(または IP アドレス)を指定すれば SSH にパスワードログインが可能である。
Ubuntu はデフォルトでは root ユーザーのパスワードが設定されておらず、その状態で SSH で root ログインすることはできない。一度他のユーザーでアクセスして $ sudo -s
で昇格すれば一時的に root ユーザーで作業できる。
$ sudo passwd root
で root にパスワードを設定すれば root にログインして作業することも可能である。
1. SSH 公開鍵のサーバーへの登録
SSH サーバーの設定を変更する前に公開鍵の準備をしておかないと締め出される。
SSH サーバー側に .ssh
ディレクトリがないと、このあとの scp
コマンドが失敗するので、先に確認しておく。
client$ ssh username@hostname
server$ ls -a
# もし .ssh がなければ
server$ mkdir .ssh
server$ exit
クライアント側から scp
コマンドでサーバーに公開鍵を移動し、サーバー側の authorized_keys
に追加する。authorized_keys
のファイルは権限を chmod 600
で設定する。
client$ scp ~/.ssh/id_ed25519.pub username@hostname:~/.ssh/register_key
client$ ssh username@hostname
server$ cd .ssh
server$ cat register_key >> authorized_keys
server$ chmod 600 authorized_keys
server$ rm register_key
2. SSH サーバーの設定
SSH サーバーの設定ファイルは /etc/ssh/sshd_config
である。手で編集するのが面倒くさい人はあとで示す ssh_setting.sh
スクリプトファイルを送って root ユーザーで実行すればよい。
設定ファイルは SSH デーモンを再起動すると反映されるが、まだやっちゃダメ。もしもポート番号を編集していたらファイアウォールにそのポートへのアクセスを弾かれて締め出される。ファイアウォールの設定を変更し、反映したあとで SSH デーモンを再起動する。
client$ scp ssh_setting.sh username@hostname:~/ssh_setting.sh
server$ sudo -s
server# ./ssh_setting.sh
Port 22
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
PermitEmptyPasswords no
SyslogFacility AUTHPRIV
LogLevel VERBOSE
手で編集する場合は $ sudo vi /etc/ssh/sshd_config
などで頑張る。
ポートは SSH_PORT_NUMBER
に好きなものを設定してよいが、0 〜 1023 番ポートはウェルノウンポートとして予約されているので 1024 〜 65535 番を指定する。
スクリプトは一度実行されると、もとの /etc/ssh/sshd_config
を /etc/ssh/sshd_config.bk
としてバックアップする。/etc/ssh/sshd_config.bk
が存在する場合は設定が行われたとみなして何もせずに終了する。
#!/bin/bash
# SSH の設定
SSH_CONFIG="/etc/ssh/sshd_config"
SSH_CONFIG_BACKUP="/etc/ssh/sshd_config.bk"
SSH_PORT_NUMBER="22"
function change_setting () {
TARGET=$1
KEYWORD=$2
VALUE=$3
EXIST=$(grep "^${KEYWORD}" ${TARGET} || true)
EXIST_COMMENT=$(grep "^#${KEYWORD}" ${TARGET} || true)
if [ "${EXIST}" != "" ]; then
sed -i '/^'${KEYWORD}'/c '${KEYWORD}' '${VALUE}'' ${TARGET}
elif [ "${EXIST_COMMENT}" != "" ]; then
sed -i '/^#'${KEYWORD}'/c '${KEYWORD}' '${VALUE}'' ${TARGET}
else
echo -e "${KEYWORD} ${VALUE}" >> ${TARGET}
fi
}
if [ -f ${SSH_CONFIG_BACKUP} ]; then
echo "SSH setting is already done."
else
echo "Modify ${SSH_CONFIG}"
cp -i ${SSH_CONFIG} ${SSH_CONFIG_BACKUP}
# Port
change_setting ${SSH_CONFIG} Port ${SSH_PORT_NUMBER}
grep "^Port" ${SSH_CONFIG}
# PermitRootLogin
change_setting ${SSH_CONFIG} PermitRootLogin no
grep "^PermitRootLogin" ${SSH_CONFIG}
# PasswordAuthentication
change_setting ${SSH_CONFIG} PasswordAuthentication no
grep "^PasswordAuthentication" ${SSH_CONFIG}
# UsePAM
change_setting ${SSH_CONFIG} UsePAM no
grep "^UsePAM" ${SSH_CONFIG}
# PubkeyAuthentication
change_setting ${SSH_CONFIG} PubkeyAuthentication yes
grep "^PubkeyAuthentication" ${SSH_CONFIG}
# ChallengeResponseAuthentication
change_setting ${SSH_CONFIG} ChallengeResponseAuthentication no
grep "^ChallengeResponseAuthentication" ${SSH_CONFIG}
# PermitEmptyPasswords
change_setting ${SSH_CONFIG} PermitEmptyPasswords no
grep "^PermitEmptyPasswords" ${SSH_CONFIG}
# SyslogFacility
change_setting ${SSH_CONFIG} SyslogFacility AUTHPRIV
grep "^SyslogFacility" ${SSH_CONFIG}
# LogLevel
change_setting ${SSH_CONFIG} LogLevel VERBOSE
grep "^LogLevel" ${SSH_CONFIG}
# TCP Port Forwarding
#change_setting ${SSH_CONFIG} AllowTcpForwarding no
#grep "^AllowTcpForwarding" ${SSH_CONFIG}
# AllowStreamLocalForwarding
#change_setting ${SSH_CONFIG} AllowStreamLocalForwarding no
#grep "^AllowStreamLocalForwarding" ${SSH_CONFIG}
# GatewayPorts
#change_setting ${SSH_CONFIG} GatewayPorts no
#grep "^GatewayPorts" ${SSH_CONFIG}
# PermitTunnel
#change_setting ${SSH_CONFIG} PermitTunnel no
#grep "^PermitTunnel" ${SSH_CONFIG}
fi
以下、設定項目の解説である。
- Port
- SSH のポート番号(デフォルトは 22 )
- PermitRootLogin no
- SSH 経由で root ユーザーへのログインを許可しない
- PasswordAuthentication no
- パスワードでのログインを許可しない
- ChallengeResponseAuthentication no
- パスワードに毛が生えた程度のチャレンジレスポンス認証でのログインは許可しない
- PermitEmptyPasswords
- パスワード未設定でも空パスワードでのログインは許可しない
- SyslogFacility
- LogLevel
3. ファイアウォール設定
Ubuntu ではファイアウォールに UFW(Uncomplicated FireWall)が使われる。他のファイアウォールを使う場合は各自で同様の設定を行うこと。
以下のコマンドでファイアウォールの現在の状態を確認できる
$ sudo ufw status
状態: アクティブ or 非アクティブ
アクティブだったら一旦ファイアウォールを無効化しておく。
$ sudo ufw disable
ファイアウォールを無効にし、システム起動時にも無効にします
デフォルトですべてのポートへの incoming を deny し、SSH に使うポートでの通信は許可する。ポートは自分で設定したものを選ぶこと。
$ sudo ufw default deny
$ sudo ufw allow 22
ポート番号をミスってもあとで削除できるのでとりあえずは無視して、自分が設定したポートを確実に開けておく。
設定できたら、SSH デーモンを再起動して、ファイアウォールを起動する。
$ sudo systemctl restart ssh
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
ファイアウォールはアクティブかつシステムの起動時に有効化されます。
設定をミスっていたらこの時点で SSH 接続が切れて締め出しを食らう。一度接続を切ってみて、『SSH サーバー設定完了後でのアクセス方法』で解説した、公開鍵でのアクセスを試みる。
client$ ssh sandbox
接続できればよし。できなければ何かが間違っているので、あなたの戦場はここじゃない。少しあとに書く『締め出された人へ』で状態を復旧したあとに『クライアント側 0. キーの生成』あたりからやり直す。
ㅤ
繰り返す。私は何度でも繰り返す。同じ時間を何度も巡り、たった一つの出口を探る。あなたを、絶望の運命から救い出す道を ── 暁美ほむら
ㅤ
公開鍵で接続できたらファイアウォールの状態を確認する。
$ sudo ufw status verbose
状態: アクティブ
To Action From
-- ------ ----
22 ALLOW Anywhere
22 (v6) ALLOW Anywhere (v6)
もしもミスった設定を追加していたら、以下の手順で削除する。
$ sudo ufw status numbered
状態: アクティブ
To Action From
-- ------ ----
[ 1] 22 ALLOW IN Anywhere
[ 2] 2822 ALLOW IN Anywhere
[ 3] 22 (v6) ALLOW IN Anywhere (v6)
[ 4] 2822 (v6) ALLOW IN Anywhere (v6)
$ sudo ufw delete 2
一度 delete すると数字が詰められるので、複数削除する場合は再度 $ sudo ufw status numbered
で数字を確認する。
Web サーバー用途であれば、80番、443番は開けておく。この辺はお好みで。
$ sudo ufw allow 80
$ sudo ufw allow 443
設定が終わったらファイアウォールを再起動する。
$ sudo ufw reload
締め出された人へ
🎉 🎊 おめでとうございます。あなたは人生の貴重な時間を完全に無駄にしました。🎊 🎉
締め出されたらサーバーのコンソールに別ルート(サーバーに直接繋がっているディスプレイとキーボードとか、VPS であればバーチャルコンソールなど)から直接アクセスして、/etc/ssh/sshd_config.bk
で /etc/ssh/sshd_config
を上書きし、ファイアウォールの設定をすべて削除した後に無効化すれば元の設定に戻る。
$ sudo rm /etc/ssh/sshd_config
$ sudo cp /etc/ssh/sshd_config.bk /etc/ssh/sshd_config
$ sudo rm /etc/ssh/sshd_config.bk
$ sudo systemctl restart ssh
$ sudo ufw status numbered
$ sudo ufw delete 番号(全部削除するまで繰り返す)
$ sudo ufw disable
これで一応は再びパスワードで SSH 接続できる状態になる。何もわからないくらいしっちゃかめっちゃかになってしまったら、サーバー側の OS を再インストールする。セキュリティに関わる部分なので、どんな変更が加わっているかわからない状態でサーバーを運用するのは危険だからである。
Discussion