Fatal Error: Unexpected BLOG

主に自分用の備忘録として

【CentOS】vsFTPdでFTPSかつchrootなFTPサーバを構築する

諸々の事情が絡み合って、外部サーバからFTP接続してファイルをアップロードしなければならない状況になったので、
「SFTPでいいじゃん。」と思って立ててなかったFTPサーバを立てることにしました。

但し平文FTPではやはりアレなので、FTPSを有効にします。
※訳あってSFTPは使えません。

以下、今回の環境です。

  • さくらのVPS
  • CentOS 6.6
  • vsftpd-3.0.3
  • FTPS有効
  • PASV有効

せっかくなのでvsftpd-3.0.3をソースからコンパイルします。
SSL用の秘密鍵と証明書は別件でオレオレのものを生成済みです。


※以下各作業を行う場合は自己責任でお願いします。


なお、以下のサイトを参考にさせて頂きました。
この場を借りて御礼申し上げます。



では、やっていきましょう。

ルート権限でログイン

リモートからのルートログインを制限している場合もあると思いますが、

$ sudo sh

でルートのパスワードを入力すれば、以降ルートのシェル環境で作業できます。

元々入っているvsftpdをアンインストール

入っていれば。

# yum remove vsftpd

ちなみに私はビビリなので、常に「-y」は付けません。

ソースを取得・展開

ソースを展開するディレクトリに移動してwgetで取得、tarで展開します。
今回はhttps://security.appspot.com/downloads/vsftpd-3.0.3.tar.gzから取得できました。

# cd /usr/local/src
# wget https://security.appspot.com/downloads/vsftpd-3.0.3.tar.gz
# tar zxvf vsftpd-3.3.3.tar.gz

展開して出来たディレクトリを丸ごとchownしておきます。

# chown -R root:root vsftpd-3.0.3


インストール先を作成

今回は一か所にまとめたかったので/opt/配下に専用ディレクトリを作成しました。

# mkdir /opt/vsftpd
# mkdir /opt/vsftpd/bin
# mkdir /opt/vsftpd/conf
# mkdir /opt/vsftpd/log
# mkdir /opt/vsftpd/work


builddefs.hを編集

コンパイル時の設定ファイルを編集してSSLtcp_wrappersを有効にします。

# cd ./vsftpd-3.0.3
# vi ./builddefs.h

【builddefs.h】

#ifndef VSF_BUILDDEFS_H
#define VSF_BUILDDEFS_H

#define VSF_BUILD_TCPWRAPPERS ←変更
#define VSF_BUILD_PAM
#define VSF_BUILD_SSL ←変更

#endif


nobodyユーザがいるか

vsftpd-3.0.3ではnobodyユーザが必要とのことで、いなければ作っておきます。

/usr/share/emptyディレクトリがあるか

こちらも必要なようなので、無ければ作成。
ちなみに今回はどちらもデフォルトで有りました。

依存パッケージのインストール

ここまで来て今更ですが、vsftpdのインストールに必要なパッケージを予め入れておきます。

  • make
  • gcc
  • tcp_wrappers-devel.x86_64
  • libcap-devel
  • openssl.x86_64 1.0.1e-48.el6_8.3
  • openssl-devel.x86_64

opensslですが、私の場合既に入っていたものではダメでした。makeが失敗します。
yumでアップデートして比較的新しいものにして下さい。(セキュリティを考えれば当然最新のものが良いです)
なお、CentOSyumでインストールした場合、バージョン番号はアップストリームとは一致しません。
以下のコマンドで更新履歴が見れるので、そちらでチェックします。

# rpm -q --changelog openssl

今回は、履歴の最も新しい日付が「2016/9/22」だったので、まぁいいでしょう。

make実行

現在地は/usr/local/share/vsftpd-3.0.3 です

# make

make install はやりません。インストール先を/opt/vsftp配下に集約するためです。

必要なファイルをインストール用ディレクトリにcp

makeが成功したら実行バイナリと設定ファイル、マニュアルをインストール用ディレクトリにコピーします。

# cp -p ./vsftpd /opt/vsftpd/bin
# cp -p ./vsftpd.conf /opt/vsftpd/conf
# cp -p ./vsftpd.8 /opt/vsftpd/conf
# cp -p ./vsftpd.conf.5 /opt/vsftpd/conf


ファイアウォールの設定

FTP接続用のポートを開けておきます。

# vi /etc/sysconfig/iptables

iptables

...(省略)...
-A INPUT -p tcp -m tcp --dport 20 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 50021 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 50040 -j ACCEPT
...(省略)...

下2つはPASVモード用です。

iptablesにモジュールをロードさせる

iptables関連でもう一つ。iptablesの設定ファイルを編集してFTP用のモジュールをロードさせます。

# vi /etc/sysconfig/iptables-config

iptables-config】

...(省略)...
IPTABLES_MODULES="ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp"
...(省略)...



書き終えたらiptablesを再起動しておきます。

# service iptables restart


vsftpdの設定を編集

vsftpdの設定を変更します。

# vi /opt/vsftpd/conf/vsftpd.conf

【vsftpd.conf】

anonymous_enable=NO  #匿名アクセスを拒否
local_enable=YES     #ローカルユーザのログイン許可
write_enable=YES     #ローカルユーザの書込許可
local_mask=022       #デフォルトのパーミションを755に

...(省略)...

xferlog_file=/opt/vsftpd/log/vsftpd.log  #ログファイル
xferlog_std_format=YES                   #ログファイルフォーマット

