

# 使用 MFA 保护 API 访问
<a name="id_credentials_mfa_configure-api-require"></a>

利用 IAM policy，可以指定用户可调用哪些 API 操作。您可以通过要求用户使用多重身份验证（MFA）进行身份验证，然后才允许他们执行特别敏感的操作，从而应用额外的安全性。

例如，您可能拥有允许用户执行 Amazon EC2 `RunInstances`、`DescribeInstances` 和 `StopInstances` 操作的策略。但您可能希望限制破坏性操作（如 `TerminateInstances`），并确保用户只能在使用 AWS MFA 设备进行身份验证后执行该操作。

**Topics**
+ [概述](#MFAProtectedAPI-overview)
+ [方案：跨账户委派的 MFA 保护](#MFAProtectedAPI-cross-account-delegation)
+ [方案：当前账户中 API 操作访问的 MFA 保护](#MFAProtectedAPI-user-mfa)
+ [方案：拥有基于资源的策略的资源的 MFA 保护](#MFAProtectedAPI-resource-policies)

## 概述
<a name="MFAProtectedAPI-overview"></a>

向 API 操作添加 MFA 保护包括以下任务：

1. 管理员为每个用户配置 AWS MFA 设备，这些用户必须发出要求 MFA 身份验证的 API 请求。有关更多信息，请参阅 [IAM 中的 AWS 多重身份验证](id_credentials_mfa.md)。

1. 管理员为用户创建包含 `Condition` 元素的策略，以检查用户是否已使用 AWS MFA 设备进行身份验证。

1. 用户会调用支持 MFA 参数的 AWS STS API 操作之一：[AssumeRole](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) 或 [GetSessionToken](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html)。调用中包含与用户关联的设备的设备标识符，以及该设备生成的基于时间的一次性密码 (TOTP)。在任一情况下，用户都会取回稍后用来向 AWS 发出其他请求的临时安全凭证。
**注意**  
仅在服务支持临时安全凭证时，该服务的 API 操作的 MFA 保护才可用。有关这些服务的列表，请参阅[使用临时安全凭证访问 AWS](https://docs.aws.amazon.com/STS/latest/UsingSTS/UsingTokens.html)。

如果授权失败，AWS 将返回“访问被拒绝”错误消息（与任何未授权的访问一样）。由于采用受 MFA 保护的 API 策略，因此，如果用户在未获得有效的 MFA 身份验证的情况下试图调用 API 操作，则 AWS 将拒绝用户访问策略中指定的 API 操作。如果 API 操作请求的时间戳在策略中指定的允许范围之外，也会拒绝操作。用户必须使用 MFA 代码和设备序列号请求新的临时安全凭证，通过 MFA 重新进行身份验证。

### 带 MFA 条件的 IAM policy
<a name="MFAProtectedAPI-policies"></a>

带 MFA 条件的策略可附加到以下项：
+ 对于 IAM 用户或组：
+ Amazon S3 存储桶、Amazon SQS 队列或 Amazon SNS 主题等资源
+ 可由用户担任的 IAM 角色的信任策略

可使用策略中的 MFA 条件检查以下属性：
+ Existence（存在性）- 如果只是验证用户是否已使用 MFA 进行身份验证，请检查 `aws:MultiFactorAuthPresent` 密钥在 `Bool` 条件中是否为 `True`。仅当用户使用短期凭证验证时，才会有该键。长期凭证，例如访问密钥，不包括此键。
+ Duration (持续时间) - 如果您只希望在 MFA 身份验证后的指定时间内授予访问权限，请使用数值条件类型将 `aws:MultiFactorAuthAge` 密钥的有效期与某个值（如 3600 秒）进行比较。请注意，如果未使用 MFA，则 `aws:MultiFactorAuthAge` 键不会显示。

以下示例说明了 IAM 角色的信任策略，该策略包含一个 MFA 条件，用于测试是否存在 MFA 身份验证。利用此策略，`Principal` 元素中指定的 AWS 账户 中的用户（将 `ACCOUNT-B-ID` 替换为有效的 AWS 账户 ID）能够代入此策略附加的角色。但是，此类用户仅在已使用 MFA 进行身份验证的情况下才能够担任角色。

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": {
    "Effect": "Allow",
    "Principal": {"AWS": "ACCOUNT-B-ID"},
    "Action": "sts:AssumeRole",
    "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
  }
}
```

------

有关 MFA 的条件类型的更多信息，请参阅[AWS 全局条件上下文密钥](reference_policies_condition-keys.md)、[数字条件运算符](reference_policies_elements_condition_operators.md#Conditions_Numeric)和[用于检查条件键是否存在的条件运算符](reference_policies_elements_condition_operators.md#Conditions_Null)。

### 在 GetSessionToken 和 AssumeRole 之间选择
<a name="scenarios"></a>

AWS STS 提供了两个 API 操作，可供用户传递 MFA 信息：`GetSessionToken` 和 `AssumeRole`。用户调用哪个 API 操作来获取临时安全凭证，取决于采用以下哪个方案。

**将 `GetSessionToken` 用于以下方案：**
+ 调用访问 AWS 账户 中的资源的 API 操作，该账户与发出请求的 IAM 用户相同。请注意，来自 `GetSessionToken` 请求的临时凭证*仅*在您将 MFA 信息包含在凭证请求中时才能访问 IAM 和 AWS STS API 操作。由于 `GetSessionToken` 返回的临时凭证包含 MFA 信息，因此您可以检查由该凭证发出的单个 API 操作中的 MFA。
+ 访问受基于资源且包含 MFA 条件的策略所保护的资源。

`GetSessionToken` 操作旨在使用 MFA 验证用户身份。您不能使用策略来控制身份验证操作。

**将 `AssumeRole` 用于以下方案：**
+ 调用访问相同或不同 AWS 账户 中的资源的 API 操作。API 调用可包含任何 IAM 或 AWS STS API。请注意，要保护访问，您可以在用户担任角色时强制执行 MFA。由 `AssumeRole` 返回的临时凭证未将 MFA 信息包含在上下文中，因此您无法检查单个 API 操作的 MFA。这就是您必须使用 `GetSessionToken` 限制对受基于资源的策略保护的资源的访问的原因。

**注意**  
IAM 用户使用 MFA 登录时，AWS CloudTrail 日志将包含 MFA 信息。如果 IAM 用户代入某个 IAM 角色，CloudTrail 还将在利用代入角色执行操作的 `sessionContext` 属性中记录 `mfaAuthenticated: true`。但是，当使用代入角色的凭证进行 API 调用时，CloudTrail 日志记录与 IAM 要求的内容是分开的。有关更多信息，请参阅 [CloudTrail userIdentity 元素](https://docs.aws.amazon.com//awscloudtrail/latest/userguide/cloudtrail-event-reference-user-identity.html)。

本文档稍后将提供有关如何实现这些方案的详细信息。

### 有关受 MFA 保护的 API 访问的要点
<a name="MFAProtectedAPI-important-points"></a>

了解 API 操作的 MFA 保护的以下几个方面非常重要：
+ MFA 保护仅通过使用临时安全凭证提供，而该凭证必须使用 `AssumeRole` 或 `GetSessionToken` 获取。
+ 无法将受 MFA 保护的 API 访问与 AWS 账户根用户凭证配合使用。
+ 无法将受 MFA 保护的 API 访问与 U2F 安全密钥配合使用。
+ 将 MFA 设备与 AWS 服务配合使用时，无法向联合身份用户分配这些设备；因此，这些用户无法访问受 MFA 控制的 AWS 资源。(请参阅下一个要点。) 
+ 返回临时凭证的其他 AWS STS API 操作不支持 MFA。对于 `AssumeRoleWithWebIdentity` 和 `AssumeRoleWithSAML`，用户通过外部提供程序进行身份验证，并且 AWS 无法确定该提供程序是否需要 MFA。对于 `GetFederationToken`，MFA 不一定要与特定用户相关联。
+ 同样，长期凭证（IAM 用户访问密钥和根用户访问密钥)）无法用于受 MFA 保护的 API 访问，因为它们不会过期。
+ 此外，可以在没有 MFA 信息的情况下调用 `AssumeRole` 和 `GetSessionToken`。在此情况下，发起人将取回临时安全凭证，但这些临时凭证的会话信息不指示使用 MFA 进行身份验证的用户。
+ 要建立 API 操作的 MFA 保护，可将 MFA 条件添加到策略。策略必须包含 `aws:MultiFactorAuthPresent` 条件键以强制使用 MFA。对于跨账户委派，角色的信任策略必须包含条件键。
+ 如果您允许其他 AWS 账户 访问您账户中的资源，则您的资源安全性取决于受信任账户（另一个账户，而不是您的账户）的配置。即使在您强制实施多重身份验证时，也是如此。有权创建虚拟 MFA 设备的受信任账户中的任何标识都可以构建 MFA 索赔，以满足您角色的信任策略的该部分。在允许其他账户的成员访问必须进行多重身份验证的 AWS 资源之前，您应确保受信任账户的所有者遵循安全最佳实践。例如，受信任账户应仅允许特定的受信任身份访问敏感 API 操作，例如 MFA 设备管理 API 操作。
+ 如果策略包含 MFA 条件，则在以下情况下，将拒绝请求：用户未进行 MFA 身份验证或用户提供了无效的 MFA 设备标识符或无效的 TOTP。

## 方案：跨账户委派的 MFA 保护
<a name="MFAProtectedAPI-cross-account-delegation"></a>

在此方案中，您希望将访问权委托给另一账户中的 IAM 用户，但前提是该用户已使用 AWS MFA 设备进行身份验证。有关跨账户委派的更多信息，请参阅 [角色术语和概念](id_roles.md#id_roles_terms-and-concepts)。

假设您有一个账户 A（拥有待访问资源的信任账户）以及 IAM 用户 Anaya，她拥有管理员权限。她希望向账户 B（受信任账户）中的用户 Richard 授予访问权，但希望确保 Richard 在担任该角色之前已使用 MFA 进行身份验证。

1. 在信任账户 A 中，Anaya 创建一个名为 `CrossAccountRole` 的 IAM 角色，并将该角色的信任策略中的主体设置为账户 B 的账户 ID。此信任策略授予对 AWS STS `AssumeRole` 操作的权限。Anaya 还向信任策略添加 MFA 条件，如以下示例中所示。

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": {
       "Effect": "Allow",
       "Principal": {"AWS": "ACCOUNT-B-ID"},
       "Action": "sts:AssumeRole",
       "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
     }
   }
   ```

------

1. Anaya 在该角色中添加一个权限策略，以指定允许该角色执行的操作。具有 MFA 保护的角色权限策略与任何其他角色权限策略没有差别。以下示例说明了 Anaya 添加到角色的策略；该策略允许担任该角色的用户对账户 A 中的表 `Books` 执行任何 Amazon DynamoDB 操作。此策略还允许 `dynamodb:ListTables` 操作，此操作是在控制台中执行操作所必需的。
**注意**  
该权限策略不包含 MFA 条件。了解 MFA 身份验证仅用于确定用户是否可以担任此角色很重要。在用户担任此角色后，将不会进行进一步的 MFA 检查。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "TableActions",
               "Effect": "Allow",
               "Action": "dynamodb:*",
               "Resource": "arn:aws:dynamodb:*:111122223333:table/Books"
           },
           {
               "Sid": "ListTables",
               "Effect": "Allow",
               "Action": "dynamodb:ListTables",
               "Resource": "*"
           }
       ]
   }
   ```

------

1. 在受信任账户 B 中，管理员确保已使用 AWS MFA 设备配置 IAM 用户 Richard，并且该用户知道设备的 ID。设备 ID 是序列号（如果是硬件 MFA 设备）或设备的 ARN（如果是虚拟 MFA 设备）。

1. 在账户 B 中，管理员将以下策略附加到用户 Richard（或该用户所在的组），该策略允许该用户调用 `AssumeRole` 操作。资源被设置到 Anaya 在第 1 步中创建的角色的 ARN。注意，该策略不包含 MFA 条件。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "sts:AssumeRole"
               ],
               "Resource": [
                   "arn:aws:iam::111122223333:role/CrossAccountRole"
               ]
           }
       ]
   }
   ```

