vsftpdのトラブルとproftpd
Debianでvsftpdを利用していましたが、再構成したらトラブルに遭遇しました。その原因と追究と、非常時用に代替候補となる proftpd の使い方を学習しました。
トラブルの症状と対応
Debian12 で vsftpd を構成しようとしたところ、FTPS接続において「 SSL: error:0A000126:SSL routines::unexpected eof while reading 」という表示がでて、FTPS接続の初期化に失敗するようになりました。
のちに、待ち受けポートを変更をしたら改善され、環境(VPS)に移行した都合によるものではないかという結論になったのですが、それに至るまでの試行錯誤を書き残しておきます。
先のエラーメッセージをネット検索してみたところ、こちらのOpenSSLの記事がヒットし、OpenSSLの1系と3系のメソッドの違いからくるのではないかと考えました。
Debian12 でインストールされる vsftpd のバージョンを確認します。
#vsftpd -v #vsftpd: version 3.0.3
また、apt でインストール可能な vsftpd の依存関係を、「 apt-cache depends vsftpd 」で調べて見ると OpenSSL3系(libssl3)が依存となっており、3系が組み込まれていることも分かりました。
ただ、公式サイトにある最新版の3.0.5のソースは、OpenSSLの3系には対応していないようで、libssl3の環境でビルドしたら非推奨のエラーにより作業が完了しませんでしたが、バージョン1系をビルドしたかったので逆に幸いでした。
libsslのビルド用のパッケージが必要なら、通常はaptコマンドを使って「 libssl-dev 」を指定すればいいのですが、Debian12用のレポジトリでは libssl3がダウンロードされます。
なので、OpenSSLのサイトから1.1.1wのソースをダウンロードしてビルドします。
# cd /usr/local/src # curl https://www.openssl.org/source/openssl-1.1.1w.tar.gz -o openssl-1.1.1w.tar.gz ... # tar vzxf openssl-1.1.1w.tar.gz ... # cd openssl-1.1.1w # ./config ... # make ... # make test ... # make install ...
OpenSSLをビルドしてインストールできたら、作成したlibssl.so.1.1ライブラリを「 ldconfig 」コマンドで認識させます。
次に vsftp をビルドします。デフォルトでは ssl は無効の構成になっています。設定は、ソースディレクトリの builddefs.h ファイルに存在します。
builddefs.h
#undef VSF_BUILD_SSL ↓ のように変更します #define VSF_BUILD_SSL
あとは make でビルド、 make install でインストールという流れは通常通りです。
install時、Debianだとヘルプファイル(man)配置用のディレクトリがなくてエラーになります。筆者は無視しましたが、気になるようなら MakeFile ファイルを編集してください。
バイナリは、/usr/local/sbin/vsftpd に配置されます。このバイナリを実行する際に、設定ファイル /etc/vsftpd.confを引数に渡します。
この作業では、改善されませんでした。
サーバー証明書の署名アルゴリズムが変わったのかとも思いましたが、それも違いました。
最終的には試行錯誤で待ち受けポートを変えてみたらうまくいきました。ローカルで同じバージョンで環境を作っても現象が再現されないことから、VPS環境の影響ではないか、という結論になりました。
ProFTPD
今回は事なきを得ましたが vsftpd がしばらくメンテナンスされていないことが判明したので、再度何かあった時のために、代替となりうるProFTPDによる構成を確認しておきます。
$sudo su ... # apt update ... # apt install proftpd-core ...
Debian12(bookwarm)における ProFTPD の設定ファイルは /etc/proftpd ディレクトリにあり、機能別に .conf ファイルが分割されています。
インストール後から、OSユーザーが自身のIDとパスワードを使ってアクセスできる構成になっているようです(chrootなし)。
メインの設定ファイルは proftpd.conf となります。ここから、他の confファイルが Include されています。設定上 モジュールの読み込みの設定が必要なら、ここから読みだされることになっている modules.conf を編集します。
ここに設定する項目の多くはGlobal(mod_core)設定となります。
主な設定項目を見てみます。
proftpd.conf
... # IPv6の利用 UseIP6 off ... # 全ユーザを対象としたの chroot 設定 # 下記でユーザーホームを chrootに DefaultRoot ~ ... # ポート Port 21 ... # 認証順 # コメントアウトの状態だとmod_auth_unix.c(OSユーザー)で判定します # PAMを含める (/etc/pam.d/proftpd) # AuthOrder mod_auth_pam.c* mod_auth_unix.c # ログファイルの設定 TransferLog /var/log/proftpd/xferlog SystemLog /var/log/proftpd/proftpd.log # FTPS の設定読み込み # (デフォルトでは利用できません) # Include /etc/proftpd/tls.conf # バーチャルホスト、ルートの設定読み込み # Include /etc/proftpd/virtuals.conf # パッシブポートの範囲指定 # PassivePorts 50000 51000 ...
Auth Orderについてですが、ここには認証モジュールを複数指定する事ができます。
mod_auth_pam.c モジュールにおいては、公式のマニュアルに単一で使用しないようにとあります。これはPAM経由ではユーザIDやグループID、ホームディレクトリが取得できないからだそうです。PAMモジュール名の後に * 記号がついていますが、こうすることで認証の結果はPAMのものに従うようにした上で、残りのパラメータを別のモジュールで取得するようになります。
ProFTPDでバーチャルユーザー
OSユーザーによるログインはインストールしただけで利用可能になったので、バーチャルユーザーを作成していきたいと思います。
ProFTPDではモジュールとしてその機能が用意されています。
mod_auth_file.c がそれにあたります。
このモジュールだけで、一応目的は達成できますが、パスワードが8文字までという制限があるので近年のセキュリティ要件を満たせない事が多いと思います。
これを回避するため、mod_auth_pam と mod_auth_file を併用します。
まず AuthOrderを次のようにします。
次に PAM を設定します。Debianの apt からインストールした場合のデフォルトは /etc/pam.d/proftpd にPAM設定がありますので、vsftpd でPAMの設定をしたのと同様に、pam-pwd-fileの構成をします。
不足している情報を proftpd に同梱されている ftpasswd コマンドを用いて行います。
バーチャルユーザー名に対して、ユーザーID、グループID、ホームディレクトリ、シェルを結びつける設定をし、保存先を指定します。
ユーザーIDやグループIDは /etc/passwdファイル等を参考に数値で指定します。バーチャルユーザーのユーザーアカウント別に結びつけるOSアカウントを変更できるので vsftpd より細かな設定が可能です。
ホームディレクトリも、バーチャルユーザーのアカウント毎に設定できます。シェルは nologin または false にしておきます。
最後に出力先を指定します。
パスワードの設定を求められますがPAMでの認証が優先されますので、適当な値でもいいです。
バーチャルユーザーはシェルにはアクセスできないようにしますが、通常は /etc/shells に記載したシェルを利用できないと、ログインできない設定となっています。ですので、これを解除します。
proftpd.conf
... RequireValidShells off ...
さきほど作成したユーザーデータを、mod_auth_file に適用させる記述をします。
proftpd.conf
... <IfModule mod_auth_file.c> AuthUserFile /etc/proftpd/proftpd.users </IfModule> ...
これでバーチャルユーザーでの FTP接続が可能となります。
ProFTPDでFTPS
次に FTPSの設定をしたいのですが、apt でインストールする proftpd は mod_tls が含まれていませんでした。
現行のビルドでバンドル済のモジュールを確認するには、proftpd -l とします。この中に mod_tls が設定されていれば、そのまま FTPS が利用できます。
また、通常は /usr/lib/proftpd 内に追加モジュールが配置されています。先の出力中に mod_dsoがあり(DSOが利用可能で)、追加モジュールのファイル群に mod_tls.so が存在すれば、設定により FTPS が利用できます。
今回はそのどちらにも存在しないため、ソースからビルドします。いつもはネットなどで公開されている最新のバージョンのソースを取得するのですが、今回はビルドオプションの問題だけなので、レポジトリからソースを取得します。
# cd /usr/local/src # mkdir proftpd # cd proftpd # apt update # apt-get source proftpd-core ... Picking 'proftpd-dfsg' as source package instead of 'proftpd-core' NOTICE: 'proftpd-dfsg' packaging is maintained in the 'Git' version control system at: https://salsa.debian.org/debian-proftpd-team/proftpd.git Please use: git clone https://salsa.debian.org/debian-proftpd-team/proftpd.git to retrieve the latest (possibly unreleased) updates to the package. Need to get 19.5 MB of source archives. Get:1 http://deb.debian.org/debian bookworm/main proftpd-dfsg 1.3.8+dfsg-4+deb12u2 (dsc) [3433 B] Get:2 http://deb.debian.org/debian bookworm/main proftpd-dfsg 1.3.8+dfsg-4+deb12u2 (tar) [19.4 MB] Get:3 http://deb.debian.org/debian bookworm/main proftpd-dfsg 1.3.8+dfsg-4+deb12u2 (diff) [79.6 kB] Fetched 19.5 MB in 9s (2079 kB/s) dpkg-source: info: extracting proftpd-dfsg in proftpd-dfsg-1.3.8+dfsg dpkg-source: info: unpacking proftpd-dfsg_1.3.8+dfsg.orig.tar.gz dpkg-source: info: unpacking proftpd-dfsg_1.3.8+dfsg-4+deb12u2.debian.tar.xz dpkg-source: info: using patch list from debian/patches/series dpkg-source: info: applying autotools dpkg-source: info: applying change_pam_name dpkg-source: info: applying ftpasswd.cracklib.location dpkg-source: info: applying mod_sql_mysql.c dpkg-source: info: applying mod_wrap_noparanoid dpkg-source: info: applying ftpstats dpkg-source: info: applying odbc dpkg-source: info: applying upstream_bug_1568.diff dpkg-source: info: applying upstream_bug_1581.diff dpkg-source: info: applying upstream_bug_1584.diff dpkg-source: info: applying upstream_1592.diff dpkg-source: info: applying upstream_bug_1597.diff dpkg-source: info: applying 01_disable_inet_connect_ipv4_test.diff dpkg-source: info: applying 02_disable_redis_sentinel_conn_new_test.diff dpkg-source: info: applying 03_disable_all_non_api_tests.diff dpkg-source: info: applying upstream_1707.diff
apt-get source でソースを取得する際 /etc/apt/sources.list 中に deb-src のエントリーが無いと取得できませんので注意してください。
proftpd-core のかわりに proftpd-dfsg が選択されたようですが、この dfsg は Debian Free Software Guidelines を意味するようで特に意識する必要はなさそうです。
apt-get source はカレントディレクトリにファイルを保存します。今回実行してみたところ、次のようなファイルとディレクトリがダウンロードされました。
- proftpd-dfsg-1.3.8+dfsg
ディレクトリです。これは apt-get source での作業過程でダウンロードした tar.xz ファイルを展開したディレクトリになると思います。
- proftpd-dfsg_1.3.8+dfsg-4+deb12u2.debian.tar.xz
.debian.tar.xz 末尾がつくファイルはDebianパッケージの為にカスタマイズされたソースです。または、.diff.gz となることもあるようです。
- proftpd-dfsg_1.3.8+dfsg-4+deb12u2.dsc
通常 .dscファイルはソースパッケージのメタデータが格納されます。電子署名が入っていました。
- proftpd-dfsg_1.3.8+dfsg.orig.tar.gz
オリジナルのソースです
ビルドには、ビルド用のパッケージに加え、libssl-dev や libpam0g-dev、libcap-devなどが必要になると思います。
# apt install libssl-dev libpam0g-dev(PAM) libcap-dev(capabilities:権限管理) libpcre2-dev(正規表現) libmemcached-dev libhiredis-dev(Redis軽量版) zlib1g-dev(圧縮) ... # ldconfig ...
ソース内の debian/rules ファイルがバイナリを make する際のスクリプトになっているそうです。これを参考に configure オプションを設定します。または、proftpd -V でもビルドオプションを表示できます。
そのあと 目的の tlsモジュールを指定する為に、--with-modules=mod_tlsを指定します。
--with-shared オプションを使って、modules.conf で利用している DSO(Dynamic Shared Object:共有ライブラリ)を指定して、あわせてDSOモジュールもビルドする必要があります。先ほどの --with-modules に mod_tls を指定するかわりに、こちらに含めてももいいです。
./confiure の結果は通常同じフォルダ内の configure.log に出力されます。configure 通過後に buildでエラーになるのは筆者の場合、ほとんど開発ライブラリのインストール不足が原因でした。
ビルドが終わったら、設定をしていきます。これは、aptでインストールした際の /etc/proftpd/ にあるファイル群の流用が可能です。同様の内容のテンプレートが ソースディレクトリ/debian/templates にあります。
シンタックスチェックは、proftpd -t -c [設定ファイルへのパス] とすることで可能です。
proftpd.conf の主な設定は先ほどと同様ですがaptから得たファイルを利用する場合は、次の修正が必要だと思われます。
proftpd.conf
... <IfModule mod_ctrls.c> ControlsEngine off ControlsMaxClients 2 ControlsLog /var/log/proftpd/controls.log ControlsInterval 5 ControlsSocket /usr/local/var/proftpd.sock </IfModule> ... # tls.confへのパスを追加します Include /path/to/tls.conf ... # コメントアウト #Include /etc/proftpd/conf.d/
次に modules.confの設定です。
今回の筆者の環境ではビルドしてインストールした DSO モジュールは /usr/local/libexec に入るようになっていました。ここは通常プログラム個別のスクリプトや実行ファイルを配置する場所ですが、気になるなら、/usr/local/lib/proftpd などに動かしてください。
modules.conf
# モジュールのパスが変更されますのでそれにあわせます ModulePath /usr/local/libexec # もし tls を DSO 化した場合はコメントアウトを解除します。 LoadModule mod_tls.c ...
tls.confは次のようになると思います。
tls.conf
... # FTPSを有効に TLSEngine on # ログファイルの場所 TLSLog /var/log/proftpd/tls.log # バージョン TLSv1 1.1 1.2 をサポートという事なので 1.2という選択になると思います TLSProtocol TLSv1.2 # TLS接続を必須にするか TLSRequired on # サーバーの証明書とキー(ここでは仮のものを使います) TLSRSACertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem TLSRSACertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key # 必要に応じてCAの証明書を設定 # TLSCACertificateFile /etc/ssl/certs/CA.pem # クライアント認証はOFFに TLSVerifyClient off ...
最後に、サービスファイルの生成をして、/etc/systemd/system/ に配置します。
元となるファイルは ソースディレクトリの contrib/dist/rpm/proftpd.service にあります。
TLSRequired on として SSL接続を強制しても設定不備等で、mod_tls 利用できない場合は、プレーンパスワードでの接続を受け付けます。また、PIDFileのパスを適切に指定しないと、起動できても、再起動できないので注意してください。
proftpd.service
[Unit] Description=ProFTPD FTP Server Wants=network-online.target After=network-online.target nss-lookup.target local-fs.target remote-fs.target [Service] # 制御を戻すようにするために simple から forking に変更 Type=forking Environment=OPTIONS= CONFIG_FILE=/etc/proftpd/proftpd.conf EnvironmentFile=-/etc/default/proftpd ExecStartPre=/usr/local/sbin/proftpd --configtest -c $CONFIG_FILE $OPTIONS # type=forking デーモン化(バックグランド化)したので --nodaemonは外します ExecStart=/usr/sbin/proftpd -c $CONFIG_FILE $OPTIONS ExecReload=/bin/kill -HUP $MAINPID # ビルドしたproftpdに合わせてpidを指定します PIDFile=/usr/local/var/proftpd.pid [Install] WantedBy=multi-user.target
デフォルトの設定ファイル群は、debian/templates にありますので、適当な場所にコピーします。その後、サービスの EnvironmentFile エントリーで指定したファイル(ここでは/etc/default/proftpd)の中に CONFIG_FILE= として新たな設定ファイルへのパスを記します。
事前に用意されている tls.conf ファイルを読み込むように、proftpd.conf ファイルのコメントアウトも解除します。
proftpd.conf
... # コメントアウトを解除 Include /etc/proftpd/tls.conf ...
ビルドしたモジュールだけ利用する
先ほどはビルドした proftpd を使用しましたが、mod_tls をDSOモジュールとしてビルドすれば、バイナリはAPTでインストールしたものを利用し、不足している mod_tls.so だけを元の環境に配置して設定することで FTPS接続が可能になります。
詳しくはmod_tls.html#Installationを確認してください。
先ほどビルドした、mod_tls を標準のライブラリがある場所へコピーし、先ほど同様に設定をします。
筆者の環境ではうまくいきましたが、APTのバイナリと、ビルドした時とライブラリのバージョンの違いによる齟齬等が原因で正常に動かないこともあるかもしれません。
執筆にあたり chatGPTの回答を参考にしています。動作確認などのファクトチェックを行っていますが、用語の意味等の一部は鵜呑みの部分もございますご容赦ください。