使用 AWS Transfer 搭建托管的SFTP服务

一、简介

来自AWS官网的简介:

AWS Transfer 系列提供完全托管支持,可将文件直接传入和传出 Amazon S3。 AWS Transfer 系列使用安全文件传输协议 (SFTP)、SSL 的文件传输协议 (FTPS) 和文件传输协议 (FTP),可通过集成现有身份验证系统并提供与 Amazon Route 53 的 DNS 路由,帮助您将文件传输工作流程无缝迁移到 AWS,而对于客户和合作伙伴及其应用而言则没有任何变化。通过 Amazon S3 中的数据,您可以配合 AWS 服务完成数据处理、分析、机器学习和存档。AWS Transfer 系列部署非常简单,无需购买和设置任何基础设施。

二、背景

本文需求:

  • 所有用户数据存储在一个S3桶的不同目录下,例如命名为sftp-demo-01;
  • 假设有100个用户,每个用户各自有独立的主目录,用户自己在自己的目录内是完全Owner,上级目录不可见,用户之间不可见,例如命名为 user01 和 user02;
  • 所有用户采用统一的IAM策略和角色实现,不需要为上百个用户单独建立额外的角色,此特性被称为“scope-down”策略;
  • 数据使用SFTP协议,不考虑不加密的普通FTP协议;
  • 身份认证采用AWS Transfer服务内置的证书认证方式,AWS Transfer服务器端保存公钥,客户端保存私钥,每个用户有单独的一对证书,例如用户user01的证书是user01.pem 和user01;user02的证书是user02.pem和user02;
  • 由于密码认证方式配置复杂,参考这篇官方文档,因此本次项目不使用密码认证;
  • 所有客户端采用Windows桌面,不使用VPN等手段不接入VPC内,直接通过互联网访问Transfer入口;
  • 登陆地址采用第三方域名CNAME解析到AWS的方式;
  • 客户端工具使用Filezilla;
  • 所有用户权限采用统一的IAM Role进行管控;
  • 以上配置采用手工操作生成,而后采用脚本方式批量生成。

由此构建的架构图如下。

三、建立S3存储桶

建立存储桶的过程相对比较简单,使用 sftp-demo-01 的名字,并建立 user01user02 两个目录。

因此S3桶内的目录结果如下。

/user01
/user02

在以上过程中,所有S3桶设置均保持默认。也就是说,无需打开S3存储桶的Versioning等高级功能,无需设置桶ACL策略,阻止公有访问的选项默认是启用状态,意味着本存储桶的所有文件都是私有不发布在互联网上。

四、创建IAM策略和角色

1、创建IAM策略

进入IAM模块,点击左侧菜单,点击策略。在右侧点击创建策略。在创建策略界面,当前默认选中的是“可视化编辑器”,点击旁边的“JSON”按钮,切换到文本编辑器。

删除掉JSON文本编辑器内已经存在的几行代码,并用如下的策略代替。本文以 sftp-demo-01 为例,请替换其中的S3桶的名字为您自己创建的S3桶的名字。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListingOfUserFolder",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::sftp-demo-01"
            ]
        },
        {
            "Sid": "HomeDirObjectAccess",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObjectVersion",
                "s3:DeleteObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::sftp-demo-01/*"
        }
    ]
}

点击右下角的“查看策略”按钮,继续下一步。

在下一步查看策略的界面,输入名称 sftp-users ,在描述位置可选输入描述,如果输入的话只能使用英文,例如输入 for sftp users to allow them only access their home directories ,然后点击右下角的创建策略按钮。

2、创建IAM角色

在IAM模块内,点击左侧的“角色”按钮,点击页面右侧的“创建角色”按钮。

在选择“选择受信任实体的类型”界面,默认选择第一个类型“AWS产品”,然后在“使用案例”的下方找到“或者选择一个服务以查看其使用案例”,从服务列表中选择“Transfer”,点击右下角的“下一步权限”按钮继续。

在“Attach 权限策略”界面,从筛选策略的文本框中,输入 sftp 也就是上一步创建策略时候使用的名字,即可成功筛选出来上一步创建的策略。选中之,点击“下一步标签”继续。

标签设置过程可略过,点击“下一步审核”按钮继续。

在审核界面,输入角色名称 sftp-users,在右下角点击“创建角色”完成角色的创建。

3、验证IAM角色的信任关系正确

本步骤是一个验证步骤,在大部分情况下AWS账号完成了第二步创建IAM角色后,这一步是系统内置已经存在的,无须任何操作的。因此按照本文进行检查即可。

在IAM模块内,点击左侧的“角色”按钮,在页面右侧收缩刚才创建的IAM角色 sftp-users,进入摘要界面。点击第二个标签页 “信任关系”,在点击编辑信任关系。

检查页面上限制的配置是否与以下相符。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "transfer.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

如果已经相符的话,检查完毕,继续下一步。

五、创建Transfer服务

从控制台进入Transfer服务界面,如果此前没有任何服务被创建,此时会打开向导界面,在页面右上方会提示显著的按钮“Create Server”。如果曾经创建过服务,那么可以从左侧菜单点击“Servers”菜单,再点击右侧的“Create Server”即可进入创建向导。