------

1. 在账户 B 中，Richard（或 Richard 正在运行的应用程序）调用 `AssumeRole`。API 调用包含要担任角色的 ARN (`arn:aws:iam::ACCOUNT-A-ID:role/CrossAccountRole`)、MFA 设备的 ID 和 Richard 从其设备中获取的当前 TOTP。

   当 Richard 调用 `AssumeRole` 时，AWS 将确定他是否拥有有效的凭证，包括 MFA 要求。如果是这样的话，Richard 将成功担任角色，并且可在使用角色的临时凭证时对账户 A 中名为 `Books` 的表执行任何 DynamoDB 操作。

   有关调用 `AssumeRole` 的程序的示例，请参阅[使用 MFA 身份验证调用 AssumeRole](id_credentials_mfa_sample-code.md#MFAProtectedAPI-example-assumerole)。

## 方案：当前账户中 API 操作访问的 MFA 保护
<a name="MFAProtectedAPI-user-mfa"></a>

在此方案中，您应确保仅当您 AWS 账户 中的用户已使用 AWS MFA 设备进行身份验证后才能访问敏感 API 操作。

假设您拥有账户 A，其中包含一组需要使用 EC2 实例的开发人员。普通开发人员可以使用实例，但他们未获得 `ec2:StopInstances` 或 `ec2:TerminateInstances` 操作的权限。您希望仅允许几个受信任用户执行这些“破坏性”特权操作，因此您将 MFA 保护添加到允许这些敏感 Amazon EC2 操作的策略中。

在此方案中，用户 Sofía 是受信任用户之一。用户 Anaya 是账户 A 中的管理员。

1. Anaya 确保已使用 AWS MFA 设备配置 Sofía，并且 Sofía 知道该设备的 ID。设备 ID 是序列号（如果是硬件 MFA 设备）或设备的 ARN（如果是虚拟 MFA 设备）。

1. Anaya 创建一个名为 `EC2-Admins` 的组并将用户 Sofía 添加到该组中。

1. Anaya 将以下策略附加到 `EC2-Admins` 组。此策略授予用户调用 Amazon EC2 `StopInstances` 和 `TerminateInstances` 操作的权限，但前提是该用户已使用 MFA 进行身份验证。

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Action": [
         "ec2:StopInstances",
         "ec2:TerminateInstances"
       ],
       "Resource": ["*"],
       "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
     }]
   }
   ```

------

1. 
**注意**  
要使此策略生效，用户必须先注销，然后重新登录。

   如果用户 Sofía 需要停止或终止 Amazon EC2 实例，则她（或她正在运行的应用程序）可调用 `GetSessionToken`。此 API 操作传递 MFA 设备的 ID 和 Sofía 从其设备获取的当前 TOTP。

1. 用户 Sofía（或 Sofía 正在使用的应用程序）使用由 `GetSessionToken` 提供的临时凭证来调用 Amazon EC2 `StopInstances` 或 `TerminateInstances` 操作。

   有关调用 `GetSessionToken` 的程序的示例，请参阅本文档后面的 [使用 MFA 身份验证调用 GetSessionToken](id_credentials_mfa_sample-code.md#MFAProtectedAPI-example-getsessiontoken)。

## 方案：拥有基于资源的策略的资源的 MFA 保护
<a name="MFAProtectedAPI-resource-policies"></a>

在此方案中，您是 S3 存储桶、SQS 队列或 SNS 主题的所有者。您希望确保访问资源的任何 AWS 账户 中的任何用户都已使用 AWS MFA 设备进行身份验证。

此方案介绍了一种提供跨账户 MFA 保护的方法，无需用户先担任角色。在此情况下，用户可在满足以下三个条件时访问资源：用户已使用 MFA 进行身份验证、能够从 `GetSessionToken` 获取临时安全凭证且在受资源策略信任的账户中。

假设您在账户 A 中并创建一个 S3 存储桶。您希望向几个不同 AWS 账户 中的用户授予对此存储桶的访问权，但前提是这些用户已使用 MFA 进行身份验证。

在此方案中，用户 Anaya 是账户 A 中的管理员。用户 Nikhil 是账户 C 中的 IAM 用户。

1. 在账户 A 中，Anaya 创建一个名为 `Account-A-bucket` 的存储桶。

1. Anaya 向该存储桶添加存储桶策略。该策略允许账户 A、账户 B 或账户 C 中的所有用户执行存储桶中的 Amazon S3 `PutObject` 和 `DeleteObject` 操作。该策略包含 MFA 条件。

------
#### [ JSON ]

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Principal": {"AWS": [
         "ACCOUNT-A-ID",
         "ACCOUNT-B-ID",
         "ACCOUNT-C-ID"
       ]},
       "Action": [
         "s3:PutObject",
         "s3:DeleteObject"
       ],
       "Resource": ["arn:aws:s3:::ACCOUNT-A-BUCKET-NAME/*"],
       "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
     }]
   }
   ```

