AWS使用日志6--使用TransferFamily替代SFTP服务器

AWS Transfer Family 是一个托管的 SFTP/FTPS/FTP 服务,可让外部用户安全访问你的 S3 bucket 或 EFS 文件系统。
它不需要你再维护 EC2、Nginx、sshd 等,只要定义用户身份映射即可

目标

  1. 为每个系统用户创建一个 Transfer Family 用户(Service-managed 模式)
  2. 使用 SSH 公钥登录,而非密码
  3. 将每个用户的 /home/ 数据同步到各自的 S3 前缀目录

实践

由于原SFTP服务器使用密码登录,现在需要改为key登录,所以我们需要在原SFTP服务器上为每一个用户创建新的key并绑定到transer上,同时需要为每一个用户都设置一个IAM Role

为EC2创建IAM Role

信任实体:ec2.amazonaws.com
需要权限:
transfer:CreateUser
s3:ListBucket

为用户创建IAM Role(TransferAccessRole)

信任实体:transfer.amazonaws.com
在创建transfer server的用户时,我们需要为每一个用户绑定一个IAM role

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::transfer-test"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::transfer-test/*"
}
]
}

或者如果权限想设置的严格一点,可以用这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": "arn:aws:s3:::my-sftp-bucket",
"Condition": {
"StringLike": {"s3:prefix": ["${transfer:UserName}/*"]}
}
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::my-sftp-bucket/${transfer:UserName}/*"
}
]
}

创建transfer server

AWS Transfer Family 提供 三种主要认证方式:

模式 用户管理方式 登录方式 优点 缺点
Service managed 在 AWS 控制台/CLI 创建用户,密码存 Secrets Manager 用户名 + 密码 / SSH key 最简单、官方托管 密码需你重新设置,无法迁移系统密码
Custom identity provider 自定义(Lambda + API Gateway) 用户名 + 密码 / SSH key 可完全控制用户验证逻辑 实现成本高(需开发)
Directory Service (AD) 使用 AWS Managed AD 域账号 + 密码 与企业 AD 集成 适合企业环境,不适合你这种本地账号场景

三种 Endpoint 类型

类型 说明 网络访问 典型使用场景
Publicly accessible (Public endpoint) AWS 托管公网端点(自动分配域名) 🌍 互联网上任何地方可访问 外部合作伙伴、客户上传文件
VPC hosted (VPC endpoint) 在你指定的 VPC/Subnet 内运行 🔒 仅限 VPC 内或通过 VPN/Direct Connect 访问 内部系统使用、合规隔离要求
VPC endpoint with custom hostname 同上,但绑定自定义域名(例如 sftp.company.com) 🔒 + 🌍(取决于你DNS配置) 对外统一品牌域名或混合云场景

✅ 1️⃣ Public endpoint(最常用)
优点:
最简单的部署;
AWS 自动生成域名:
s-xxxxxxxxx.server.transfer.ap-southeast-1.amazonaws.com
无需配置 VPC、安全组、子网;
直接支持 SFTP/FTPS。

适合场景:
你现在的老 SFTP 服务器是公网访问的;
用户分布在互联网;
没有合规要求必须在私网中运行。

⚙️ 推荐配置:
Endpoint type:Publicly accessible
Protocols:SFTP(如有安全要求再开 FTPS)
AZs:3个(免费)
Logging:启用 CloudWatch Logs(方便审计)

✅ 2️⃣ VPC hosted endpoint(私有部署)

特点:

SFTP 服务器运行在你的 VPC 内;
只能通过:
VPC 内 EC2;
VPN;
或 Direct Connect 访问;
你可以精确控制安全组、NACL、子网。

适合场景:
企业内部文件传输;
必须走专线 / VPN;
不能暴露在公网(例如金融机构)。

⚙️ 推荐配置:
Endpoint type:VPC hosted
VPC:选择你当前的 VPC
Subnets:建议选 3 个不同 AZ
Security group:允许 22(SFTP)或 990/21(FTPS)端口
Route:确保能访问 S3(通过 Gateway Endpoint 或 NAT)

✅ 3️⃣ VPC endpoint + Custom hostname(品牌域名)
特点:
功能与 VPC endpoint 相同;
额外允许你绑定自定义域名(例如 sftp.company.com);
需在 Route53 或外部 DNS 设置 CNAME;
支持 TLS 证书(ACM 管理)。

适合场景:
希望用户使用品牌域名;
有自己的 TLS 证书;
混合云或多区域部署。

⚙️ 推荐配置:
Endpoint type:VPC endpoint
Custom hostname:sftp.company.com
ACM Certificate:选你的自定义证书
DNS 记录:在外部或 Route53 建立 CNAME → Transfer endpoint

Security Policy

Security Policy(安全策略)决定了当客户端(例如 FileZilla、WinSCP、程序里的 SFTP 模块)连接到你的 AWS Transfer 服务器时,双方在握手过程中可以使用哪些:

Kex(Key Exchange):密钥交换算法
MAC(Message Authentication Code):消息完整性验证算法
SSH Ciphers / TLS Ciphers:加密算法
简单来说,就是越新的规则越严格,如果要兼容老系统,那么就可以设置的不是那么新

Logical Directories

这是一个虚拟目录映射功能,让你的 S3 bucket 看起来像传统服务器的文件结构。
AWS Transfer Family 本质上是把用户操作的路径(/home/alice/data.txt)映射到 S3 上的对象路径(s3://my-bucket/users/alice/data.txt)。
如果不用 Logical Directory,你的用户登录后看到的是实际 S3 路径结构;
但用它之后,你可以人为定义“友好的路径”。
这对于:

  • 多用户共享一个 bucket
  • 用户目录比较深或复杂
  • 需要隐藏真实 bucket 结构
    都非常有用。

Optimized Directories

这是 AWS 在 2024 年推出的新功能,专门提升 SFTP 列目录(ls 命令)性能的。
默认情况下,Transfer Family 在列出 S3 文件夹内容时,底层其实是在调用:
ListObjectsV2 API(S3 原生接口)

这个接口在文件很多时(比如一个目录里上万文件)会非常慢。
开启 Optimized directories 后,AWS 会自动为你的 S3 目录构建索引(metadata index),加快查询。
结果就是:
ls、dir 命令响应几乎是秒级
大目录列出性能提升 10~100 倍
不需要改变现有 S3 结构

✅ 注意事项
只适用于 S3 backend(不是 EFS)
AWS 在后台自动维护索引(你不用手动干预)
不会额外收费,但会略微增加 S3 API 调用频率

SetStat option

AWS 给你两个选择:

设置 含义 行为
Ignore SetStat = true 忽略 SETSTAT 命令(推荐) 客户端执行修改属性时不会报错,只会在 CloudWatch 日志中记录
Ignore SetStat = false 不忽略(默认) 当客户端尝试修改属性时,返回“Operation not supported”错误

✅ 建议做法:
如果你用的是 S3 作为存储后端,请启用 “Ignore SetStat”。

原因:
绝大多数 SFTP 客户端都会自动尝试执行 SETSTAT(例如 WinSCP 上传后自动设置时间戳)。
如果不忽略,它会在每次上传后报错(虽然文件其实上传成功了,但用户会看到红色错误信息)。
启用忽略后,用户体验更好,日志仍然会在 CloudWatch 中保留。

创建一个新的S3 Bucket

这个不必多说,直接创建一个general purpose bucket即可

(可选)在EC2上通过脚本创建测试用户及文件

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
#!/bin/bash
# 批量创建 SFTP 测试用户并生成随机文件
# 适用于 Amazon Linux / CentOS / Ubuntu

USER_COUNT=5 # 要创建的用户数量
BASE_NAME="sftpuser" # 用户名前缀
PASSWORD_FILE="./user_passwords.txt"

# 清空旧的密码记录
echo "生成日期: $(date)" > $PASSWORD_FILE

for i in $(seq 1 $USER_COUNT); do
USERNAME="${BASE_NAME}${i}"
PASSWORD=$(openssl rand -base64 12)

# 创建用户(带 home 目录),禁止 SSH 登录,仅用于 SFTP
useradd -m -s /sbin/nologin "$USERNAME"

# 设置密码(可选)
echo "${USERNAME}:${PASSWORD}" | chpasswd

# 在 home 目录下创建一个随机文件
HOME_DIR="/home/${USERNAME}"
FILE_PATH="${HOME_DIR}/file_$(date +%s)_$RANDOM.txt"

echo "This is a random test file for ${USERNAME}" > "$FILE_PATH"
echo "Random content: $(openssl rand -hex 8)" >> "$FILE_PATH"

# 修改文件所有权
chown ${USERNAME}:${USERNAME} "$FILE_PATH"

# 输出结果
echo "✅ Created user: ${USERNAME}, password: ${PASSWORD}, file: $(basename $FILE_PATH)" | tee -a $PASSWORD_FILE
done

echo
echo "✅ 所有用户已创建完成,密码已保存到: $PASSWORD_FILE"

在EC2上运行迁移脚本

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
#!/bin/bash
# === Configuration ===
SERVER_ID="s-xxxxxxxxxxxx" # 替换为你的 Transfer Family server ID
ROLE_ARN="arn:aws:iam::123456789012:role/TransferAccessRole"
BUCKET="my-sftp-bucket"
OUTPUT_CSV="transfer_users.csv"
KEY_DIR="./sftp_keys"

mkdir -p $KEY_DIR
echo "username,private_key_path,s3_path" > $OUTPUT_CSV

# === Iterate system users ===
for user in $(ls /home); do
HOME_DIR="/home/$user"
if [ ! -d "$HOME_DIR" ]; then
continue
fi

echo "Processing user: $user"

# Generate SSH key pair
ssh-keygen -t rsa -b 2048 -N "" -f "$KEY_DIR/$user" >/dev/null 2>&1
PUB_KEY=$(cat "$KEY_DIR/$user.pub")

# Create Transfer user
aws transfer create-user \
--server-id $SERVER_ID \
--user-name "$user" \
--role "$ROLE_ARN" \
--home-directory "/$BUCKET/$user" \
--ssh-public-key-body "$PUB_KEY"

# Sync user data to S3
aws s3 sync "$HOME_DIR" "s3://$BUCKET/$user" --exclude ".ssh/*"

# Save record
echo "$user,$KEY_DIR/$user,s3://$BUCKET/$user" >> $OUTPUT_CSV
done

echo "✅ Migration complete. Keys saved in $KEY_DIR, summary in $OUTPUT_CSV."

脚本功能:

  1. 创建transfer user,并为每个用户创建ssh key
  2. 将user与S3 Bucket对应的路径匹配上
  3. 将/home/user下的文件同步到S3
  4. 通过csv文件记录每一个用户的key,以便到时候分发

如何登录

1
2
3
4
5
6
7
8
通过winscp或其他工具登录时,host就不是ip地址,而是transfer server的DNS了
格式如下:
s-xxxxxxxxx.server.transfer.ap-southeast-1.amazonaws.com
username: 刚才生成的用户名
ssh key: 生成的用户私钥

用命令行的话,命令如下
sftp -i ./alice alice@s-xxxxxxxxx.server.transfer.ap-southeast-1.amazonaws.com

价格

收费类别 收费说明 备注
Endpoint 每小时启用费 当你建立一个 SFTP(或 FTPS/FTP/AS2)“服务器端点”(server endpoint)时,每小时按协议计费。例如 SFTP 每小时约 $0.30(美东区域示例)
Amazon Web Services, Inc.
无论有多少用户,只要端点启用,都在计费。
数据上传/下载量(按 GB) 用户通过该 SFTP 上传或下载的数据量,按 GB 收费。例如 SFTP 上传 + 下载按 $0.04/GB(美东示例)
Amazon Web Services, Inc.
只计算通过该服务协议传输的数据,不是 S3 里已有数据本身的存储费用。
其他协议/功能收费 比如 AS2 消息每条、SFTP 连接器调用、工作流处理等有额外费用。
Amazon Web Services, Inc.
若你只用简单的 “用户通过 SFTP 登入,把数据放到 S3” 情况,可能暂时不用这些额外功能。
存储 & 请求 虽然不是 Transfer Family 本身的“主收费”,但你将数据存到 Amazon S3/或 Amazon EFS 后,要支付 S3 的存储费用、请求(GET/PUT)费用、跨区或跨网传输费用等。 这是迁移之后你额外需要预算的。