1、选择协议

创建向导第一步,选择协议,在“Choose protocols”只选中第一个“SFTP”协议,点击下一步继续。

2、选择认证方式

在向导第二步,选择认证方式“Identity provider”界面,选择左侧的“Service managed”,即使用Transfer服务自己的认证方式。点击下一步继续。

3、选择Endpoint入口域名

在向导第三步,选择“Endpoint type”的类型是“Publicly accessible”,即允许从互联网上的公开访问。

在“Custom hostname”下拉框位置,选择第三项“Other DNS”,然后输入一个将要分配给本服务的统一接入域名,例如输入 sftp.abc.com 。注意这个域名需要您额外注册和管理,并且在创建完成后要为这个域名创建一个CNAME解析,将这个域名指向AWS的Transfe服务。

输入完成后,点击下一步继续。

4、设置服务器参数

在“Logging role”界面,是为Transfer服务设置一个写入日志到CloudWatch的角色。这个角色不是用户登陆并上传IAM到S3的角色,它仅是一个记录日志的角色。因此这里就选择默认的“Create a new role”即可。

在“Cryptographic algorithm options”选项,保持默认加密选项不要修改。

在“Server Host Key”位置留空不要填写任何信息。

在“Tag”位置可选填写,也可以留空。点击右下角Next按钮来到Review界面。

5、完成创建

在Review界面,无须修改任何参数,点击“Create Server”完成创建。

在Transfer服务的Server界面,等待几分钟后,刷新界面,只到本Server的“State”状态显示为“Online”,即表示创建完成。

6、查看登陆地址

在Servers界面,点击“Server ID”即可查看为本服务器的详情。

在“Endpoint Detail”界面下,可以看到“Custom Hostname”和“Endpoint”。

其中Custom Hostname就是前文输入的客户自己的域名,请添加一个CNAME解析,指向下文的“Endpoint地址”。Endpoint的形式是 s-c89bfd7c5b974cfea.server.transfer.ap-southeast-1.amazonaws.com 这样的地址。如果不添加这个CNAME解析,直接把Endpoint分发给最终用户,也可以进行正常登陆,但是不方便后续管理,一旦重新创建服务器,Endpoint地址会产生变化,则所有登陆都将失效。由此建议使用CNAME解析。

六、添加用户

1、使用Linux/MacOS的终端生成用户证书

在前文背景章节已经讲述采用证书认证的原因,接下来生成证书。环境建议采用MacOS自带的终端,或者在任意区域创建一个Amazon Linux 2系统,或者是本地的CentOS等系统均可。生成证书的机器可以为其他客户端批量生成证书。

执行如下命令创建 user01 对应的证书。

ssh-keygen -P "" -f user01

返回结果如下。

$ ssh-keygen -P "" -f user01
Generating public/private rsa key pair.
Your identification has been saved in user01.
Your public key has been saved in user01.pub.
The key fingerprint is:
SHA256:/WyTTR7eep/rvC6l10Ezrcwxz4DzMUNXgYdrGsv2GEg lxy@8c85905f3ef5.ant.amazon.com
The key's randomart image is:
+---[RSA 3072]----+
|              o.+|
|             o...|
|             oo..|
|         E .ooB+.|
|        S + ==+@o|
|         . O *==o|
|          . X * +|
|           o =.o+|
|              *O=|
+----[SHA256]-----+

$ 

通过 ls -l 命令可以查看这一对密钥文件,结果如下。

$ ls -l
total 16
-rw-------  1 lxy  ANT\Domain Users  2622 Sep 29 14:19 user01
-rw-r--r--  1 lxy  ANT\Domain Users   585 Sep 29 14:19 user01.pub

$

这里可以看到一个扩展名带 .pub 的文件是公钥,需要上传到AWS上,另一个不带任何扩展名的文件是私钥,需要发给最终用户用于登陆SFTP服务。

执行 cat user01.pub 命令,显示user01的公钥的全文。返回结果如下。

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC3vaR6+FbJygJpr5BLjlzmnEoIOKeV52S+k0h3dbOEr08JMtCtVYua2xqR6r87jMpG85ajdRyK4VBQGRqipM+mXC/fIokuUEpsBr9dQ13KY7fCM8A4exIAQNaec2s9ydvs2L/CFqmE919ZX8Jjekbb1zO4UHmsvbrughf0NPWT6+WHoubslLXL0UkYI8x0+zm+7/KchGxVLSJko58bmtQiU4deCpwT64kxWFlQTbCupIWH5LYYvDREmsAXlIeoicOc+SEr2fy5roqhpg5wc5rVCu9iJiAT/U6hm7KHvM1ZBZPvBACI2A3FmKmQLYiG9xTlvBN5dm37lGMeb9XG+SGrKmvZ5DkTNkwwR/JY79Z24vC79a2WxPEcfYYE9VjwQHRG+rsXVePeyMX2eN3QoxBk8w032i7H6kAkdJLuUZDCidN9HfY1kvxM3ADqzs/96ZHInSLimXW/peRBw3+GJgMbuIQPpciaLi0thbMbb9k5jxMQNxVH0HplK0xkqpxKWls= lxy@8c85905f3ef5.ant.amazon.com

