在 CentOS 7.x 环境下使用 vsftpd 搭建 ftp 服务器、配置 SSL 并使用虚拟账号访问。


1. 基本说明

FTP 提供了三种访问方式:匿名访问、本地用户(Local User)访问,以及虚拟用户(Virtual User)访问。

本地用户就是服务器本地的用户,即可通过 SSH 远程登录服务器的用户。虚拟用户则是仅用于 FTP 服务的用户,而非真实的 Linux 用户(但是需要与一个本地用户进行绑定)。

本文内容为:

  1. 创建一个用于绑定虚拟用户的本地账户 (myFtp),但该用户无法通过 SSH 登录服务器。
  2. 启用 vsftpd 服务并完成配置。
  3. 定义一个虚拟用户 (myVirtualUser), 使用者可在 FTP 客户端中用该用户进行登录。
  4. 配置 TLS 加密传输。
  5. 设置防火墙

FTP 客户端使用 fileZilla 进行访问。

2. 创建本地用户

创建用户名为 “myFtp” 的账户,禁止其通过 shell 登录,并将 home 设置为 /data/vsftpd/

需要注意的是,在 myFtp 的 home 目录下,需要手动为虚拟用户 myVirtualUser 创建根目录(以及设置文件所有权)

1
2
3
4
5
sudo useradd -s /usr/sbin/nologin -d /data/vsftpd myFtp

sudo mkdir /data/vsftpd/myVirtualUser

sudo chown -R myFtp:myFtp /data/vsftpd

3. 安装 vsftpd

基本思路为,由 vsftpd (Very Secure File Transfer Protocol Deamon) 提供 FTP 服务,由 PAM 完成账号验证。使用自签名的 RSA 证书实现 SSL 访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 更新 yum packages (可选)
sudo yum -y update

# 安装 vsftpd
sudo yum install -y vsftpd

# 开机启动
sudo systemctl enable vsftpd

# 运行vsftpd
sudo systemctl start vsftpd

# 查看运行状态
systemctl status vsftpd

4. 修改 vsftpd.conf

vsftpd 配置文件的位置:/etc/vsftpd/vsftpd.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 备份原配置文件
sudo cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.original

# 使用 tee 命令将配置内容写入 vsfptd.conf, 也可 sudo vim /etc/vsftpd/vsfptd.conf 进行编辑
echo '
# 禁用匿名访问,必须显式设置 NO, 仅备注则仍可进行匿名访问
anonymous_enable=NO
# 启用 Local User 的访问
local_enable=YES
# 允许 Local User 的写入权限
write_enable=YES
# 虚拟账号的权限与关联的 Local User 相同
virtual_use_local_privs=YES

# 使用验证文件 /etc/pam.d/vsftpd.virtual
pam_service_name=vsftpd.virtual

# 所有登录用户均视为 "guess",并匹配 $guest_username 指定的账号
guest_enable=YES
# 关联的 Local User 账号
guest_username=myFtp

user_sub_token=$USER
local_root=/data/vsftpd/$USER
# 限制用户登录后的访问目录
chroot_local_user=YES
allow_writeable_chroot=YES

# 日志配置
xferlog_enable=YES
vsftpd_log_file=/var/log/vsftpd.log
log_ftp_protocol=YES

# 在客户端中隐藏文件所属用户和组信息,全部显示为"ftp"
hide_ids=YES

#开启被动模式。
pasv_enable=YES
# 限制被动连接的端口范围
pasv_min_port=53000
pasv_max_port=53010
' | sudo tee /etc/vsftpd/vsftpd.conf

# 重启 vsftpd 服务,重新加载配置文件
sudo systemctl restart vsftpd

5. 设置 pam 验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义虚拟用户的账号与密码(第一行为 account, 第二行为明文 password,可以同时定义多个用户),
# 写入到 /tmp/ftp_users.txt 文件
echo 'myVirtualUser
123456' > /tmp/ftp_users.txt

# 将 ftp_users.txt 输出为 Berkeley DB 文件 (ftp_users.db)
sudo db_load -T -t hash -f /tmp/ftp_users.txt /etc/vsftpd/ftp_users.db

# PAM 验证
echo '#%PAM-1.0
auth required pam_userdb.so db=/etc/vsftpd/ftp_users
account required pam_userdb.so db=/etc/vsftpd/ftp_users
session required pam_loginuid.so
' | sudo tee /etc/pam.d/vsftpd.virtual

vsfptd.conf 配置文件中,pam_service_name=vsftpd.virtual 指定了 FTP 使用 Linux PAM 进行鉴权。鉴权方式由 vsftpd.virtual 文件配置,该文件位于目录 /etc/pam.d/

/etc/pam.d/vsftpd.virtual 文件中指定的 pam_userdb.so db=/etc/vsftpd/ftp_users 则指向通过 db_load 生成的 db 文件。

一个安全问题:

以上通过组合命令的方式将账号密码写入到 /tmp/ftp_users.txt 后,该记录会留在 history 中,由于是个人服务器,因此可以直接使用 history -c 清空历史记录,否则该账号密码仍可通过 history 查看,因此推荐使用 vim 编辑的方式。

6. chroot

chroot 可以修改登录用户的根目录,即将用户的访问限制在指定范围,起到”囚禁”的效果。

以上 vsfptd.conf 配置中,定义了不同 FTP 匿名用户登录后只能访问各自的目录,根据以上的配置,myVirtualUser 的访问范围将限制在 /data/vsftpd/myVirtualUser/, 如果有另一个虚拟用户 vUser2, 则登录后只能访问 /data/vsftpd/vUser2/(注意在虚拟用户登录前,必须先创建该目录并通过 chown 保证用户 myFtp 对目录有所需权限)。

除此之外,可以配置 vsftpd.conf local_root=/data/vsftpd/,去掉 $USER 变量,使得所有虚拟用户登录后都被限制在 /data/vsftpd 中,则无需创建相应的目录并修改所有权。

7. 配置 TLS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 安装 openssl, 已安装可跳过
sudo yum install -y openssl

# 创建目录用于存放证书文件
sudo mkdir /etc/ssl/private

# 创建自签名 RSA 证书。创建时可以设置证书的信息。
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/vsftpd.pem -out /etc/ssl/private/vsftpd.pem


# 在 vsftpd.conf 中追加 SSL/TLS 的配置,也可以使用 vim 进行编辑
echo '
# SSL
ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
listen_port=990
' | sudo tee -a /etc/vsftpd/vsftpd.conf

# 重启服务
sudo systemctl restart vsftpd

8. 配置防火墙

在云服务器的控制台中设置允许外部对 990, 53000-53010 端口的访问。

或通过 firewalld 在服务器内部进行配置:

1
2
3
4
5
6
sudo firewall-cmd --zone=public --add-port=990/tcp --permanent

sudo firewall-cmd --zone=public --add-port=53000-53010/udp --permanent

# 重启防火墙服务
sudo systemctl restart firewalld

9. 参考资料