はじめに
最終的にはKubernetesでの利用を考えているrsyncバックアップ用のサーバーを構築するために、AlpineコンテナでSSHサーバーを稼動するテストを行ないました。
その際に、パスワード認証はできるものの、公開鍵を利用したログインができなかったため事象が発生しました。
Ubuntuベースで作成したプロトタイプを元にしていますが、Alpineに移行したのでそのDockerfileなどをメモしておくことにしました。
参考資料
コンテナの構築
Dockerファイルはだいたい次のような内容になっています。
Alpineイメージで/etc/init.d/のスクリプトを起動させるには、openrcパッケージを利用しますが、今回は直接起動するためインストールしていません。
FROM alpine:3.13.5
RUN apk --no-cache add tzdata bash ca-certificates make openssh rsync openssl
ENV SSHD_CONFIG_FILEPATH /etc/ssh/sshd_config
ENV SSH_PUBKEY_FILEPATH /conf/id_key.pub
ENV SSH_AUTHKEYS_FILEPATH /root/.ssh/authorized_keys
COPY run.sh /run.sh
RUN chmod +x /run.sh
EXPOSE 22
ENTRYPOINT ["/run.sh"]
最後に呼んでいるrun.shの中では次のような操作を行なっています。
#!/bin/bash -x
SSHD_CONFIG_FILEPATH="${SSHD_CONFIG_FILEPATH:-/etc/ssh/sshd_config}"
SSH_SERVERKEYS_FILEPATH="${SSH_SERVERKEYS_FILEPATH_LIST:-/etc/ssh/ssh_host_rsa_key}"
## update the sshd_config file
echo "HostKey ${SSH_SERVERKEYS_FILEPATH}" >> "${SSHD_CONFIG_FILEPATH}"
echo "PubkeyAuthentication yes" >> "${SSHD_CONFIG_FILEPATH}"
echo "PasswordAuthentication no" >> "${SSHD_CONFIG_FILEPATH}"
echo "PermitRootLogin yes" >> "${SSHD_CONFIG_FILEPATH}"
echo "StrictModes yes" >> "${SSHD_CONFIG_FILEPATH}"
## prepare the ~/.ssh/authorized_keys
SSH_PUBKEY_FILEPATH="${SSH_PUBKEY_FILEPATH:-/conf/id_key.pub}"
SSH_AUTHKEYS_FILEPATH="${SSH_AUTHKEYS_FILEPATH:-/root/.ssh/authorized_keys}"
SSH_AUTHKEYS_BASEDIR="$(dirname ${SSH_AUTHKEYS_FILEPATH})"
mkdir -p "${SSH_AUTHKEYS_BASEDIR}"
chmod 700 "${SSH_AUTHKEYS_BASEDIR}"
cp "${SSH_PUBKEY_FILEPATH}" "${SSH_AUTHKEYS_FILEPATH}"
chmod 0600 "${ROOK_SSH_AUTHKEYS_FILEPATH}"
## change the root password
echo "root:$(openssl rand -hex 12)" | chpasswd
exec /usr/sbin/sshd -D
次に必要な秘密鍵・公開鍵を準備します。
$ ssh-keygen -t ed25519 -f id_ed25519
$ ssh-keygen -t ed25519 -f ssh_host_ed25519_key
最終的に次のようなファイルを準備したことになります。
$ ls
Dockerfile id_ed25519 id_ed25519.pub run.sh ssh_host_ed25519_key ssh_host_ed25519_key.pub
Dockerコンテナのビルドと実行
準備したファイルを利用してDockerコンテナをビルドし、再現するかテストを行ないます。
$ sudo docker build . --tag sshd
$ sudo docker run -it --rm -v `pwd`/id_ed25519.pub:/conf/id_key.pub \
-v `pwd`/ssh_host_ed25519_key:/etc/ssh/ssh_host_rsa_key \
-p 2222:22 --name sshd sshd:latest
既存のsshdと競合しないように、2222番ポートを利用しています。環境に応じて変更してください。
無事に起動したら別のshellから接続を試みます。
あらかじめid_ed25519ファイルのあるディレクトリに移動してから進めます。
$ ls
Dockerfile id_ed25519 id_ed25519.pub run.sh ssh_host_ed25519_key ssh_host_ed25519_key.pub
$ ssh -i id_ed25519 -p 2222 root@localhost
エラーの原因について
遭遇したエラーについてまとめておきます。
エラーメッセージ
次のようなエラーメッセージが表示されています。
ssh -i conf/id_ed25519 -p 2222 root@localhost
root@localhost: Permission denied (publickey,keyboard-interactive).
次のようなメッセージが表示されるかもしれません。
ssh -i conf/id_ed25519 -p 2222 root@localhost
Received disconnect from 127.0.0.1 port 2222:2: Too many authentication failures
Disconnected from 127.0.0.1 port 2222
エラー発生の可能性と原因
このような事象が発生しているのには、いつくかの理由が考えられます。
- 接続しようとしているユーザーID(root)にパスワードが設定されていない
- sshコマンドがpublickey認証に対応していない
前者はrun.shの中で強制的にランダムなパスワードを実行時に指定するようになっています。
後者の原因は、/etc/ssh/ssh_configや~/.ssh/ssh_configに、PreferredAuthentications passwordのような設定を入れている場合に発生します。
Dockerコンテナ側の/etc/passwdで該当ユーザーのログイン・シェルが設定されている必要もあります。
alpineの場合、ユーザーIDをadduserコマンドでDockerfileで作成しただけでは、ログイン・シェルが/sbin/nologinなどに設定されていまいます。
一般ユーザーを追加する際の考慮点
chshコマンドはshadowパッケージから導入できますが、非対話的に設定することができないようなので、次のように一般ユーザーを作成しています。
RUN adduser -S test01 && echo "test01:secret-password" | chpasswd
RUN sed -i -e '/test01/s/sbin\/nologin/bin\/bash/' /etc/passwd
一応chpasswdコマンドを実行していますが、実際にはrootユーザーと同様に実行時にランダムなパスワードを設定する方法がお勧めです。
また、sedコマンドはbusybox版なので、デリミタに'/'文字以外を指定することはできません。
以上