SNS

CPI の共用サーバーに SSH 鍵で入れない → 原因は鍵ファイルの改行コード(CRLF)とパーミッションだった

投稿日:
|

CPI の共用サーバーに SSH で入ろうとしたところ、鍵を指定しているのにパスワードを聞かれ続けて入れませんでした。コントロールパネルで鍵を発行し直しても同じです。

原因は、ダウンロードした秘密鍵ファイルの 改行コードが CRLF で、パーミッションが 644 だったことでした。ssh が鍵を読めずに無視し、パスワード認証に移っていました。

症状

$ ssh myserver
Enter passphrase for key '~/.ssh/server_key':
(user@xxxx.secure.ne.jp) Password:
(user@xxxx.secure.ne.jp) Password:
(user@xxxx.secure.ne.jp) Password:
Connection closed by xxx.xxx.xxx.xxx port xxxxx

鍵のパスフレーズのあとにパスワードを聞かれ、何を入れても通りません。

鍵ファイルを確認する

ssh-keygen -l で鍵を読ませると、2つのメッセージが出ました。

$ ssh-keygen -l -f ~/.ssh/server_key
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '~/.ssh/server_key' are too open.
This private key will be ignored.
~/.ssh/server_key is not a key file.
  • Permissions 0644 ... are too open:ほかのユーザーも読める状態なので、ssh が鍵を使いません。
  • is not a key file:パーミッションを直しても、このメッセージは消えませんでした。

中身を調べると、改行コードが CRLF(Windows 形式)でした。

file ~/.ssh/server_key                      # PEM RSA private key
grep -c $'\r' ~/.ssh/server_key             # 0 以外なら CRLF が混ざっている

PEM 形式の鍵は、行末に \r が付いていると OpenSSH が読めません。

直し方

元のファイルを残してから、CR を取り除いてパーミッションを 600 にします。

cd ~/.ssh
cp -p server_key server_key.crlf.bak
tr -d '\r' < server_key.crlf.bak > server_key
chmod 600 server_key server_key.crlf.bak
ssh-keygen -l -f server_key                 # 2048 SHA256:... (RSA) と出れば OK

これで鍵が読めるようになり、パスワードを聞かれずに入れるようになりました。

コントロールパネルで鍵を発行し直しても、ダウンロードしたファイルはまた CRLF になっていました。発行し直したときは、毎回この変換が必要です。

接続設定の例

~/.ssh/config に書いておくと、ssh myserver だけで入れます。ホスト名・ポート・ユーザー名は、コントロールパネルに表示されているものに置き換えてください(ポートは 22 ではありませんでした)。

Host myserver
  HostName xxxx.secure.ne.jp
  Port xxxxx
  User xxxxxxxx
  IdentityFile ~/.ssh/server_key
  IdentitiesOnly yes
  UseKeychain yes
  AddKeysToAgent yes
  ServerAliveInterval 60

UseKeychain は macOS の ssh だけの設定です。ほかの OS ではエラーになるので外してください。

ユーザー名が分からなかったとき

コントロールパネルが重く、SSH のユーザー名がすぐには確認できませんでした。手元にあった本番の設定ファイルの、ホームディレクトリのパス(/usr/home/<アカウント>)に出てくるアカウント名がユーザー名でした。FTP のアカウント名とは別でした。

遠回りしたこと

最初は、「鍵が古い RSA 形式(BEGIN RSA PRIVATE KEY)なので、SHA-1 署名(ssh-rsa)が最近の OpenSSH で無効になっているのでは」と考え、PubkeyAcceptedAlgorithms +ssh-rsa を足しました。しかし、ssh -v で接続先を見ると OpenSSH 9.1 で、新しい署名方式(rsa-sha2)に対応していたので、関係ありませんでした。

パスワードを聞かれるときは、サーバー側を疑う前に、まず手元の鍵ファイルが読めているかを ssh-keygen -l -f で確かめるのが近道です。

おまけ:入ってみて分かったサーバーの様子

  • シェルは csh で、md5 や whoami も入っていない、かなり制限された環境でした。
  • php コマンドは無く、/usr/local/bin/php-8.3 のようにバージョン付きの名前で入っています。
  • mysqldump はあるので、DB のバックアップは SSH 越しに手元へ直接流せました。パスワードはサーバー上で wp-config.php から読んで環境変数で渡すと、画面にもコマンドの引数にも出ません。
# サーバー上で実行するスクリプトを標準入力で渡す(サーバーにファイルを作らない)
ssh myserver /bin/sh -s -- html/cms/wp-config.php <DB名> < remote_dump.sh \
  | gzip > backup-$(date +%Y%m%d).sql.gz
# remote_dump.sh(サーバー上で動く)
set -eu
conf=$1; db=$2
val() { sed -n "s/^[[:space:]]*define([[:space:]]*'$1'[[:space:]]*,[[:space:]]*'\([^']*\)'.*/\1/p" "$conf" | head -1; }
[ "$(val DB_NAME)" = "$db" ] || { echo "DB名が一致しません" >&2; exit 1; }
MYSQL_PWD=$(val DB_PASSWORD); export MYSQL_PWD
exec mysqldump -h "$(val DB_HOST)" -u "$(val DB_USER)" \
  --single-transaction --quick --no-tablespaces --default-character-set=utf8mb4 "$db"

CONTACT

サイト訪問ありがとうございます。
お仕事のご依頼、ご相談がありましたらお気軽にご連絡ください。
*は必須項目となります。

お名前 *
メールアドレス *
会社・組織名
お問い合わせ内容 *
0/300

当サイトはreCAPTCHAによって保護されており、Google のプライバシーポリシーおよび利用規約が適用されます。
当サイトのプライバシーポリシーをご一読の上ご連絡ください。