

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

# 使用 Amazon API Gateway 整合您的身份提供程序
<a name="authentication-api-gateway"></a>

本主题介绍如何使用 AWS Lambda 函数支持 API Gateway 方法。如果您需要一个 RESTful API 来集成您的身份提供商，或者想要利用其功能来处理地理封锁或速率限制请求，请使用 AWS WAF 此选项。

对于大多数用例，配置自定义身份提供商的推荐方法是使用[自定义身份提供商解决方案](custom-idp-toolkit.md)。

**使用 API Gateway 集成身份提供程序时的限制**
+ 此配置不支持自定义域。
+ 此配置不支持私有 API Gateway 网址。

如果您需要其中任何一个，则可以使用 Lambda 作为身份提供程序，而无需使用 API Gateway。有关更多信息，请参阅 [AWS Lambda 用于整合您的身份提供商](custom-lambda-idp.md)。

## 使用 API Gateway 方法进行身份验证
<a name="authentication-custom-ip"></a>

您可以创建一个 API Gateway 方法，用作 Transfer Family 的身份提供程序。这种方法为您提供了一种高度安全的创建和提供方式 APIs。借助 API Gateway，您可以创建 HTTPS 终端节点，以便以更高的安全性传输所有传入的 API 操作。有关 API Gateway 服务的更多详细信息，请参阅 [API Gateway 开发者指南](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html)。

API Gateway 提供了一种名为的授权方法`AWS_IAM`，该方法为您提供与内部 AWS 使用的相同基于 AWS Identity and Access Management (IAM) 的身份验证。如果您通过 `AWS_IAM` 启用身份验证，则只有具有调用 API 的明确权限的调用程序才能访问该 API 的 API Gateway 方法。

要将您的 API Gateway 方法用作 Transfer Family 的自定义身份提供程序，请为您的 API Gateway 方法启用 IAM。在此过程中，您需要为一个 IAM 角色提供 Transfer Family 使用您的网关的权限。

**注意**  
为了提高安全性，可以配置 Web 应用程序防火墙。 AWS WAF 是一种 Web 应用程序防火墙，可让您监视转发到 Amazon API Gateway 的 HTTP 和 HTTPS 请求。有关更多信息，请参阅 [添加 Web 应用程序防火墙](web-application-firewall.md)。

**不要启用 API Gateway 缓存**  
将 API Gateway 方法用作 Transfer Family 的自定义身份提供者时，请勿为其启用缓存。缓存对身份验证请求不恰当且无效，因为：  
每个身份验证请求都是唯一的，需要实时响应，而不是缓存的响应
缓存没有任何好处，因为 Transfer Family 永远不会向 API Gateway 发送重复或重复的请求
启用缓存将导致 API Gateway 使用不匹配的数据进行响应，从而导致对身份验证请求的响应无效

**使用您的 API Gateway 方法对 Transfer Family 进行自定义身份验证**