将以上一段文字复制下来,稍后需要粘贴到界面上。复制时候注意包含开头的ssh-rsa和最后的主机名,不包含换行。

重复以上过程,生成user02的证书,稍后用于测试user01和user02自建的权限隔离特性。

2、创建“Scope-down”策略

Scope-down策略允许在一个S3桶内,分别为每个用户创建一个子目录,然后将用户权限限定到子目录内。由此只需要一个IAM策略即可为上百个用户限制权限。

进入IAM模块,点击左侧菜单,点击策略。在右侧点击创建策略。在创建策略界面,当前默认选中的是“可视化编辑器”,点击旁边的“JSON”按钮,切换到文本编辑器。

输入以下内容,本文以 sftp-demo-01 为例,请注意替换其中的S3桶名为您自己的桶的名字。其他保持不变。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowListingOfUserFolder",
            "Action": [
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::sftp-demo-01"
            ]
        },
        {
            "Sid": "HomeDirObjectAccess",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObjectVersion",
                "s3:DeleteObject",
                "s3:GetObjectVersion"
            ],
            "Resource": "arn:aws:s3:::sftp-demo-01/${transfer:UserName}/*"
        }
    ]
}

在查看策略界面,名称输入sftp-scope-down,描述可留空不输入,点击右下角的创建策略按钮完成。

3、在AWS Transfer界面创建新的用户

在Transfer服务界面上,点击“Servers”按钮,进入SFTP服务界面,在右侧的页面中部,找到“Users”位置,点击“Add user”添加用户。

在“Username”位置输入 user01 ,即要创建的用户名。请事先确认本文第一步,已经创建好S3桶,和S3桶下对应的目录。

在“Achess”下拉框中,通过搜索方式,定位并选中前文创建的IAM角色“sftp-users”。

在“Policy”下拉框中,选中第三项“Select a policy from IAM”,然后通过下拉框搜索前文创建的Scope-down策略,本文使用的名字是sftp-scope-down,选中之。注意,如果修改过IAM策略,这里需要点击右侧的刷新按钮,才可以立刻显示出来刚才添加的IAM策略。如果是在进入Transfer界面之前创建好的IAM策略,这里就无须点击刷新按钮了。

在“Home directory”选项中,从下拉框总选择前文创建的s3桶 sftp-demo-01,下方的 “Enter Optional folder” 这里填写为本用户的用户名即user01。此外下方还有一个 “Restricted” 选项,选中之,表示限制用户访问只能在自己目录内。

在页面下方“SSH public keys”位置,将前文复制下来的user01.pub的内容,粘贴到此处。这里的控制台上的文本输入框只有一行高度,不用介意,直接粘贴即可。

最下方“Tag”是可选输入,点击页面右下角的“Add”按钮完成创建。

4、注意事项

  • 由于数据是存在S3上的,因此当删除了用户后,数据不会删除。如果重新建立一个相同用户名的用户,就又可以继续看见以前用户的数据了,因此请特别注意用户轮换。
  • 修改密钥是通过删除当前用户下的SSH Key并更换新的Key实现的,因此更换密钥不影响现有数据。
  • 每个用户需要有一个独立的ssh key,因此创建user01完毕后,创建user02时候,需要重复上文步骤,新生成一个ssh key命名为user02,然后填写到界面中。

至此用户添加完成。

七、验证操作

本文通过开源、免费的FTP客户端Filezilla进行连接测试。Filezilla是跨平台的FTP客户端,有原生的Windows版本、MacOS版本,支持FTP协议、SFTP协议等。

启动Filezilla后,点击左上角的第一个按钮,即“Site Manager”。

打开Site Manager后,点击左侧下方的“New Site”按钮,在右侧的“General”标签页下,选择“Protocol”是SFTP协议。

在“Host”位置粘贴前文查看服务器时候获得的Enpoint。注意粘贴后可能文本框中依然显示是空白的,这是由于粘贴时候自动包含了一个换行符造成的。请按键盘左键,即可看到正常输入了完整地址。例如如下地址 s-c89bfd7c5b974cfea.server.transfer.ap-southeast-1.amazonaws.com 。在“Port”端口中填写22。

在“Logon Type”位置,从下拉框中选择“Key file”,在“User”位置填写user01,这个地方需要与创建用户时候使用的用户名对应匹配。在“Key file”文本框中,点击浏览,选择分发给这个用户的证书文件。

点击最下方“Connect”按钮,即可完成链接。

完成登陆后,用户只能看到当前位置就是根目录,用户对自己的目录有完全的读写权限。用户感觉不到自己是处在user01的虚拟目录中,也无法访问user02的文件。

至此操作完成。

八、参考资料

AWS Transfer在一个账号内允许10个SFTP服务,每个服务允许100000个User级别账号,因此日常使用不会超过用户数限制。

编写Scope-down策略的参考文档如下。

https://docs.aws.amazon.com/transfer/latest/userguide/users-policies.html#users-policies-scope-down