centos7のvsftpdでchroot環境を作る

centos7でFTPのchroot機能を利用した環境を作成する。
FTPサービスはcentos7の標準パッケージのvsftpを使用する。
chrootとはFTPを利用するユーザーが参照できるディレクトリの範囲を限定する機能である。

# 参考
[Red Hat Enterprise Linux7 > システム管理者のガイド > 16.2. FTP]
(https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/s1-ftp)
[Red Hat Enterprise Linux6 > 導入ガイド > 18.2.5. VSFTPD 設定オプション]
(https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/deployment_guide/s2-ftp-vsftpd-conf)

# 検証環境
- centos7
- 1 vCPU
- 1 GB RAM

# 環境設定

## vsftpdのインストール

```bash
# vsftpdのインストール確認
$yum list vsftpd
# ...
利用可能なパッケージ
vsftpd.x86_64                         3.0.2-25.el7                      base

# vsftpdのインストール
$sudo yum install vsftpd
# ...
Running transaction
  インストール中          : vsftpd-3.0.2-25.el7.x86_64                      1/1
  検証中               : vsftpd-3.0.2-25.el7.x86_64                      1/1

インストール:
  vsftpd.x86_64 0:3.0.2-25.el7

完了しました!
```
## vsftpdの状態確認

```bash
# vsftpdの状態を確認
# 自動起動の状態：vsftpd.service
# 現在の状態：Active
$systemctl status vsftpd
● vsftpd.service - Vsftpd ftp daemon
   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
```

## サービス開始

```bash
$sudo systemctl start vsftpd
```

## サービス停止

```bash
$sudo systemctl stop vsftpd
```
## 自動起動有効化

```bash
$sudo systemctl enable vsftpd
```

## 自動起動無効化

```bash
$sudo systemctl disable vsftpd
```

## デフォルト設定の確認

### /etc/vsftpd/vsftpd.conf

vsftpdの基本的な設定を行うファイル。
各設定項目のデフォルト値の詳細はman vsftpd.confで確認できる。

