使用自定义身份提供商 - Amazon Transfer Family
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用自定义身份提供商

要将现有身份提供商集成到Amazon Transfer Family,提供一个带有单个 Amazon API Gateway 方法的 REST 风格界面。Transfer Family 调用此方法来对用户进行身份验证。

此单一方法将对您的用户进行身份验证和授权,以访问 Amazon S3 或 Amazon Elastic File System (Amazon EFS)。配置该方法后,在创建新服务器时将其附加到服务器。您可以使用Amazon Transfer Family控制台CreateServerAPI 操作。

有关使用 Amazon API Gateway 的更多信息,请参阅API Gateway 开发人员指南.

使用自定义身份提供商进行身份

要为 Transfer Family 创建自定义身份提供程序,请使用 API Gateway,它为您提供了一种高度安全的方式来创建和提供 API。使用 API Gateway,您可以创建 HTTPS 终端节点,以便所有传入 API 调用都能以更高的安全性传输。有关 API Gateway 服务的更多详细信息,请参阅API Gateway 开发人员指南.

API Gateway 提供了名为AWS_IAM,它为您提供了相同的身份验证,基于Amazon Identity and Access Management(IAM),Amazon内部使用。如果启用身份验证AWS_IAM,只有具有明确权限调用 API 的调用方才能访问该 API 的 API Gateway 方法。

要将您的 API Gateway 方法用作 Transfer Family 的自定义身份提供商,请为您的 API Gateway 方法启用 IAM。作为此流程的一部分,您将提供一个 IAM 角色,该角色具有 “Transfer Family” 使用您的网关的权限。

注意

为了提高安全性,您可以配置 Web 应用程序防火墙。Amazon WAF是一种 Web 应用程序防火墙,让您能够监控转发到 Amazon API Gateway 的 HTTP 和 HTTPS 请求。有关详细信息,请参阅添加 Web 应用程序防火墙

使用 API Gateway 方法进行自定义身份验证与 Transfer Family

  1. 创建Amazon CloudFormation堆栈。要实现此目的,应按照以下步骤进行:

    1. 打开 Amazon CloudFormation 控制台,地址:https://console.aws.amazon.com/cloudformation

    2. 按照部署Amazon CloudFormation堆栈中的现有模板选择堆栈模板中的Amazon CloudFormation用户指南.

    3. 使用以下基本模板之一创建Amazon Lambda支持的 API Gateway 方法,用作 Transfer Family 列中的自定义身份提供程序。

    部署其中一个堆栈是将自定义身份提供程序集成到 Transfer Family 工作流中的最简单方法。每个堆栈都使用 Lambda 函数来支持基于 API Gateway 的 API 方法。然后,您可以将 API 方法用作 Transfer Family 列中的自定义身份提供程序。默认情况下,Lambda 函数会验证名为myuser,密码为MySuperSecretPassword. 部署完成后,您可以编辑这些凭据或更新 Lambda 函数代码以执行不同的操作。

    重要

    我们建议您编辑默认用户和密码凭据。

    在部署堆栈后,您可以在输出选项卡中的 CloudFormation 版本。这些详细信息包括堆栈的 Amazon 资源名称 (ARN)、堆栈创建的 IAM 角色的 ARN 以及新网关的 URL。

    注意

    如果您使用自定义身份提供商选项为用户启用基于密码的身份验证,并启用了 API Gateway 提供的请求和响应日志记录,则 API Gateway 会将用户的密码记录到 Amazon CloudWatch 日志中。我们建议不要在生产环境中使用此日志。有关更多信息,请参阅 。在 API Gateway 中设置 CloudWatch API 日志记录中的API Gateway 开发人员指南.

  2. 检查服务器的 API Gateway 方法配置。要实现此目的,应按照以下步骤进行:

    1. 通过以下网址打开 API Gateway 控制台:https://console.aws.amazon.com/apigateway/

    2. 选择转移自定义身份提供程序基本模板 API的Amazon CloudFormation已生成模板。

      以下屏幕截图显示了完整的 API 配置。在本示例中,该方法由 Lambda 函数支持,但其他许多集成类型也是可能的。

    3. 资源窗格中,选择GET,然后选择方法请求. 以下屏幕截图显示了正确的方法配置。

    此时,您的 API 网关已经就绪,可以部署。

  3. 适用于操作中,选择部署 API. 适用于部署阶段中,选择Prod,然后选择部署.

    API Gateway 方法成功部署后,请在舞台编辑器部分,如以下屏幕截图所示。

    注意

    将复制到调用 URL地址,显示在屏幕顶部。您在下一个步骤中需要使用此值。

  4. 打开Amazon Transfer Family控制台位于https://console.aws.amazon.com/transfer/.

  5. 选择创建服务器以打开创建服务器页. 适用于选择身份提供商中,选择Custom (自定义),如以下屏幕截图所示。

    调用角色包含Amazon CloudFormation堆栈名称,您为您在步骤 1 中创建的堆栈选择。格式如下:CloudFormation-stack-name-TransferIdentityProviderRole-ABC123DEF456GHI.

  6. 适用于自定义提供商,粘贴调用 URL您在上一步创建的 API Gateway 终端节点的地址。

  7. 适用于调用角色下,选择由Amazon CloudFormation模板。此角色允许 Transfer Family 调用您的 API 网关方法。

  8. 填写其余框,然后选择创建服务器.