------
**注意**  
Amazon S3（仅）针对*根*账户访问提供“MFA 删除”功能。在您设置存储桶的版本化状态时，可启用 Amazon S3 MFA Delete 功能。Amazon S3 MFA Delete 功能不适用于 IAM 用户，在管理时独立于 MFA 保护的 API 访问。即使 IAM 用户具有删除存储桶的权限，但在启用 Amazon S3 MFA Delete 功能时，也无法执行删除。有关 Amazon S3 MFA Delete 功能的更多信息，请参阅 [MFA Delete](https://docs.aws.amazon.com/AmazonS3/latest/dev/MultiFactorAuthenticationDelete.html)。

1. 在账户 C 中，管理员确保已使用 AWS MFA 设备配置用户 Nikhil，并且该用户知道设备的 ID。设备 ID 是序列号（如果是硬件 MFA 设备）或设备的 ARN（如果是虚拟 MFA 设备）。

1. 在账户 C 中，Nikhil（或他正在运行的应用程序）将调用 `GetSessionToken`。此调用包括 MFA 设备的 ID 或 ARN 以及 Nikhil 从其设备中获取的当前 TOTP。

1. Nikhil（或他正在使用的应用程序）使用 `GetSessionToken` 返回的临时凭证调用 Amazon S3 `PutObject` 操作以将文件上传到 `Account-A-bucket`。

   有关调用 `GetSessionToken` 的程序的示例，请参阅本文档后面的 [使用 MFA 身份验证调用 GetSessionToken](id_credentials_mfa_sample-code.md#MFAProtectedAPI-example-getsessiontoken)。
**注意**  
在此情况下，`AssumeRole` 返回的临时凭证将不可用。尽管用户可以提供 MFA 信息来担任角色，但 `AssumeRole` 返回的临时凭证不包含 MFA 信息。需要此信息才能满足策略中的 MFA 条件。