[【参考】VSFTPD.CONFマニュアル翻訳]
(https://linuxjm.osdn.jp/html/vsftpd/man5/vsftpd.conf.5.html)

centos7のデフォルト設定を抜粋。

```conf:/etc/vsftpd/vsftpd.conf
anonymous_enable=YES
local_enable=YES
write_enable=YES
local_umask=022
#anon_upload_enable=YES
#anon_mkdir_write_enable=YES
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
#chown_uploads=YES
#chown_username=whoever
#xferlog_file=/var/log/xferlog
xferlog_std_format=YES
#idle_session_timeout=600
#data_connection_timeout=120
#nopriv_user=ftpsecure
#async_abor_enable=YES
#ascii_upload_enable=YES
#ascii_download_enable=YES
#ftpd_banner=Welcome to blah FTP service.
#deny_email_enable=YES
#banned_email_file=/etc/vsftpd/banned_emails
#chroot_local_user=YES
#chroot_list_enable=YES
#chroot_list_file=/etc/vsftpd/chroot_list
#ls_recurse_enable=YES
listen=NO
listen_ipv6=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES
```

### /etc/vsftpd/ftpusers

登録されているユーザーはFTPにログインできない。
セキュリティの観点から最低限rootは登録しておいたほうが良い。

### /etc/vsftpd/user_list

vsftpd.confのuserlist_denyの設定内容により、意味が変わる。

- userlist_deny=NOとしたとき、user_listはホワイトリストの扱いとなり
ファイルに含まれるユーザーのみがFTP接続可能となる。
- userlist_deny=YES（デフォルト）としたとき、user_listはブラックリストの扱いとなり
ファイルに含まれるユーザーはFTP接続が拒否される。

## 設定ファイルの変更

chroot機能を利用してユーザーごとにchroot jailのディレクトリを変更してみる。
例えばftpuser1は/var/ftp/jail-1にchrootし、ftpuser2は/var/ftp/jail-2にchrootする。

スタンドアローンモードで起動する。

```diff:/etc/vsftpd/vsftpd.conf
- listen=NO
- listen_ipv6=YES
+ listen=YES
+ listen_ipv6=NO
```

匿名ユーザーのログインを拒否する。

```diff:/etc/vsftpd/vsftpd.conf
- anonymous_enable=YES
+ anonymous_enable=NO
```

user_listをホワイトリストとして利用する。

```diff:/etc/vsftpd/vsftpd.conf
+ userlist_deny=NO
```

chrootを有効化する。

```diff:/etc/vsftpd/vsftpd.conf
- #chroot_list_enable=YES
+ chroot_list_enable=YES
```

chroot対象のユーザーリストファイルの場所を指定する。

```diff:/etc/vsftpd/vsftpd.conf
- #chroot_list_file=/etc/vsftpd/chroot_list
+ chroot_list_file=/etc/vsftpd/chroot_list
```

ユーザー毎の設定ファイルの場所を指定する。

```diff:/etc/vsftpd/vsftpd.conf
+ user_config_dir=/etc/vsftpd/user_config_dir
```

ローカルタイムゾーンを使用する。

```diff:/etc/vsftpd/vsftpd.conf
+ use_localtime=YES
```

userlist_deny=NOのとき、user_listはftp接続を許可するユーザーのみを記入する。

```config:/etc/vsftpd/user_list
ftpuser1
ftpuser2
```

chroot対象ユーザーリストファイルを作成する。

```bash
$sudo touch /etc/vsftpd/chroot_list
```

```config:/etc/vsftpd/chroot_list
ftpuser1
ftpuser2
```

ユーザー毎の設定ファイルを作成する。

```bash
$sudo mkdir /etc/vsftpd/user_config_dir
$sudo touch /etc/vsftpd/user_config_dir/ftpuser1
$sudo touch /etc/vsftpd/user_config_dir/ftpuser2
```

ユーザー毎のchroot後のディレクトリを設定する。

ftpuser1がftpログインすると/var/ftp/jail-1がルートディレクトリとなる。

```config:/etc/vsftpd/user_config_dir/ftpuser1
local_root=/var/ftp/jail-1
```
ftpuser２がftpログインすると/var/ftp/jail-2がルートディレクトリとなる。

```config:/etc/vsftpd/user_config_dir/ftpuser2
local_root=/var/ftp/jail-2
```

ftpディレクトリを作成する。

```bash
$sudo mkdir -p /var/ftp/jail-1/subdir
$sudo mkdir -p /var/ftp/jail-2/subdir
$sudo touch /var/ftp/jail-1/here-is-jail1
$sudo touch /var/ftp/jail-2/here-is-jail2
```

ftpサービスを再起動する。

```bash
$sudo systemctl restart vsftpd
```

# 動作検証

ftpサーバーに接続。

```
$ftp
ftp>open localhost
Name (localhost:centos): ftpuser1
331 Please specify the password.
Password:
230 Login successful.
```

ftpuser1でログインした場合、/var/ftp/jail-1が
ルートディレクトリになっていることがわかる。

```
ftp> pwd
257 "/"
ftp> ls
150 Here comes the directory listing.
-rw-r--r--    1 0        0               0 Feb 24 15:53 here-is-jail1
drwxr-xr-x    2 0        0               6 Feb 24 15:53 subdir
226 Directory send OK.
```

chrootで指定したディレクトリから外には移動できない。

```
ftp> pwd
257 "/"
ftp> cd /home/ftpuser1
550 Failed to change directory.
```
ルートディレクトリより上に移動すると、移動は成功するが
実際にはchroot後のルートディレクトリからは移動しない。

```
ftp> pwd
257 "/"
ftp> cd ..
250 Directory successfully changed.
ftp> pwd
257 "/"
```



サブディレクトリには移動できる。

```
ftp> cd /subdir
250 Directory successfully changed.
ftp> pwd
257 "/subdir"
```

# 設定ファイル（vsftpd.conf）のオプションについて

マニュアルからよく利用しそうなオプションを抜粋。

### デーモンの設定

- listen
    - デフォルト：NO
    - 設定ファイル：NO
    - YESに設定した場合、スタンドアロンモードで起動する。スタンドアローンモードではvsftpd自身が、入ってくる接続を待ち、処理する面倒をみる。

### ログインオプションとアクセス制御に関する設定

- anonymous_enable
    - デフォルト：YES
    - 設定ファイル：YES
    - YESにすると匿名ユーザーによるログインが可能となる。 匿名ユーザーはパスワードなしのログインが可能
- cmds_allowed
    - デフォルト：なし
    - 設定ファイル：-
    - 許可するFTPコマンドをカンマ区切りで設定する。
- local_enable
    - デフォルト：NO
    - 設定ファイル：YES
    - YESにすると/etc/passwdに記述されたローカルユーザーによるログインを許可する。 
- userlist_deny
    - デフォルト値：YES
    - 設定ファイル：-
    - このオプションはuserlist_enableが有効な場合にのみ意味を持つ。 NOにした場合、userlist_fileで指定したファイルに明示的にリストされた ユーザ以外はログインが拒否される。
- userlist_enable
    - デフォルト値：NO
    - 設定ファイル：YES
    - 有効にした場合、userlist_fileで指定したファイルをユーザ名の リストとして読み込む。 このファイルに名前のあるユーザでのログインしようとすると、 パスワードを尋ねられる前に拒否される。
- userlist_file
    - デフォルト値：/etc/vsftpd/user_list
    - 設定ファイル：-
    - userlist_deny, userlist_enableで利用するuser_listファイルの  場所を指定する。

### ローカルユーザーの設定

- chmod_enable
    - デフォルト：YES
    - 設定ファイル：-
    - YESに設定した場合、パーミションを変更するSITE CHMODコマンドを許可する。
- chroot_list_enable
    - デフォルト：NO
    - 設定ファイル：-
    - YESに設定した場合、ログイン後にホームディレクトリへとchrootされるローカルユーザのリストを指定できる。chroot_local_userをYESに設定した場合には、意味が異なってくる。リストはその場合、chroot jailへと移動されないユーザのリストとなる。デフォルトでは、このリストは/etc/vsftpd.chroot_listファイルであるが、
chroot_list_file設定によってこれを変更することができる。
- chroot_list_file
    - デフォルト：/etc/vsftpd.chroot_list
    - 設定ファイル：-
    - ホームディレクトリ内のchoot jailに入れられるローカルユーザのリストを示すファイル名を指定する。                 このオプションは、chroot_list_enableが有効な場合にのみ意味を持つ。もしchroot_local_userが有効であれば、このリストは chroot jail に入れられ*ない* ユーザのリストになる。
- chroot_local_user
    - デフォルト：NO
    - 設定ファイル：-
    - YES に設定した場合、ローカルユーザは(デフォルトで)ログイン後に ホームディレクトリへとchrootされる。
- local_root
    - デフォルト：なし
    - 設定ファイル：-
    - ローカルログイン(すなわち、非anonymousログイン)の後に変更するディレクトリを指定する。
- local_umask
    - デフォルト：077
    - 設定ファイル：022
    - ローカルユーザが生成したファイルの umask 値。設定値の先頭の0がないと、10進数として扱われるため注意。
- passwd_chroot_enable
    - デフォルト：NO
    - 設定ファイル：-
    - chroot_local_userと共にYESに設定した場合、chroot jailの場所はユーザごとになる。jailは/etc/passwdにある各人のホームディレクトリから得られる。ホームディレクトリを表わす文字列に  /./があれば、そのパスの場所が jail になる。
- user_config_dir
    - デフォルト：なし
    - 設定ファイル：-
    - 設定オプションをユーザーごとに上書きすることができる。例えばuser_con‐fig_dirを/etc/vsftpd_user_confに設定しユーザー"chris"がログインした場合、そのセッションの間 /etc/vsftpd_user_conf/chris というファイルにある設定が適用される。

### ディレクトリのオプション

- dirlist_enable
    - デフォルト：YES
    - 設定ファイル：なし
    - YESにした場合、ディレクトリ表示コマンドが使用可能となる。
- force_dot_files
    - デフォルト：NO
    - 設定ファイル：-
    - YESに設定した場合、クライアントが "a"フラグを使用していなくても、ドット(.)で始まるファイルとディレクトリも、ディレクトリリストに表示する。
- hide_ids
    - デフォルト：NO
    - 設定ファイル：-
    - YES に設定した場合、ディレクトリリストでのユーザ・グループの情報を "ftp" と表示する。
- text_userdb_names
    - デフォルト：NO
    - 設定ファイル：-
    - ディレクトリリストを表示した場合、デフォルトではユーザとグループのフィールドがIDの数値で表示される。
このオプションをYESにすれば、名前を示す文字列になる。
性能上の理由から、デフォルトはNOである。
- use_localtime
    - デフォルト：NO
    - 設定ファイル：-
    - 有効にした場合、ディレクトリリストの表示にローカルのタイムゾーンを使用する。