1. 创建 CloudFormation 堆栈。要实现此目的，应按照以下步骤进行：
**注意**  
堆栈模板已更新为使用 BASE64编码密码：有关详细信息，请参阅。[对 CloudFormation 模板的改进](#base64-templates)

   1. 在 [https://console.aws.amazon.com/cloudformat](https://console.aws.amazon.com/cloudformation/) ion 上打开 CloudFormation 控制台。

   1. 按照*AWS CloudFormation 用户指南*中的[选择 CloudFormation 堆栈模板中的使用现有模板部署堆栈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-using-console-create-stack-template.html)的说明进行操作。

   1. 使用以下基本模板之一创建由 AWS Lambda支持的 API Gateway 方法，以便在 Transfer Family 中用作自定义身份提供程序。
      + [基本堆栈模板](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-basic-apig.template.yml)

        默认情况下，您的 API Gateway 方法用作自定义身份提供者，使用硬编码的 SSH（安全外壳）密钥或密码对单个服务器中的单个用户进行身份验证。部署后，您可以修改 Lambda 函数代码以执行不同的操作。
      + [AWS Secrets Manager 堆栈模板](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-secrets-manager-apig.template.yml)

        默认情况下，您的 API Gateway 方法会根据格式 `aws/transfer/server-id/username` 的 Secrets Manager 中的条目进行身份验证。此外，该密钥必须包含返回给 Transfer Family 的所有用户属性的键值对。部署后，您可以修改 Lambda 函数代码以执行不同的操作。有关更多信息，请参阅博客文章[启用密码身份验证以供 AWS Transfer Family 使用 AWS Secrets Manager](https://aws.amazon.com/blogs/storage/enable-password-authentication-for-aws-transfer-family-using-aws-secrets-manager-updated/)。
      + [Okta 堆栈模板](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-okta-apig.template.yml)

        您的 API Gateway 方法与 Okta 集成，以作为 Transfer Family 中的自定义身份提供程序。有关更多信息，请参阅博客文章：[使用 AWS Transfer Family将 Okta 用作身份提供程序](https://aws.amazon.com/blogs/storage/using-okta-as-an-identity-provider-with-aws-transfer-for-sftp/)。

   部署其中一个堆栈是将自定义身份提供程序集成到 Transfer Family 工作流程的最简单方法。每个堆栈都使用 Lambda 函数来支持基于 API Gateway 的 API 方法。然后，您可以在 Transfer Family 中使用您的 API 方法作为自定义身份提供程序。默认情况下，Lambda 函数对使用 `MySuperSecretPassword` 密码 `myuser` 调用的单个用户进行身份验证。部署后，您可以编辑这些凭证或更新 Lambda 函数代码以执行不同的操作。
**重要**  
我们建议您编辑默认的用户和密码凭证。

   部署堆栈后，您可以在 CloudFormation 控制台的**输出**选项卡上查看有关堆栈的详细信息。这些详细信息包括堆栈的 Amazon 资源名称 (ARN)、堆栈创建的 IAM 角色的 ARN 以及您的新网关的 URL。
**注意**  
如果您使用自定义身份提供商选项为用户启用基于密码的身份验证，并且启用了 API Gateway 提供的请求和响应日志，API Gateway 会将用户的密码记录到您的 Amazon 日志中。 CloudWatch 我们建议不要在生产环境中使用此日志。有关更多信息，请参阅《[ CloudWatch API Gateway *开发者指南》中的 “在 API Gateway 中设置 API* 日志](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html)”。

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

   1. 打开 API Gateway 控制台，网址为[https://console.aws.amazon.com/apigateway/](https://console.aws.amazon.com/apigateway/)。

   1. 选择模板生成的**转移自定义身份提供商基本 CloudFormation 模板 API**。您可能需要选择您的区域才能看到您的网关。

   1. 在 “**资源**” 窗格中，选择 **GET**。以下屏幕截图显示了正确的方法配置。  
![\[API 配置详细信息，显示请求路径的方法配置参数和 URL 查询字符串的 。\]](http://docs.aws.amazon.com/zh_cn/transfer/latest/userguide/images/apig-config-method-fields.png)

   此时，您的 API Gateway 已准备好部署。

1. 在**操作**，选择**部署 API**。对于**部署阶段**，选择 **prod**，然后选择**部署**。

   成功部署 API Gateway 方法后，在 “阶段” > “**阶段****详情**” 中查看其性能，如以下屏幕截图所示。
**注意**  
复制显示在屏幕顶部的**调用 URL** 地址。下一步可能需要它。  
![\[暂存细节，突出显示调用网址。\]](http://docs.aws.amazon.com/zh_cn/transfer/latest/userguide/images/apig-config-method-invoke.png)

1. 打开 AWS Transfer Family 控制台，网址为[https://console.aws.amazon.com/transfer/](https://console.aws.amazon.com/transfer/)。

1. 在你创建堆栈时，应该已经为你创建了 Transfer Family。如果不是，请使用以下步骤配置您的服务器。

   1. 选择“**创建服务器**”以打开“**创建服务器**”页面。在**“选择身份提供程序**”中，选择“**自定义**”，然后选择“**使用 Amazon API Gateway 连接到您的身份提供程序**”，如以下屏幕截图所示。  
![\[身份提供者屏幕，选择自定义身份提供商，并选择 API Gateway 来连接到您的身份提供商。\]](http://docs.aws.amazon.com/zh_cn/transfer/latest/userguide/images/create-server-choose-idp-custom.png)

   1. 在**提供 Amazon API Gateway 网址**文本框中，粘贴您在本过程的步骤 3 中创建的 API Gateway 端点的**调用 URL** 地址。

   1. 对于**角色**，选择由 CloudFormation 模板创建的 IAM 角色。此角色允许 Transfer Family 调用您的 API Gateway 方法。

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

   1. 填写其余的方框，然后选择“**创建服务器**”。有关创建服务器的其余步骤的详细信息，请参阅 [配置 SFTP、FTPS 或 FTP 服务器端点](tf-server-endpoint.md)。

## 实施您的 API Gateway 方法
<a name="authentication-api-method"></a>

要为 Transfer Family 创建自定义身份提供程序，您的 API Gateway 方法必须实现资源路径为 `/servers/serverId/users/username/config` 的单个方法。`serverId`和`username`值来自 RESTful 资源路径。此外，在**方法请求**中添加 `sourceIp` 和 `protocol` 作为 **URL 查询字符串参数**，如下图所示。

![\[API Gateway 的资源屏幕显示了GET方法的详细信息。\]](http://docs.aws.amazon.com/zh_cn/transfer/latest/userguide/images/apig-config-method-request.png)


**注意**  
此用户名长度最少为 3 个字符，最多为 100 个字符。你可以在用户名中使用以下字符：a—z、A-Z、0—9、下划线 '\$1'、连字符 '-'、句点 '.' 和 at 符号 '@'。用户名不能以连字符 “-”、“句点” 或 “@” 开头。

如果 Transfer Family 代表您的用户尝试进行密码身份验证，则该服务会提供 `Password:` 标头字段。在没有 `Password:` 标头的情况下，Transfer Family 会尝试通过公钥身份验证来验证您的用户。

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

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

您的 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": "/amzn-s3-demo-bucket/path/to/home/directory"
}
```

**注意**  
 策略会以 JSON 格式转义为字符串。例如：  

****  

```
"Policy":
"{
  \"Version\": \"2012-10-17\",
  \"Statement\":
     [
     {\"Condition\":
        {\"StringLike\":
            {\"s3:prefix\":
               [\"user/*\", \"user/\"]}},
     \"Resource\": \"arn:aws:s3:::amzn-s3-demo-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/transfer-access-role-s3",
   "HomeDirectoryType":"LOGICAL",
   "HomeDirectoryDetails":"[{\"Entry\":\"/\",\"Target\":\"/amzn-s3-demo-bucket1\"}]",
   "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/transfer-access-role-efs",
    "HomeDirectoryType": "LOGICAL",
    "HomeDirectoryDetails":"[{\"Entry\":\"/\",\"Target\":\"/faa1a123\"}]",
    "PublicKeys":[""],
    "PosixProfile":{"Uid":65534,"Gid":65534}
}
```

您可以在 JSON 格式的 Lambda 函数中包含用户策略。有关在 Transfer Family 中配置用户策略的更多信息，请参阅 [管理访问控制](users-policies.md)。

## 默认 Lambda 函数
<a name="authentication-lambda-examples-default"></a>

要实施不同的身份验证策略，请编辑您的网关使用的 Lambda 函数。为了帮助您满足应用程序的需求，您可以在 Node.js 中使用以下示例 Lambda 函数。有关更多信息，请参见 [AWS Lambda 开发人员指南](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) 或 [ 通过 Node.js 构建 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html)。

以下示例 Lambda 函数使用您的用户名、密码（如果您正在执行密码身份验证）、服务器 ID、协议和客户端 IP 地址。您可以使用这些输入的组合来查找您的身份提供程序并确定是否应接受登录。

**注意**  
如果您为服务器启用了多个协议，并且想要通过多个协议使用相同的用户名提供访问权限，则只要在身份提供程序中设置了相关协议的特定凭据，就可以这样做。  
对于文件传输协议 (FTP)，我们建议为 Secure Shell (SSH) 文件传输协议 (SFTP) 和 SSL (FTPS) 文件传输协议设置不同的凭证。我们建议为 FTP 保留单独的凭据，因为与 SFTP 和 FTPS 不同，FTP 以明文形式传输凭据。通过将 FTP 凭证与 SFTP 或 FTPS 隔离开来，如果共享或公开 FTP 凭证，则使用 SFTP 或 FTPS 的工作负载会保持安全。

此示例函数会返回角色和逻辑主目录详细信息以及公钥（如果它执行公钥身份验证）。

创建服务托管用户时，可以设置他们的主目录，无论是逻辑目录还是物理目录均是如此。同样，我们需要 Lambda 函数的结果来传达所需的用户物理或逻辑目录结构。您设置的参数取决于该 [https://docs.aws.amazon.com//transfer/latest/APIReference/API_CreateUser.html#TransferFamily-CreateUser-request-HomeDirectoryType](https://docs.aws.amazon.com//transfer/latest/APIReference/API_CreateUser.html#TransferFamily-CreateUser-request-HomeDirectoryType) 字段的值。
+ `HomeDirectoryType` 设置为 `PATH` — 然后，`HomeDirectory` 字段必须是您的用户可见的 Amazon S3 存储桶绝对前缀或 Amazon EFS 绝对路径。
+ `HomeDirectoryType` 设置为 `LOGICAL` — 请*不要*设置 `HomeDirectory` 字段。相反，我们设置了一个提供所需 Entry/Target 映射的`HomeDirectoryDetails`字段，类似于服务管理用户的[https://docs.aws.amazon.com//transfer/latest/APIReference/API_CreateUser.html#TransferFamily-CreateUser-request-HomeDirectoryMappings](https://docs.aws.amazon.com//transfer/latest/APIReference/API_CreateUser.html#TransferFamily-CreateUser-request-HomeDirectoryMappings)参数中描述的值。

[Lambda 函数示例](custom-lambda-idp.md#lambda-auth-examples) 中列出了示例函数。

## 与一起使用的 Lambda 函数 AWS Secrets Manager
<a name="authentication-lambda-examples-secrets-mgr"></a>

要 AWS Secrets Manager 用作您的身份提供商，您可以使用示例 CloudFormation 模板中的 Lambda 函数。Lambda 函数使用您的凭证查询 Secrets Manager 服务，如果成功，则会返回指定的密钥。有关 Secrets Manager 的更多信息，请参阅《AWS Secrets Manager 用户指南》[https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)。

要下载使用此 Lambda 函数的示例 CloudFormation 模板，请访问[提供的 Amazon S3 存储桶](https://s3.amazonaws.com/aws-transfer-resources/custom-idp-templates/aws-transfer-custom-idp-secrets-manager-apig.template.yml)。 AWS Transfer Family

## 对 CloudFormation 模板的改进
<a name="base64-templates"></a>

已发布的 CloudFormation模板已对 API Gateway 界面进行了改进。现在，这些模板在 API BASE64 Gateway 中使用经过编码的密码。如果没有此增强功能，您的现有部署将继续运行，但不允许使用基本 US-ASCII 字符集之外的字符的密码。

启用此功能的模板更改如下：
+ `GetUserConfigRequest AWS::ApiGateway::Method`资源必须有这个`RequestTemplates`代码（斜体行是更新的行）

  ```
  RequestTemplates:
     application/json: |
     {
        "username": "$util.urlDecode($input.params('username'))",
        "password": "$util.escapeJavaScript($util.base64Decode($input.params('PasswordBase64'))).replaceAll("\\'","'")",
        "protocol": "$input.params('protocol')",
        "serverId": "$input.params('serverId')",
        "sourceIp": "$input.params('sourceIp')"
  }
  ```
+ `GetUserConfig`资源必须更改`RequestParameters`为使用`PasswordBase64`标题（斜体行是更新的行）：

  ```
  RequestParameters:
     method.request.header.PasswordBase64: false
     method.request.querystring.protocol: false
     method.request.querystring.sourceIp: false
  ```

**检查堆栈的模板是否是最新的**

1. 在 [https://console.aws.amazon.com/cloudformat](https://console.aws.amazon.com/cloudformation/) ion 上打开 CloudFormation 控制台。

1. 从堆栈列表中选择您的堆栈。

1. 在详细信息面板中，选择**模板**选项卡。

1. 寻找以下内容：
   + 搜索`RequestTemplates`并确保你有以下行：

     ```
     "password": "$util.escapeJavaScript($util.base64Decode($input.params('PasswordBase64'))).replaceAll("\\'","'")",
     ```
   + 搜索`RequestParameters`并确保你有以下行：

     ```
     method.request.header.PasswordBase64: false
     ```

如果您没有看到更新的行，请编辑您的堆栈。有关如何更新 CloudFormation 堆栈的详细信息，请参阅《*用户指南》*中的[AWS CloudFormation修改堆栈模板](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-get-template.html)。