...(省略)...

ascii_upload_enable=YES    #ASCIIモードでのアップロードを許可
ascii_download_enable=YES  #ASCIIモードでのダウンロードを許可

...(省略)...

chroot_local_user=YES                                 #ローカルユーザをchroot(※1)
chroot_list_enable=YES                                #chroot_listを有効
chroot_list_file=/opt/vsftpd/conf/vsftpd.chroot_list  #↑がYESなので、これはchrootされないユーザのリスト

...(省略)...

listen=YES

...(以下追加)...

# Enable writing under chroot
allow_writeable_chroot=YES  #chroot下にあるユーザの書込を許可

# About SSL
ssl_enable=YES                        #SSL有効
rsa_cert_file=/path/to/cert/file.pem  #サーバ証明書(pemファイル)のパス(※2)
ssl_sslv2=NO                          #SSLv2は無効
ssl_sslv3=NO                          #SSLv3も無効
ssl_tlsv1=YES                         #TLSv1を有効
force_local_data_ssl=YES              #SSLを強制
force_local_logins_ssl=YES            #SSLを強制

# About PASV
pasv_address=your.host.name  #PASVモードでアクセスするホスト名(グローバルIPでも可)
pasv_enable=YES              #PASVモード有効
pasv_min_port=50021          #PASVモードで使用するポート番号の最小値
pasv_max_port=50040          #PASVモードで使用するポート番号の最大値
※1

chroot_local_userの値によって、chroot_list_fileで指定したファイルの扱いが変わります。
chroot_local_user=YESの場合、chrootされないユーザのリストになり、
chroot_local_user=NOの場合、chrootされるユーザのリストになります。

※2

証明書のみ、または秘密鍵のみのファイルではNGです。
証明書と秘密鍵が併記されたpemファイルが必要です。無ければ作成して下さい。
※それぞれのファイルの生成は割愛します。

# (cat /path/to/cert/file.crt ; cat /path/to/key/file.key) > /path/to/cert/file.pem

chroot_listを作成しておく

今回の設定ではchroot_listはchrootされないユーザのリストです。
FTPで接続するユーザは全てchrootしておきたいので、今回は空にしておきました。

# echo -n > /opt/vsftpd/conf/vsftpd.chroot_list


起動スクリプトの設置

ソースからコンパイルしたので、起動スクリプトも作成しなければなりません。
これについては、前述の参考サイト様を大いに参考にさせて頂きました。というかほぼまんまです。

# vi /etc/init.d/vsftpd

【/etc/init.d/vsftpd】

#!/bin/bash
#
# vsftpd    This shell script takes care of starting and stopping
#           standalone vsftpd.
#
# chkconfig: 2345 60 50
# description: Vsftpd is a ftp deamon, which is the program \
#              that answers incoming ftp service requests.
# processname: vsftpd
# config: /opt/vsftpd/conf/vsftpd.conf

# Source function library.
. /etc/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "${NETWORKING}" = "no" ] && exit 0
# Check that the binary is excutable.
[ -x /opt/vsftpd/bin/vsftpd ] || exit 0

RETVAL=0
prog="vsftpd"

start() {
    # Start deamons.
    if [ -d /opt/vsftpd ]
    then
        for i in `ls /opt/vsftpd/conf/*.conf`
        do
            site=`basename $i .conf`
            echo -n $"Starting $prog for $site: "
            /opt/vsftpd/bin/vsftpd $i &
            RETVAL=$?
            [ $RETVAL -eq 0 ] && {
                touch /var/lock/subsys/$prog
                success $"$prog $site"
            }
            echo
        done
    else
        RETVAL=1
    fi
    return $RETVAL
}

stop() {
    # Stop daemons.
    echo -n $"Shutting down $prog: "
    killproc $prog
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
    return $RETVAL
}

# See how we were called.
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart|reload)
        stop
        start
        RETVAL=$?
        ;;
    condrestart)
        if [ -f /var/lock/subsys/$prog ]
        then
            stop
            start
            RETVAL=$?
        fi
        ;;
    status)
        status $prog
        RETVAL=$?
        ;;
    *)
        echo $"Usage: $0 {start|stop|restart|condrestart|status}"
        exit 1
esac

exit $RETVAL

※上記はあくまで参考として、コピペでそのまま使用することは避けて下さい。環境によっては動作しないかもしれないので。
※繰り返しますが設定は自己責任でお願いします。

自動起動設定

サーバ起動時に自動で起動するようchkconfigに追加します。

# chkconfig --add vsftpd


確認

以下のコマンドで起動、停止、状態確認が出来ます。

# service vsftpd start
# service vsftpd stop
# service vsftpd restart
# service vsftpd status



クライアントから接続してみてFTPS接続できたら成功です。
お疲れ様でした。


おまけ

今回、クライアントからPASVモードでファイル一覧が取得できない事象が発生しまして、結局はiptablesの設定だったんですが、
その際、クライアントからどのポートにアクセスしているか以下の情報から分かるということを知りました。

#サーバのレスポンス
227 Entering Passive Mode (xxx,xxx,xxx,xxx,nnn,mmm).

上記の「xxx.xxx.xxx.xxx」はサーバのグローバルIPですが、
後半の「nnn,mmm」の部分。
これは、

256 * nnn + mmm = ポート番号

ということだそうです。
己の無知を噛み締めた次第。忘れないようにメモ。