测试配置

创建自定义身份提供程序后,应测试配置。

Console

若要测试配置,请使用Amazon Transfer Family控制台

  1. 打开Amazon Transfer Family控制台位于https://console.aws.amazon.com/transfer/.

  2. 在存储库的服务器页面上,选择您的新服务器,选择操作,然后选择测试.

  3. 输入文本用户名密码当您部署Amazon CloudFormation堆栈。如果您保留默认选项,则用户名为myuser,密码为MySuperSecretPassword.

  4. 选择服务器协议,然后输入源 IP,如果您在部署Amazon CloudFormation堆栈。

    如果用户身份验证成功,则测试返回StatusCode: 200HTML 响应和包含用户角色和权限详细信息的 JSON 对象,如以下屏幕截图所示。

CLI

若要测试配置,请使用AmazonCLI

  1. 运行测试身份提供程序命令。

    aws transfer test-identity-provider --server-id s-1234abcd5678efgh --user-name myuser --user-password MySuperSecretPassword --server-protocol FTP --source-ip 127.0.0.1
  2. 输入服务器 ID。

  3. 输入您在部署Amazon CloudFormation堆栈。如果您保留默认选项,则用户名为myuser,密码为MySuperSecretPassword.

  4. 输入服务器协议和源 IP 地址(如果您在部署Amazon CloudFormation堆栈。

    如果用户身份验证成功,此命令将返回StatusCode: 200HTML 响应和包含用户角色和权限详细信息的 JSON 对象,如以下示例所示。

    { "Response": "{\"Policy\": \"{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n{\n \"Sid\": \"ReadAndListAllBuckets\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"s3:ListAllMybuckets\",\n \"s3:GetBucketLocation\",\n \"s3:ListBucket\",\n \"s3:GetObjectVersion\",\n \"s3:GetObjectVersion\"\n],\n \"Resource\":\"*\"\n}\n]\n}\",\"Role\": \"arn:aws:iam::000000000000:role/MyUserS3AccessRole\",\"HomeDirectory\": \"/\"}", "StatusCode": 200, "Message": "", "Url": "https://abcde1234.execute-api.us-east-2.amazonaws.com/prod/servers/s-123a4567bcd891e23/users/myuser/config" }

实施 API Gateway 方法

要为 Transfer Family 创建自定义身份提供程序,您的 API Gateway 方法必须实现一个方法,该方法的资源路径为/servers/serverId/users/username/config. 这些区域有:serverIdusername值来自 RESTful 资源路径。(可选)您可以将sourceIpprotocol值添加到 RESTful 资源路径。

注意

用户名长度最少为 3 个字符,最多为 100 个字符 您可以在用户名中使用以下字符:a—z、A-Z、A-Z、0-9、连字符 (-)、句点 (.) 和 @ (.) 和 @。但是,用户名不能以连字符 (-)、句点 (.) 或 @ (@) 开头。

如果 Transfer Family 尝试对用户进行密码身份验证,则该服务将提供Password:标头字段。在没有Password:标头时,Transfer Family 会尝试公钥身份验证来验证您的用户。

当您使用身份提供商对最终用户进行身份验证和授权时,除了验证他们的凭据外,您还可以根据最终用户使用的客户端的 IP 地址允许或拒绝访问请求。您可以使用此功能来确保存储在 S3 存储桶或 Amazon EFS 文件系统中的数据只能通过受支持的协议从您指定为受信任的 IP 地址访问。若要启用此功能,您必须包含sourceIpRESTful 资源路径中的值。

如果您为服务器启用了多个协议,并希望通过多个协议使用相同的用户名提供访问权限,则只要您的身份提供程序中已设置了每个协议的特定凭据,您就可以这样做。若要启用此功能,您必须包含protocolRESTful 资源路径中的值。

您的 API Gateway 方法应始终返回 HTTP 状态代码200. 任何其他 HTTP 状态代码表示访问 API 时出现的错误。

Amazon S3 示例响应

示例响应正文是 Amazon S3 的以下形式的 JSON 文档。

{ "Role": "IAM role with configured S3 permissions", "PublicKeys": [ "ssh-rsa public-key1", "ssh-rsa public-key2" ], "Policy": "STS Assume role session policy", "HomeDirectory": "/bucketName/path/to/home/directory" }
注意

策略以字符串形式转义 JSON。例如:

"Policy": "{ \"Version\": \"2012-10-17\", \"Statement\": [ {\"Condition\": {\"StringLike\": {\"s3:prefix\": [\"user/*\", \"user/\"]}}, \"Resource\": \"arn:aws:s3:::bucket\", \"Action\": \"s3:ListBucket\", \"Effect\": \"Allow\", \"Sid\": \"ListHomeDir\"}, {\"Resource\": \"arn:aws:s3:::*\", \"Action\": [\"s3:PutObject\", \"s3:GetObject\", \"s3:DeleteObjectVersion\", \"s3:DeleteObject\", \"s3:GetObjectVersion\", \"s3:GetObjectACL\", \"s3:PutObjectACL\"], \"Effect\": \"Allow\", \"Sid\": \"HomeDirObjectAccess\"}] }"

以下示例响应显示用户具有逻辑主目录类型。

{ \"Role\": \"arn:aws:iam::123456789012:role/role-api-gateway-s3\", \"HomeDirectoryType\": \"LOGICAL\", \"HomeDirectoryDetails\": \"[{\\\"Entry\\\":\\\"/\\\",\\\"Target\\\":\\\"/my-home-bucket\\\"}]\", \"PublicKeys\": \"[]\" }

Amazon EFS 示例

示例响应正文是 Amazon EFS 的以下形式的 JSON 文档。

{ "Role": "IAM role with configured EFS permissions", "PublicKeys": [ "ssh-rsa public-key1", "ssh-rsa public-key2" ], "PosixProfile": { "Uid": "POSIX user ID", "Gid": "POSIX group ID", "SecondaryGids": [Optional list of secondary Group IDs], }, "HomeDirectory": "/fs-id/path/to/home/directory" }

这些区域有:Role字段显示发生了成功的身份验证。进行密码身份验证时(当您提供Password:标头),则不需要提供 SSH 公钥。如果用户无法进行身份验证,例如,如果密码不正确,则您的方法应该返回一个没有Role集。这种响应的一个示例是空 JSON 对象。

以下示例响应显示具有逻辑主目录类型的用户。

{ \"Role\": \"arn:aws:iam::123456789012:role/role-api-gateway-efs\", \"HomeDirectoryType\": \"LOGICAL\", \"HomeDirectoryDetails\": \"[{\\\"Entry\\\":\\\"/\\\",\\\"Target\\\":\\\"/fs-faa1a123\\\"}]\", \"PublicKeys\": \"[]\", \"PosixProfile\": \"{Gid: 65534,Uid: 65534}\" }

您可以在 Lambda 函数中以 JSON 格式包含用户策略。有关在 Transfer Family 中配置用户策略的详细信息,请参阅管理访问控制.

用于身份验证的 Lambda 函数示例

要实现不同的身份验证策略,请编辑网关使用的 Lambda 函数。为了帮助您满足应用程序的需求,您可以在 Node.js 中使用以下示例 Lambda 函数。有关 Lambda 的更多信息,请参阅Amazon Lambda开发人员指南或者使用 Node.js 构建 Lambda 函数.

默认 Lambda 函数

以下 Lambda 函数获取您的用户名、密码(在头字段中)、IAM 访问角色、公共 SSH 密钥和协议。您可以使用协议字段查找身份提供程序。支持的协议值包括 SFTP、FTPS 和 FTP。

注意

如果为服务器启用了多个协议,并希望通过多个协议使用相同的用户名提供访问权限,则只要在身份提供程序中设置了协议特定的凭据,您就可以这样做。对于 FTP,我们建议维护与 SFTP 和 FTPS 的单独凭据。这是因为,与 SFTP 和 FTPS 不同,FTP 以明文形式传输凭据。通过将 FTP 凭据与 SFTP 或 FTPS 隔离开来,如果 FTP 凭据是共享或公开的,则使用 SFTP 或 FTPS 的工作负载将保持安全。

Lambda 函数对用户进行身份验证,如果成功,则返回相关的 IAM 访问角色和策略。此 Lambda 函数与示例中使用的函数相同Amazon CloudFormation模板。

这些区域有:HomeDirectoryType参数指定您希望用户在登录服务器时,用户主目录成为的登录目录(文件夹)的类型。如果将该参数设置为PATH,用户将在其文件传输协议客户端中原样看到 Amazon S3 存储桶或 Amazon EFS 的绝对路径。如果将该参数设置为LOGICAL,则必须在HomeDirectoryMappings参数,了解您希望如何使 Amazon S3 或 Amazon EFS 路径对用户可见。

// GetUserConfig Lambda exports.handler = (event, context, callback) => { console.log("Username:", event.username, "ServerId: ", event.serverId); var response; // Check if the user name presented for authentication is correct. This doesn't check the value of the serverId, only that it is provided. // There is also event.protocol (one of "FTP", "FTPS", "SFTP") and event.sourceIp (e.g., "127.0.0.1") to further restrict logins. if (event.serverId !== "" && event.username == '${UserName}') { response = { Role: '${UserRoleArn}', // The user will be authenticated if and only if the Role field is not blank Policy: '', // Optional JSON blob to further restrict this user's permissions HomeDirectory: '${UserHomeDirectory}' // Not required, defaults to '/' }; // Check if password is provided if (event.password == "") { // If no password provided, return the user's SSH public key response['PublicKeys'] = [ "${UserPublicKey1}" ]; // Check if password is correct } else if (event.password !== '${UserPassword}') { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } } else { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } callback(null, response); };

以下 Lambda 函数提供具有逻辑主目录类型的用户的详细信息。用户,角色,Posix,密码和家庭指导详细信息都是示例,需要替换为您的实际值。

// GetUserConfig Lambda exports.handler = (event, context, callback) => { console.log("Username:", event.username, "ServerId: ", event.serverId); var response; // Check if the username presented for authentication is correct. This doesn't check the value of the serverId, only that it is provided. if (event.serverId !== "" && event.username == 'example-user') { response = { Role: 'arn:aws:iam::123456789012:role/role-api-gateway', // The user will be authenticated if and only if the Role field is not blank PosixProfile: {"Gid": 65534, "Uid": 65534}, HomeDirectoryDetails: "[{\"Entry\": \"/\", \"Target\": \"/fs-faa1a123\"}]", HomeDirectoryType: "LOGICAL", //HomeDirectory: '/fs-faa1a123' // Not required, defaults to '/' }; // Check if password is provided if (event.password == "") { // If no password provided, return the user's SSH public key response['PublicKeys'] = [ "" ]; // Check if password is correct } else if (event.password !== 'Password1234') { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } } else { // Return HTTP status 200 but with no role in the response to indicate authentication failure response = {}; } callback(null, response); };

Lambda 函数与Amazon Secrets Manager

使用Amazon Secrets Manager作为您的身份提供者,您可以在示例中使用 Lambda 函数Amazon CloudFormation模板。Lambda 函数使用您的凭据查询 Secrets Manager 服务,如果成功,则返回指定的密码。有关 SSecrets Manager 的更多信息,请参阅Amazon Secrets Manager用户指南.

下载示例Amazon CloudFormation模板中使用此 Lambda 函数,请转到由提供的 Amazon S3 存储桶Amazon Transfer Family.