

# IAM 教程
<a name="tutorials"></a>

以下教程提供了 AWS Identity and Access Management (IAM) 的常见任务的完整端到端过程。这些过程适用于实验室类型环境，使用了虚构的公司名称、用户名称等。其目的在于提供一般性指导。在未进行仔细审核并进行改进以满足组织环境的独特需求的情况下，这些过程不适合在您的生产环境中直接使用。

**Topics**
+ [使用角色委派跨 AWS 账户 的访问权限](tutorial_cross-account-with-roles.md)
+ [创建客户托管策略](tutorial_managed-policies.md)
+ [使用基于属性的访问控制 (ABAC)](tutorial_attribute-based-access-control.md)
+ [使 用户能够管理其凭证和 MFA 设置](tutorial_users-self-manage-mfa-and-creds.md)
+ [使用 CloudFormation 创建 SAML IdP](tutorial_saml-idp.md)
+ [使用 CloudFormation 创建 SAML 联合角色](tutorial_saml-federated-role.md)
+ [使用 CloudFormation 创建 SAML IdP 和联合角色](tutorial_saml-idp-and-federated-role.md)

# IAM 教程：使用 IAM 角色委托跨 AWS 账户的访问权限
<a name="tutorial_cross-account-with-roles"></a>

**重要**  
 IAM [最佳实践](best-practices.md)建议您您要求人类用户使用与身份提供商的联合身份验证才能使用临时凭证访问 AWS，而不是使用具有长期凭证的 IAM 用户。建议您仅在联合用户不支持的[特定用例](gs-identities-iam-users.md)中使用 IAM 用户。

本教程将指导您如何使用角色来委派对您拥有的不同 AWS 账户（称为**目标**和**原始**）中资源的访问权限。您将与另一账户中的用户共享一个账户中的资源。通过以这种方式设置跨账户存取，您不需要在每个账户中创建单个 IAM 用户。此外，用户不必从一个账户注销并登录另一个账户，即可访问不同 AWS 账户 中的资源。配置角色后，您将了解如何从 AWS 管理控制台、AWS CLI 和 API 中使用角色。

在本教程中，**目标**账户管理不同应用程序和团队访问的应用程序数据。在每个账户中，您将应用程序信息存储在 Amazon S3 存储桶中。您可以在**原始**账户中管理 IAM 用户，其中有两个 IAM 用户角色：**开发人员**和**分析师**。开发人员和分析师使用**原始**账户生成由多个微服务共享的数据。两个角色都拥有在原始账户中工作的权限，可访问该账户中的资源。开发人员必须不时更新**目标**账户中的共享数据。开发人员将此数据存储在名为 `amzn-s3-demo-bucket-shared-container` 的 Amazon S3 存储桶中。

在本教程结束时，您将拥有以下内容：
+ **原始**账户（受信任账户）中能够担任**目标**账户中特定角色的用户。
+ **目标**账户（可信账户）中能够访问特定 Amazon S3 存储桶的角色。
+ **目标**账户中的 `amzn-s3-demo-bucket-shared-container` 存储桶。

开发人员可以在 AWS 管理控制台 中使用该角色访问**目标**账户中的 `amzn-s3-demo-bucket-shared-container` 存储桶。他们还可以使用通过该角色提供的临时凭证进行了身份验证的 API 调用来访问该存储桶。分析师同样尝试使用该角色，但会失败。

此工作流程具有三个基本步骤：

**[在目标账户中创建角色](#tutorial_cross-account-with-roles-1)**  
首先，您使用 AWS 管理控制台 在**目标**账户（ID 号 999999999999）和**原始**账户（ID 号 111111111111）之间建立信任。可通过创建名为 *UpdateData* 的 IAM 角色 角色开始。当您创建角色时，将**原始**账户定义为受信任实体，并指定一个权限策略，允许受信任用户更新 `amzn-s3-demo-bucket-shared-container` 存储桶。

**[向角色授予访问权限](#tutorial_cross-account-with-roles-2)**  
在本节中，您将修改角色策略，以拒绝分析师访问 `UpdateData` 角色。这种情况下，因为分析师有 PowerUser 访问权限，您必须显式*拒绝*使用该角色的能力。

**[通过切换角色测试访问权限](#tutorial_cross-account-with-roles-3)**  
最后，以开发人员的身份使用 `UpdateData` 角色更新**目标**账户中的 `amzn-s3-demo-bucket-shared-container` 存储桶。您可以了解如何通过 AWS 控制台、AWS CLI 和 API 访问角色。

## 注意事项
<a name="tutorial_cross-account-with-roles-considerations"></a>

在使用 IAM 角色跨 AWS 账户 委派资源访问权限之前，务必考虑以下几点：
+ 以 AWS 账户根用户 身份登录后无法切换至角色。
+ IAM 角色和基于资源的策略仅在单个分区内跨账户委派访问权限。例如，假定您在标准 `aws` 分区的美国西部（加利福尼亚北部）中有一个账户。您在 `aws-cn` 分区的中国（北京）中也有一个账户。您不能使用中国（北京）的账户中 Amazon S3 基于资源的策略，来允许标准 `aws` 账户中用户的访问权限。
+ 您可以使用 AWS IAM Identity Center 通过安全断言标记语言（SAML）为外部 AWS 账户（AWS Organizations 之外的账户）单点登录（SSO）提供便利。有关详细信息，请参阅 [Integrate external AWS 账户 into AWS IAM Identity Center for central access management with independent billing using SAML 2.0](https://community.aws/content/2dIMI8N7w7tGxbE0KQMrkSBfae4/aws-iam-identity-center-integration-with-external-aws-accounts-for-independent-billing?lang=en) 
+ 您可以将角色与 Amazon EC2 实例或 AWS Lambda 函数等 AWS 资源关联。有关更多信息，请参阅 [创建向 AWS 服务委派权限的角色](id_roles_create_for-service.md)。
+ 如果您想让一个应用程序担任另一个 AWS 账户 中的角色，则可以使用 AWS SDK 跨账户担任角色。有关更多信息，请参阅《AWS SDKs and Tools Reference Guide》**中的 [Authentication and access](https://docs.aws.amazon.com//sdkref/latest/guide/access.html)。
+ 使用 AWS 管理控制台 切换角色仅适用于不需要 `ExternalId` 的账户。例如，假定您将您账户的访问权限授予第三方，并在权限策略的 `Condition` 元素中要求 `ExternalId`。在此情况下，第三方只能通过使用 AWS API 或命令行工具访问您的账户。第三方不能使用控制台，因为它必须提供 `ExternalId` 值。有关此方案的更多信息，请参阅 AWS 安全博客中的 [访问第三方拥有的 AWS 账户](id_roles_common-scenarios_third-party.md) 和 [How to enable cross account access to the AWS 管理控制台](https://aws.amazon.com/blogs/security/how-to-enable-cross-account-access-to-the-aws-management-console)。

## 先决条件
<a name="tutorial_cross-account-with-roles-prereqs"></a>

本教程假定您已准备好以下各项：
+ 您可以使用的**两个**独立 AWS 账户，一个代表**原始**账户，一个代表**目标**账户。
+ **原始**账户中的用户和角色的创建和配置方式如下：  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html)
+ 您不需要在**目标**账户中创建任何用户。
+ 在**目标**账户中创建的 Amazon S3 存储桶。在本教程中，您可以将其称为 `amzn-s3-demo-bucket-shared-container`，但由于 S3 存储桶名称必须全局唯一，您必须使用具有其他名称的存储桶。

## 在目标账户中创建角色
<a name="tutorial_cross-account-with-roles-1"></a>

您可以允许一个 AWS 账户 中的用户访问其他 AWS 账户 中的资源。在本教程中，我们将通过创建一个角色来实现这一点，该角色定义可以访问它的人员以及它向切换到它的用户授予的权限。

在教程的这一步中，您将在**目标**账户中创建角色，并将**原始**账户指定为受信任实体。此外，限制更改角色的权限，只有 `amzn-s3-demo-bucket-shared-container` 存储桶的读写权限。任何人只要获得使用该角色的权限，就能对 `shared-container` 存储桶进行读写。

在创建角色之前，您需要**原始** AWS 账户 的*账户 ID*。每个 AWS 账户 均拥有向其分配的唯一账户 ID 标识符。

**获取原始 AWS 账户 ID**

1. 以**原始**账户管理员身份登录 AWS 管理控制台 并在 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 上打开 IAM 控制台。

1. 在 IAM 控制台中，在右上角的导航栏上选择您的用户名。它通常类似于：***username*@*account\$1ID\$1number\$1or\$1alias***。

   对于此场景，您可以将账户 ID 111111111111 用于**原始**账户。但是，如果您在测试环境中使用此方案，则应使用有效的账户 ID。

**在目标账户中创建可供原始账户使用的角色**

1. 以**目标**账户管理员身份登录 AWS 管理控制台 并打开 IAM 控制台。

1. 创建角色之前，准备好定义角色所需权限的托管策略。您可在以后的步骤中将此策略附加到角色。

   您想要设置针对 `amzn-s3-demo-bucket-shared-container` 存储桶的读写权限。尽管 AWS 提供了一些 Amazon S3 托管策略，但这些策略并未提供对单个 Amazon S3 存储桶的读写访问权限。您可以创建自己的自定义策略。

   在导航窗格中选择**策略**，然后选择**创建策略**。

1. 选择 **JSON** 选项卡，然后复制以下 JSON 策略文档中的文本。将该文本粘贴到 **JSON** 文本框中，并将资源 ARN (`arn:aws:s3:::shared-container`) 替换为与您的 Amazon S3 存储桶对应的真实资源 ARN。

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

****  

   ```
   {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Action": "s3:ListAllMyBuckets",
         "Resource": "*"
       },
       {
         "Effect": "Allow",
         "Action": [
           "s3:ListBucket",
           "s3:GetBucketLocation"
          ],
         "Resource": "arn:aws:s3:::amzn-s3-demo-bucket-shared-container"
       },
       {
         "Effect": "Allow",
         "Action": [
           "s3:GetObject",
           "s3:PutObject",
           "s3:DeleteObject"
         ],
         "Resource": "arn:aws:s3:::amzn-s3-demo-bucket-shared-container/*"
       }
     ]
   }
   ```

------

   `ListAllMyBuckets` 操作会授予列出已通过身份验证的请求发出者所拥有的全部存储桶的权限。`ListBucket` 权限允许用户浏览 `amzn-s3-demo-bucket-shared-container` 存储桶中的对象。`GetObject`、`PutObject`、`DeleteObject` 权限允许用户查看、更新和删除 `amzn-s3-demo-bucket-shared-container` 存储桶中的内容。
**注意**  
您可以随时在**可视化**和 **JSON** 编辑器选项卡之间切换。不过，如果您进行更改或在**可视化**编辑器中选择**下一步**，IAM 可能会调整您的策略结构以针对可视化编辑器进行优化。有关更多信息，请参阅 [调整策略结构](troubleshoot_policies.md#troubleshoot_viseditor-restructure)。

1. 在**查看并创建**页面上，键入 **read-write-app-bucket** 作为策略名称。查看您的策略授予的权限，然后选择**创建策略**以保存您的工作。

   新策略会显示在托管策略列表中。

1. 在导航窗格中，选择**角色**，然后选择**创建角色**。

1. 选择 **AWS 账户** 角色类型。

1. 对于**账户 ID**，键入**原始**账户 ID。

   本教程使用**原始**账户的示例账户 ID **111111111111**。您应使用有效的账户 ID。如果使用无效的账户 ID，如 **111111111111**，IAM 不会让您创建新角色。

   现在，您不必要求外部 ID 或要求用户拥有多重身份验证 (MFA) 就可以担任该角色。将这些选项保持未选中状态。有关更多信息，请参阅 [IAM 中的 AWS 多重身份验证](id_credentials_mfa.md)。

1. 选择 **Next: Permissions** 设置将与角色关联的权限。

1. 选中您之前创建的策略旁边的复选框。
**提示**  
对于 **Filter**，选择 **Customer managed** 对列表进行筛选，使其只包含您创建的策略。这会隐藏 AWS 创建的策略，更容易找到您所需要的策略。

   然后选择**下一步**。

1. （可选）以键值对形式附加标签来向角色添加元数据。有关在 IAM 中使用标签的更多信息，请参阅 [AWS Identity and Access Management 资源的标签](id_tags.md)。

1. （可选）对于 **Description**（描述），输入新角色的描述。

1. 检查角色后，选择 **Create role**。

    

   `UpdateData` 角色显示在角色列表中。

现在，您必须获取该角色的 Amazon Resource Name (ARN)，这是角色的唯一标识。当您修改原始账户中的开发人员角色时，可指定目标账户中的角色 ARN 以授予或拒绝权限。

**获取 UpdateData 的 ARN**

1. 在 IAM 控制台的导航窗格中，选择**角色**。

1. 在角色列表中，选择 `UpdateData` 角色。

1. 在详细信息窗格的 **Summary (摘要)** 部分中，复制 **Role ARN (角色 ARN)** 值。

   目标账户的账户 ID 是 999999999999，因此角色 ARN 是 `arn:aws:iam::999999999999:role/UpdateData`。确保为目标账户提供真实的 AWS 账户 ID。

此时，您已经在**目标**账户和**原始**账户之间建立了信任。您通过在**目标**账户中创建一个角色来将**原始**账户标识为受信的主体，从而实现这一点。您还可以定义切换到 `UpdateData` 角色的用户可执行哪些操作。

接下来，修改开发人员角色的权限。

## 向角色授予访问权限
<a name="tutorial_cross-account-with-roles-2"></a>

此时，分析师和开发人员都拥有允许其管理**原始**账户中数据的权限。使用以下必要步骤添加权限以允许切换到角色。

**修改开发人员角色以允许其切换到 UpdateData 角色**

1. 以**原始**账户中的管理员身份登录，打开 IAM 控制台。

1. 选择**组**，然后选择**开发人员**。

1. 请选择 **Permissions**（权限）选项卡，然后选择 **Add permissions**（添加权限），接着选择 **Create inline policy**（创建内联策略）。

1. 选择 **JSON** 选项卡。

1. 添加以下策略语句，允许对目标账户中的 `UpdateData` 角色执行 `AssumeRole` 操作。请确保将 `Resource` 元素中的 *DESTINATION-ACCOUNT-ID* 更改为目标账户的实际 AWS 账户 ID。

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

****  

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

------

   `Allow` 效果显式允许开发人员组访问目标账户中的 `UpdateData` 角色。尝试访问该角色的任何开发人员都会成功。

1. 选择**查看策略**。

1. 键入**名称**，例如 **allow-assume-S3-role-in-destination**。

1. 选择**创建策略**。

在大多数环境中，可能不需要执行以下步骤。但是，如果您使用 PowerUserAccess，则某些组可能已能够切换角色。以下过程介绍如何向分析师组添加 `"Deny"` 权限，以确保其无法担任角色。如果您的环境中不需要此过程，建议不要添加该权限。`"Deny"` 权限会让整个权限体系更为复杂、难以管理和理解。仅当您没有更好的选择时才使用 `"Deny"` 权限。

**修改分析师角色以拒绝担任 `UpdateData` 角色的权限**

1. 选择**角色**，然后选择**分析师**。

1. 请选择 **Permissions**（权限）选项卡，然后选择 **Add permissions**（添加权限），接着选择 **Create inline policy**（创建内联策略）。

1. 选择 **JSON** 选项卡。

1. 添加以下策略语句以拒绝对 `AssumeRole` 角色执行的 `UpdateData` 操作。请确保将 `Resource` 元素中的 *DESTINATION-ACCOUNT-ID* 更改为目标账户的实际 AWS 账户 ID。

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

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": {
           "Effect": "Deny",
           "Action": "sts:AssumeRole",
           "Resource": "arn:aws:iam::111122223333:role/UpdateData"
       }
   }
   ```

------

   `Deny` 效果显式拒绝分析师组访问目标账户中的 `UpdateData` 角色。任何尝试访问该角色的分析师都会收到一条拒绝访问信息。

1. 选择**查看策略**。

1. 键入**名称**，例如 **deny-assume-S3-role-in-destination**。

1. 选择**创建策略**。

开发人员角色现在有使用目标账户中 `UpdateData` 角色的应权限。禁止分析师角色使用 `UpdateData` 角色。

接下来，您将了解开发人员 David 如何能访问目标账户中的 `amzn-s3-demo-bucket-shared-container` 存储桶。David 可以从 AWS 管理控制台、AWS CLI 或 AWS API 访问存储桶。

## 通过切换角色测试访问权限
<a name="tutorial_cross-account-with-roles-3"></a>

完成本教程的前两个步骤后，您将具有一个可以授予对**目标**账户中资源的访问权限的角色。您还将在**原始**账户中有一个角色，并且用户可以使用该角色。此步骤讨论如何对从 AWS 管理控制台、AWS CLI 和 AWS API 切换到该角色进行测试。

要获取有关在使用 IAM 角色时可能遇到的常见问题的帮助，请参阅[排查 IAM 角色问题](troubleshoot_roles.md)。

### 切换角色（控制台）
<a name="switch-tutorial_cross-account-with-roles"></a>

如果 David 需要在 AWS 管理控制台 中更新**目标**账户中的数据，则他可以使用**切换角色**来进行更新。他指定账户 ID 或别名以及角色名称，他的权限会立即切换为该角色允许的权限。然后，他可以通过控制台使用 `amzn-s3-demo-bucket-shared-container` 存储桶，但是无法使用**目标**中的其他任何资源。当 David 使用该角色时，他无法使用其在**原始**账户中的高级用户权限。这是因为，一次仅一组权限能够生效。

David 可以使用 IAM 提供的两种方法进入 **Switch Role**（切换角色）页：
+ David 收到其管理员提供的一个链接，该链接指向一个预定义的“Switch Role”（切换角色）配置。该链接在 **Create role** 向导最后一页上或在跨账户角色的 **Role Summary** 页面上提供给管理员。选择该链接将引导 David 进入已填写 **Account ID**（账户 ID）和 **Role name**（角色姓名）字段的 **Switch Role**（切换角色）页面。David 只需选择 **Switch Role**（切换角色）。
+ 管理员不会通过电子邮件发送该链接，而是发送**账户 ID** 号和**角色名称**值。要切换角色，David 必须手动输入这些值。以下步骤对此进行说明。

**要代入角色**

1. David 使用其常规用户以**原始**账户登录到 AWS 管理控制台。

1. 他们选择管理员通过电子邮件向其发送的链接。该会将 David 跳转至 **Switch Role**（切换角色）页面，其中已填写了账户 ID 或别名和角色名称信息。

   —或者—

   David 在导航栏上选择其姓名 [Identity（身份）菜单]，然后选择 **Switch Roles**（切换角色）。

   如果这是 David 首次通过这种方式尝试访问“Switch Role (切换角色)”页面，则他会首先登录初始 **Switch Role (切换角色)** 页面。此页面提供有关切换角色如何使用户可以跨 AWS 账户 管理资源的其他信息。David 必须选择此页面上的 **Switch Role**（切换角色）才能完成此过程的其余步骤。

1. 接下来，为了访问该角色，David 必须手动键入目标账户 ID 号（`999999999999`）和角色名称（`UpdateData`）。

   此外，David 还想监控当前 IAM 中处于活动状态的角色及相关权限。为了跟踪此信息，他在 **Display Name（显示名称）**文本框中键入 `Destination`，并选择红色选项，然后选择 **Switch Role（切换角色）**。

1. David 现在可以通过 Amazon S3 控制台使用 Amazon S3 存储桶，或使用 `UpdateData` 角色有权限的其他任何资源。

1. 完成后，David 可返回其原始权限。为此，他们可以选择导航栏上的**目标**角色显示名称，然后选择**返回 David @ 111111111111**。

1. 当 David 下次要切换角色并在导航栏中选择**身份**菜单时，他将看到目标条目仍在上次的位置。他可以选择该条目立即切换角色，无需重新输入账户 ID 和角色名称。

### 切换角色 (AWS CLI)
<a name="switch-cli-tutorial_cross-account-with-roles"></a>

 如果 David 需要在**目标**环境中的命令行上工作，他可以使用 [AWS CLI](https://aws.amazon.com/cli/) 做到这一点。他运行 `aws sts assume-role` 命令并传递角色 ARN 以获取该角色的临时安全凭证。然后，他在环境变量中配置这些凭证，使后续的 AWS CLI 命令能够使用该角色的权限执行。当 David 使用该角色时，他不能同时使用他在**原始**账户中的高级用户权限，因为同一时间只有一组权限有效。

请注意，所有访问密钥和令牌都只是示例，不能原样照用。请用您的实际环境的适当值替换。

**要代入角色**

1. David 打开命令提示符窗口，运行以下命令确认 AWS CLI 客户端正在工作：

   ```
   aws help
   ```
**注意**  
David 的默认环境使用他通过 `David` 命令创建的默认配置文件中的 `aws configure` 用户凭证。有关更多信息，请参阅《AWS Command Line Interface 用户指南》**中的[配置 AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-quick-configuration)。

1. 他通过运行以下命令开始角色切换过程，以切换到**目标**账户中的 `UpdateData` 角色。他从创建该角色的管理员处获得了角色 ARN。该命令还需要您提供一个会话名称，您可以选择任何文本作为该名称。

   ```
   aws sts assume-role --role-arn "arn:aws:iam::999999999999:role/UpdateData" --role-session-name "David-ProdUpdate"
   ```

   然后 David 在输出中看到以下内容：

   ```
   {
       "Credentials": {
           "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
           "SessionToken": "AQoDYXdzEGcaEXAMPLE2gsYULo+Im5ZEXAMPLEeYjs1M2FUIgIJx9tQqNMBEXAMPLE
   CvSRyh0FW7jEXAMPLEW+vE/7s1HRpXviG7b+qYf4nD00EXAMPLEmj4wxS04L/uZEXAMPLECihzFB5lTYLto9dyBgSDy
   EXAMPLE9/g7QRUhZp4bqbEXAMPLENwGPyOj59pFA4lNKCIkVgkREXAMPLEjlzxQ7y52gekeVEXAMPLEDiB9ST3Uuysg
   sKdEXAMPLE1TVastU1A0SKFEXAMPLEiywCC/Cs8EXAMPLEpZgOs+6hz4AP4KEXAMPLERbASP+4eZScEXAMPLEsnf87e
   NhyDHq6ikBQ==",
           "Expiration": "2014-12-11T23:08:07Z",
           "AccessKeyId": "AKIAIOSFODNN7EXAMPLE"
       }
   }
   ```

1. David 在输出的“Credentials”（凭证）部分中看到了他们所需要的三个部分。
   + `AccessKeyId`
   + `SecretAccessKey`
   + `SessionToken`

   David 需要配置 AWS CLI 环境，以在后续的调用中使用这些参数。有关各种凭证配置方法的信息，请参阅[配置 AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#config-settings-and-precedence)。您不能使用 `aws configure` 命令，因为它不支持捕获会话令牌。但是，您可手动将信息输入到配置文件中。由于这些是到期时间相对较短的临时凭证，将它们添加到您当前的命令行会话环境中是最简单的。

1. 为了将三个值添加到环境，David 将上一步的输出剪切并粘贴到以下命令中。您可能希望剪切并粘贴到简单文本编辑器中，以解决会话令牌输出中的换行问题。即使此处为清晰起见，将输出显示为换行格式，在添加时也必须是单个长字符串形式。

   以下示例显示了 Windows 环境中的命令，其中“set”是创建环境变量的命令。在 Linux 或 MacOS 计算机上，您将改用“export”命令。该示例的其余部分对于三种环境均有效。

   有关使用适用于 Windows Powershell 的工具的详细信息，请参阅 [切换到 IAM 角色（Tools for Windows PowerShell）](id_roles_use_switch-role-twp.md)

   ```
   set AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
   set AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
   set AWS_SESSION_TOKEN=AQoDYXdzEGcaEXAMPLE2gsYULo+Im5ZEXAMPLEeYjs1M2FUIgIJx9tQqNMBEXAMPLECvS
   Ryh0FW7jEXAMPLEW+vE/7s1HRpXviG7b+qYf4nD00EXAMPLEmj4wxS04L/uZEXAMPLECihzFB5lTYLto9dyBgSDyEXA
   MPLEKEY9/g7QRUhZp4bqbEXAMPLENwGPyOj59pFA4lNKCIkVgkREXAMPLEjlzxQ7y52gekeVEXAMPLEDiB9ST3UusKd
   EXAMPLE1TVastU1A0SKFEXAMPLEiywCC/Cs8EXAMPLEpZgOs+6hz4AP4KEXAMPLERbASP+4eZScEXAMPLENhykxiHen
   DHq6ikBQ==
   ```

   此时，以下所有命令都在这些凭证确定的角色的权限下运行。对 David 而言就是 `UpdateData` 角色。
**重要**  
您可以将常用的配置设置和凭证保存在由 AWS CLI 维护的文件中。有关更多信息，请参阅《AWS Command Line Interface User Guide》**中的 [Using existing configuration and credentials files](https://docs.aws.amazon.com//cli/latest/userguide/getting-started-quickstart.html#getting-started-quickstart-existing)。

1. 运行该命令访问目标账户中的资源。在此示例中，David 使用以下命令列出其 S3 存储桶的内容。

   ```
   aws s3 ls s3://shared-container
   ```

   因为 Amazon S3 存储桶名称通常是唯一的，所以无需指定拥有存储桶的账户 ID。要访问其他 AWS 服务的资源，请参阅该服务的 AWS CLI 文档，了解引用其资源所需使用的命令和语法。

### 使用 AssumeRole (AWS API)
<a name="api-tutorial_cross-account-with-roles"></a>

当 David 需要通过代码来更新**目标**账户时，他执行 `AssumeRole` 调用来担任 `UpdateData` 角色。该调用返回临时凭证，他可以使用这些凭证访问**目标**账户中的 `amzn-s3-demo-bucket-shared-container` 存储桶。使用这些凭证，David 可以调用 API 以更新 `amzn-s3-demo-bucket-shared-container` 存储桶。但是，即使他在**原始**账户中拥有高级用户权限，也无法通过调用 API 来访问**目标**账户中的任何其他资源。

**要代入角色**

1. David 把 `AssumeRole` 视为应用程序的一个段调用。他们必须指定 `UpdateData` ARN：`arn:aws:iam::999999999999:role/UpdateData`。

   `AssumeRole` 调用返回的结果包含临时凭证以及 `AccessKeyId` 和 `SecretAccessKey`。它还包括一个 `Expiration` 时间，该时间指示凭证何时到期（届时您必须请求新的凭证）。当您使用 AWS SDK 设置角色链时，许多凭证提供者会在凭证过期之前自动刷新凭证。

1. David 使用那些临时证书调用 `s3:PutObject` 升级 `amzn-s3-demo-bucket-shared-container` 存储段。他们会将凭证作为 `AuthParams` 参数传递给 API 调用。由于临时角色凭证只有 `amzn-s3-demo-bucket-shared-container` 存储桶的读写权限，因此对目标账户的任何其他操作都会被拒绝。

有关代码示例 (使用 Python)，请参阅[切换到 IAM 角色（AWS API）](id_roles_use_switch-role-api.md)。

## 其他资源
<a name="tutorial_cross-account-with-roles-related"></a>

以下资源可帮助您了解有关本教程中主题的更多信息：
+ 有关 IAM 用户的更多信息，请参阅 [IAM 身份](id.md)。
+ 有关 Amazon S3 存储桶的更多信息，请参阅 *Amazon Simple Storage Service 用户指南*中的[创建存储桶](https://docs.aws.amazon.com/AmazonS3/latest/userguide/CreatingABucket.html)。
+  要了解您信任区域之外的账户（受信任的企业或账户）中的主体是否有权承担您的角色，请参阅[什么是 IAM Access Analyzer？](https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html)。

## 摘要
<a name="tutorial_cross-account-with-roles-summary"></a>

您已经完成跨账户 API 访问教程。您创建了一个角色与另一个账户之间建立信任关系，并规定了受信任实体可以执行哪些操作。然后，您修改了角色策略以控制哪些 IAM 用户可以访问该角色。最终，**原始**账户的开发人员可以使用临时凭证升级**目标**账户中的 `amzn-s3-demo-bucket-shared-container` 存储桶。

# IAM 教程：创建和附加您的第一个客户托管策略
<a name="tutorial_managed-policies"></a>

在本教程中，您将使用 AWS 管理控制台 创建一个[客户管理型策略](access_policies_managed-vs-inline.md#customer-managed-policies)，然后将该策略附加到您 AWS 账户 中的一个 IAM 用户。您创建的策略允许具有只读权限的 IAM 测试用户直接登录 AWS 管理控制台。

此工作流程具有三个基本步骤：

**[步骤 1：创建策略](#step1-create-policy)**  
默认情况下，IAM 用户没有权限来执行任何操作。未经过您的允许，他们无法访问 AWS 管理控制台，也无法管理其中的数据。在该步骤中，您创建一个允许任何附加的用户登录到该控制台的客户托管策略。

**[步骤 2：附加策略](#step2-attach-policy)**  
将策略附加到用户时，该用户继承与该策略相关的所有访问权限。在此步骤中，您会将新策略附加到测试用户。

**[步骤 3：测试用户访问权限](#step3-test-access)**  
附加策略后，您即可以该用户身份登录并测试策略。

## 先决条件
<a name="tutorial-managed-policies-prereqs"></a>

要执行本教程中的步骤，您必须已具备以下内容：
+ 可作为 IAM 用户身份登录且具有管理权限的 AWS 账户。
+ 未分配有如下权限或组成员资格的测试 IAM 用户：  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_managed-policies.html)

## 步骤 1：创建策略
<a name="step1-create-policy"></a>

在该步骤中，您创建一个允许任何附加用户（具有 IAM 数据的只读访问权限）登录 AWS 管理控制台 的客户托管策略。

**为测试用户创建策略**

1. 使用您具有管理员权限的账户，通过以下网址登录到 IAM 控制台：[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)。

1. 在导航窗格中，选择**策略**。

1. 在内容窗格中，选择**创建策略**。

1. 选择 **JSON** 选项，然后复制以下 JSON 策略文档中的文本。将该文本粘贴到 **JSON** 文本框中。

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

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [ {
           "Effect": "Allow",
           "Action": [
               "iam:GenerateCredentialReport",
               "iam:Get*",
               "iam:List*"
           ],
           "Resource": "*"
       } ]
   }
   ```

------

1.  解决[策略验证](access_policies_policy-validator.md)过程中生成的任何安全警告、错误或常规警告，然后选择**下一步**。
**注意**  
您可以随时在**可视化**和 **JSON** 编辑器选项卡之间切换。不过，如果您进行更改或在**可视化编辑器**选项卡中选择 **Review policy（查看策略）**，IAM 可能会调整您的策略结构以针对可视化编辑器进行优化。有关更多信息，请参阅 [调整策略结构](troubleshoot_policies.md#troubleshoot_viseditor-restructure)。

1. 在**查看并创建**页面上，键入 **UsersReadOnlyAccessToIAMConsole** 作为策略名称。查看您的策略授予的权限，然后选择**创建策略**以保存您的工作。

   将在托管策略列表中显示新策略，并已准备好附加该策略。

## 步骤 2：附加策略
<a name="step2-attach-policy"></a>

接下来，您会将刚刚创建的策略附加到测试 IAM 用户。

**将策略挂载到测试用户**

1. 在 IAM 控制台的导航窗格中，选择 **Policies**（策略）。

1. 在策略列表顶部的搜索框中，开始键入 **UsersReadOnlyAccesstoIAMConsole** 直至您的策略出现。然后，选中列表中 **UsersReadOnlyAccessToIAMConsole** 旁边的单选按钮。

1. 请选择 **Actions**（操作）按钮，然后选择 **Attach**（附加）。

1. 在 IAM 实体中，选择选项以筛选**用户**。

1. 在搜索框中，开始键入 **PolicyUser** 直至该用户在列表上可见。然后，选中列表中该用户旁边的框。

1. 选择**附加策略**。

您已将策略挂载到 IAM 测试用户，这意味着现在该用户具有 IAM 控制台的只读访问权限。

## 步骤 3：测试用户访问权限
<a name="step3-test-access"></a>

对于本教程，我们建议您以各测试用户身份登录来测试访问权限，以便能了解用户可能获得的体验。

**使用测试用户登录以测试访问权限**

1. 使用您的 `PolicyUser` 测试用户通过以下网址登录到 IAM 控制台：[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)。

1. 浏览控制台的各个页面并尝试创建新的用户或组。请注意，`PolicyUser` 可以显示数据，但无法创建或修改现有 IAM 数据。

## 相关资源
<a name="tutorial-managed-policies-addl-resources"></a>

有关信息，请参阅以下资源：
+ [托管策略与内联策略](access_policies_managed-vs-inline.md)
+ [控制 IAM 用户对 AWS 管理控制台 的访问](console_controlling-access.md)

## 摘要
<a name="tutorial-managed-policies-summary"></a>

现在，您已成功完成创建和附加客户托管策略所需的所有步骤。因此，您可以使用测试账户登录 IAM 控制台，以了解用户可能获得的体验。

# IAM 教程：根据标签定义访问 AWS 资源的权限
<a name="tutorial_attribute-based-access-control"></a>

基于属性的访问权限控制 (ABAC) 是一种授权策略，该策略基于属性来定义权限。在 AWS 中，这些属性被称为“标签”**。您可以将标签附加到 IAM 资源（包括 IAM 实体（用户和角色））以及 AWS 资源。您可以定义策略，这些策略使用标签条件键来根据主体的标签向其授予权限。当您使用标签控制对 AWS 资源的访问时，可通过对 AWS 策略进行较少更改来实现团队和资源的增长。ABAC 策略比传统 AWS 策略更加灵活，后者需要您列出每个单独的资源。有关 ABAC 及其相对于传统策略的优势的更多信息，请参阅[使用 ABAC 授权根据属性定义权限](introduction_attribute-based-access-control.md)。

**注意**  
您必须为每个会话标签传递一个值。AWS Security Token Service 不支持多值会话标签。

**Topics**
+ [

## 教程概述
](#tutorial_attribute-based-access-control-overview)
+ [

## 先决条件
](#tutorial_abac_prereqs)
+ [

## 步骤 1：创建测试用户
](#tutorial_abac_step1)
+ [

## 步骤 2：创建 ABAC 策略
](#tutorial_abac_step2)
+ [

## 步骤 3：创建角色
](#tutorial_abac_step3)
+ [

## 步骤 4：测试创建密钥
](#tutorial_abac_step4)
+ [

## 步骤 5：测试查看密钥
](#tutorial_abac_step5)
+ [

## 步骤 6：测试可扩展性
](#tutorial_abac_step6)
+ [

## 步骤 7：测试更新和删除密钥
](#tutorial_abac_step7)
+ [

## 摘要
](#tutorial-abac-summary)
+ [

## 相关资源
](#tutorial_abac_related)
+ [

# IAM 教程：将 SAML 会话标签用于 ABAC
](tutorial_abac-saml.md)

## 教程概述
<a name="tutorial_attribute-based-access-control-overview"></a>

本教程说明如何创建一个允许具有主体标签的 IAM 角色 角色访问具有匹配标签的资源的策略并测试该策略。当主体向 AWS 发出请求时，将根据主体标签和资源标签是否匹配来授予其权限。此策略仅允许用户查看或编辑其作业需要的 AWS 资源。

**场景**  
假设您是一家名为 Example Corporation 的大公司的开发人员主管，同时也是一名经验丰富的 IAM 管理员。您熟悉 IAM 用户、角色和策略的创建和管理。您希望确保您的开发工程师和质量保证团队成员能够访问其所需的资源。您还需要一个随公司发展而扩展的策略。

您选择使用 AWS 资源标签和 IAM 角色主体标签来为支持 ABAC 策略的服务实施该策略（从 AWS Secrets Manager 开始）。要了解哪些服务支持基于标签的授权，请参阅[使用 IAM 的 AWS 服务](reference_aws-services-that-work-with-iam.md)。要了解可以在策略中使用哪些标记条件键以及每个服务的操作和资源，请参阅 [AWS 服务的操作、资源和条件键](reference_policies_actions-resources-contextkeys.html)。您可以对基于 SAML 的身份提供程序或 Web 身份提供程序进行配置，将[会话标签](id_session-tags.md)传递给 AWS。当您的员工希望联合身份到 AWS 中时，其属性将应用到 AWS 中所得到的主体。然后，您可以使用 ABAC 来允许或拒绝基于这些属性的权限。要了解 SAML 联合身份中的会话标签与本教程的不同之处，请参阅[IAM 教程：将 SAML 会话标签用于 ABAC](tutorial_abac-saml.md)。

您的工程和质量保证团队成员是 **Pegasus** 或 **Unicorn** 项目。您可以选择以下 3 个字符的项目和团队标签值：
+ `access-project` = `peg`（对于 **Pegasus** 项目）
+ `access-project` = `uni`（对于 **Unicorn** 项目）
+ `access-team` = `eng`（对于工程团队）
+ `access-team` = `qas`（对于质量保证团队）

此外，您选择需要 `cost-center` 成本分配标签以启用自定义 AWS 账单报告。有关更多信息，请参阅《AWS 账单与成本管理 用户指南》**中的[使用成本分配标签](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html)。

**重要决策摘要**
+ 员工使用 IAM 用户凭证进行登录，然后代入其团队和项目的 IAM 角色 角色。如果您的公司拥有与自己的身份系统，则您可以设置联合身份验证以允许员工在没有 IAM 用户的情况下代入角色。有关更多信息，请参阅 [IAM 教程：将 SAML 会话标签用于 ABAC](tutorial_abac-saml.md)。
+ 将向所有角色附加同一策略。根据标签允许或拒绝操作。
+ 员工可以创建新的资源，但前提是员工必须将相同的标签附加到应用于其角色的资源。这将确保员工能够在创建资源后进行查看。管理员不再需要使用新资源的 ARN 来更新策略。
+ 员工可以读取其团队拥有的资源，无论项目如何。
+ 员工可以更新和删除其团队和项目拥有的资源。
+ IAM 管理员可以为新项目添加新角色。他们可以创建和标记新的 IAM 用户以允许访问相应的角色。管理员不需要编辑策略来支持新项目或团队成员。

在本教程中，您将标记每个资源，标记项目角色，并将策略添加到角色以允许前面所述的行为。生成的策略允许角色对使用同一项目和团队标签标记的资源进行 `Create`、`Read`、`Update` 和 `Delete` 访问。此策略还允许对使用同一团队标记的资源进行跨项目 `Read` 访问。

![\[此图显示了两个项目，在这两个项目中，角色只能对其项目外的资源进行只读访问，而在其自己的项目中则拥有创建、读取、更新和删除资源的权限。\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/images/tutorial-abac-cross-project.png)


## 先决条件
<a name="tutorial_abac_prereqs"></a>

要执行本教程中的步骤，您必须已具备以下内容：
+ 可使用用户身份登录的具有管理权限的 AWS 账户。
+ 您的 12 位账户 ID（用于在步骤 3 中创建角色）。

  要使用 AWS 管理控制台查找 AWS 账户 ID 号，请在右上角的导航栏上选择 **Support (支持)**，然后选择 **Support Center (支持中心)**。账户号 (ID) 将显示在左侧的导航窗格中。  
![\[显示账号的 支持 Center 页面。\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/images/account-id-support-center.console.png)
+ 体验在 AWS 管理控制台 中创建和编辑 IAM 用户、角色和策略。但是，如果您需要获得帮助以便记住 IAM 管理过程，请访问本教程提供的链接来查看分步说明。

## 步骤 1：创建测试用户
<a name="tutorial_abac_step1"></a>

为了进行测试，请创建四个有权代入具有相同标签的角色的 IAM 用户。这可让您更轻松地向您的团队添加更多用户。在标记用户时，他们会自动获得访问权来代入正确角色。如果用户仅在一个项目和团队中工作，则无需将其添加到角色的信任策略中。

1. 创建以下名为 `access-assume-role` 的客户托管策略。有关创建 JSON 策略的更多信息，请参阅[创建 IAM 策略](access_policies_create-console.md#access_policies_create-start)。

**ABAC 策略：代入任何 ABAC 角色，但前提是用户和角色标签匹配**  
以下策略允许用户在您的账户中代入任何带有 `access-` 名称前缀的角色。还必须使用与用户相同的项目、团队和成本中心来标记角色。

   要使用此策略，请将示例策略中的*斜体占位符文本*替换为您的账户信息。

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

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "TutorialAssumeRole",
               "Effect": "Allow",
               "Action": "sts:AssumeRole",
               "Resource": "arn:aws:iam::111122223333:role/access-*",
               "Condition": {
                   "StringEquals": {
                       "iam:ResourceTag/access-project": "${aws:PrincipalTag/access-project}",
                       "iam:ResourceTag/access-team": "${aws:PrincipalTag/access-team}",
                       "iam:ResourceTag/cost-center": "${aws:PrincipalTag/cost-center}"
                   }
               }
           }
       ]
   }
   ```

------

   要将本教程扩展到大量用户，您可以将策略附加到一个组并将每个用户添加到该组。有关更多信息，请参阅[创建 IAM 组](id_groups_create.md)和[编辑 IAM 组中的用户](id_groups_manage_add-remove-users.md)。

1. 创建以下 IAM 用户，附加 `access-assume-role` 权限策略。确保选择**向用户提供对 AWS 管理控制台 的访问权限**，然后添加以下标签。

       
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

## 步骤 2：创建 ABAC 策略
<a name="tutorial_abac_step2"></a>

创建以下名为 **access-same-project-team** 的策略。您将在以后的步骤中将此策略添加到角色。有关创建 JSON 策略的更多信息，请参阅[创建 IAM 策略](access_policies_create-console.md#access_policies_create-start)。

有关可针对本教程调整的其他策略，请参阅以下页面：
+ [控制 IAM 主体进行的访问](access_iam-tags.md#access_iam-tags_control-principals)
+ [Amazon EC2：允许以编程方式和在控制台中启动或停止用户已标记的 EC2 实例](reference_policies_examples_ec2_tag-owner.md)
+ [EC2：基于匹配的主体和资源标签来启动或停止实例](reference_policies_examples_ec2-start-stop-match-tags.md)
+ [EC2：基于标签来启动或停止实例](reference_policies_examples_ec2-start-stop-tags.md)
+ [IAM：代入具有特定标签的角色](reference_policies_examples_iam-assume-tagged-role.md)

**ABAC 策略：仅在主体标签和资源标签匹配时访问 Secrets Manager 资源**  
以下策略允许主体创建、读取、编辑和删除资源，但前提是已使用与主体相同的键/值对标记这些资源。当主体创建资源时，必须添加 `access-project`、`access-team` 和 `cost-center` 标签以及与主体的标签匹配的值。该策略还允许添加可选的 `Name` 或 `OwnedBy` 标签。

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

****  

```
{
 "Version":"2012-10-17",		 	 	 
 "Statement": [
     {
         "Sid": "AllActionsSecretsManagerSameProjectSameTeam",
         "Effect": "Allow",
         "Action": "secretsmanager:*",
         "Resource": "*",
         "Condition": {
             "StringEquals": {
                 "aws:ResourceTag/access-project": "${aws:PrincipalTag/access-project}",
                 "aws:ResourceTag/access-team": "${aws:PrincipalTag/access-team}",
                 "aws:ResourceTag/cost-center": "${aws:PrincipalTag/cost-center}"
             },
             "ForAllValues:StringEquals": {
                 "aws:TagKeys": [
                     "access-project",
                     "access-team",
                     "cost-center",
                     "Name",
                     "OwnedBy"
                 ]
             },
             "StringEqualsIfExists": {
                 "aws:RequestTag/access-project": "${aws:PrincipalTag/access-project}",
                 "aws:RequestTag/access-team": "${aws:PrincipalTag/access-team}",
                 "aws:RequestTag/cost-center": "${aws:PrincipalTag/cost-center}"
             }
         }
     },
     {
         "Sid": "AllResourcesSecretsManagerNoTags",
         "Effect": "Allow",
         "Action": [
             "secretsmanager:GetRandomPassword",
             "secretsmanager:ListSecrets"
         ],
         "Resource": "*"
     },
     {
         "Sid": "ReadSecretsManagerSameTeam",
         "Effect": "Allow",
         "Action": [
             "secretsmanager:Describe*",
             "secretsmanager:Get*",
             "secretsmanager:List*"
         ],
         "Resource": "*",
         "Condition": {
             "StringEquals": {
                 "aws:ResourceTag/access-team": "${aws:PrincipalTag/access-team}"
             }
         }
     },
     {
         "Sid": "DenyUntagSecretsManagerReservedTags",
         "Effect": "Deny",
         "Action": "secretsmanager:UntagResource",
         "Resource": "*",
         "Condition": {
             "ForAnyValue:StringLike": {
                 "aws:TagKeys": "access-*"
             }
         }
     },
     {
         "Sid": "DenyPermissionsManagement",
         "Effect": "Deny",
         "Action": "secretsmanager:*Policy",
         "Resource": "*"
     }
 ]
}
```

------

**此策略有何作用？**
+ `AllActionsSecretsManagerSameProjectSameTeam` 语句允许对所有相关资源执行此服务的所有操作，但前提是资源标签与主体标签匹配。通过将 `"Action": "secretsmanager:*"` 添加到策略，策略将在 Secrets Manager 增长时扩展。如果 Secrets Manager 添加一个新的 API 操作，则您无需将该操作添加到语句。该语句使用三个条件块实施 ABAC。仅在所有三个块都返回 true 时允许该请求。
  + 如果资源上存在指定的标签键，并且其值与主体的标签匹配，则此语句的第一个条件块将返回 true。对于不匹配的标签或不支持资源标记的操作，此块返回 false。要了解此块不允许哪些操作，请参阅 [AWS Secrets Manager 的操作、资源和条件键](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awssecretsmanager.html)。此页面指明对 [**Secret (密钥)** 资源类型](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awssecretsmanager.html#awssecretsmanager-resources-for-iam-policies)执行的操作支持 `secretsmanager:ResourceTag/tag-key` 条件键。某些 [Secrets Manager 操作](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awssecretsmanager.html#awssecretsmanager-actions-as-permissions)不支持该资源类型，包括 `GetRandomPassword` 和 `ListSecrets`。您必须创建额外语句才能允许这些操作。
  + 如果请求中传递的每个标签键都包含在指定列表中，则第二个条件块将返回 true。通过将 `ForAllValues` 和 `StringEquals` 条件运算符结合使用来执行此操作。如果没有传递键或一组键的子集，则条件返回 true。对于不允许在请求中传递标签的 `Get*` 操作，这将允许该操作。如果请求者包含列表中没有的标签键，则条件返回 false。请求中传递的每个标签键均必须与该列表的一个成员匹配。有关更多信息，请参阅 [多值上下文键的集合运算符](reference_policies_condition-single-vs-multi-valued-context-keys.md#reference_policies_condition-multi-valued-context-keys)。
  + 在以下情况下，第三个条件块将返回 true：请求支持传递标签；所有三个标签都存在；标签与主体标签值匹配。如果请求不支持传递标签，则此块也返回 true。这要归功于条件运算符中的 [`...IfExists`](reference_policies_elements_condition_operators.md#Conditions_IfExists)。如果在支持该块的操作期间未传递任何标签，或者标签键和值不匹配，则该块将返回 false。
+ `AllResourcesSecretsManagerNoTags` 语句允许 `GetRandomPassword` 和 `ListSecrets` 操作，而第一个语句不允许这两项操作。
+ 如果使用与资源相同的 access-team 标签来标记主体，则 `ReadSecretsManagerSameTeam` 语句允许只读操作。无论项目或成本中心标签如何，都允许此操作。
+ `DenyUntagSecretsManagerReservedTags` 语句拒绝从 Secrets Manager 中删除带有以“access-”开头的键的标签的请求。这些标签用于控制对资源的访问，因此删除这些标签可能会删除权限。
+ `DenyPermissionsManagement` 语句拒绝访问创建、编辑或删除 Secrets Manager 的基于资源的策略。这些策略可用于更改密钥的权限。

**重要**  
此策略使用一种策略来允许服务的所有操作，但明确拒绝权限更改操作。拒绝操作将覆盖任何其他允许主体执行该操作的策略。这可能会产生意外结果。作为最佳实践，仅在没有允许该操作的情况下才使用显式拒绝。否则，允许各个操作的列表，默认情况下将拒绝不需要的操作。

## 步骤 3：创建角色
<a name="tutorial_abac_step3"></a>

创建以下 IAM 角色并附加您在上一步中创建的 **access-same-project-team** 策略。有关创建 IAM 角色的更多信息，请参阅 [创建角色，向 IAM 用户授予权限](id_roles_create_for-user.md)。如果选择使用联合身份而不是 IAM 用户和角色，请参阅 [IAM 教程：将 SAML 会话标签用于 ABAC](tutorial_abac-saml.md)。


| 作业函数 | 角色名称 | 角色标签 | 角色描述 | 
| --- | --- | --- | --- | 
|  项目 Pegasus 工厂  |  access-peg-engineering  |  access-project = `peg` access-team = `eng` cost-center = `987654`   | 允许工程师读取所有工程资源以及创建和管理 Pegasus 工程资源。 | 
|  项目 Pegasus 质量保证  |  access-peg-quality-assurance  |  access-project = `peg` access-team = `qas` cost-center = `987654`  |  允许 QA 团队读取所有 QA 资源以及创建和管理所有 Pegasus QA 资源。  | 
|  项目 Unicorn 工程  |  access-uni-engineering  |  access-project= `uni` access-team = `eng` cost-center = `123456`  | 允许工程师读取所有工程资源以及创建和管理 Unicorn 工程资源。 | 
|  项目 Unicorn 质量保证  |  access-uni-quality-assurance  |  access-project = `uni` access-team = `qas` cost-center = `123456`   |  允许 QA 团队读取所有 QA 资源以及创建和管理所有 Unicorn QA 资源。  | 

## 步骤 4：测试创建密钥
<a name="tutorial_abac_step4"></a>

附加到角色的权限策略允许员工创建密钥。仅在使用其项目、团队和成本中心标记密钥时允许这样做。通过在 Secrets Manager 中以用户身份登录、代入正确的角色并测试活动，确认您的权限按预期工作。

**测试创建带有和不带有所需标签的密钥**

1. 在您的主浏览器窗口中，仍以管理员用户身份登录，以便能在 IAM 中查看用户、角色和策略。使用浏览器无痕窗口或单独的浏览器来进行测试。在那里，以 `access-Arnav-peg-eng` IAM 用户的身份登录并打开 Secrets Manager 控制台，地址：[https://console.aws.amazon.com/secretsmanager/](https://console.aws.amazon.com/secretsmanager/)。

1. 尝试切换到 `access-uni-engineering` 角色。

   此操作失败，因为 `access-project` 和 `cost-center` 标签值与 `access-Arnav-peg-eng` 用户和 `access-uni-engineering` 角色的不匹配。

   有关在 AWS 管理控制台 中切换角色的更多信息，请参阅 [从用户切换到 IAM 角色（控制台）](id_roles_use_switch-role-console.md)。

1. 切换到 `access-peg-engineering` 角色。

1. 使用以下信息存储新密钥。要了解如何存储密钥，请参阅 *AWS Secrets Manager 用户指南*中的[创建基本密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html)。
**重要**  
Secrets Manager 会显示提醒，告知您没有权限使用与 Secrets Manager 配合使用的其他 AWS 服务。例如，要创建 Amazon RDS 数据库凭证，您必须有权描述 RDS 实例、RDS 集群和 Amazon Redshift 集群。您可以忽略这些提醒，因为您没有使用本教程中的这些特定 AWS 服务。

   1. 在 **Select secret type (选择密钥类型)** 部分中，选择 **Other type of secrets (其他类型的密钥)**。在两个文本框中，输入 `test-access-key` 和 `test-access-secret`。

   1. 为 **Secret name (密钥名称)** 字段输入 `test-access-peg-eng`。

   1. 从下表添加不同的标签组合，并查看预期行为。

   1. 选择 **Store (存储)** 以尝试创建密钥。当存储失败时，请返回之前的 Secrets Manager 控制台页面，并使用下表中的下一个标签集。允许使用最后一个标签集，并且将成功创建密钥。

   下表显示了 `test-access-peg-eng` 角色的 ABAC 标签组合。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

1. 注销并针对以下每个角色和标签值重复此过程的前三个步骤。在此过程的第四步中，测试所选的任何一组缺少的标签、可选标签、不允许的标签和无效的标签值。然后，使用所需的标签创建具有以下标签和名称的密钥。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

## 步骤 5：测试查看密钥
<a name="tutorial_abac_step5"></a>

您附加到每个角色的策略允许员工查看标记有其团队名称的所有密钥，而不管其项目如何。通过在 Secrets Manager 中测试您的角色来确认您的权限按预期工作。

**测试查看带有或不带有所需标签的密钥**

1. 以下列某个 IAM 用户身份登录：
   + `access-Arnav-peg-eng`
   + `access-Mary-peg-qas`
   + `access-Saanvi-uni-eng`
   + `access-Carlos-uni-qas`

1. 切换到匹配的角色：
   + `access-peg-engineering`
   + `access-peg-quality-assurance`
   + `access-uni-engineering`
   + `access-uni-quality-assurance`

   有关在 AWS 管理控制台中切换角色的更多信息，请参阅[从用户切换到 IAM 角色（控制台）](id_roles_use_switch-role-console.md)。

1. 在左侧导航窗格中，选择菜单图标以展开菜单，然后选择 **Secrets (密钥)**。

1. 无论您当前的角色如何，都应在表中看到所有四个密钥。这是预期情况，因为名为 `access-same-project-team` 的策略允许对所有资源执行 `secretsmanager:ListSecrets` 操作。

1. 选择其中一个密钥的名称。

1. 在密钥的详细信息页面上，您的角色标签将确定您是否能查看页面内容。将您的角色名称与您的密钥名称进行比较。如果它们共享同一团队名称，则 `access-team` 标签匹配。如果它们不匹配，则访问将被拒绝。

   下表显示每个角色的 ABAC 密钥查看行为。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

1. 从页面顶部的痕迹导航中，选择 **Secrets (密钥)** 以返回密钥列表。使用不同的角色重复此过程中的步骤来测试您是否能查看每个密钥。

## 步骤 6：测试可扩展性
<a name="tutorial_abac_step6"></a>

在基于角色的访问控制 (RBAC) 上使用基于属性的访问控制 (ABAC) 的重要原因是可扩展性。当您的公司向 AWS 添加新的项目、团队或人员时，您无需更新 ABAC 驱动型策略。例如，假设 Example Company 正在资助一个代号为 **Centaur** 的新项目。一个名叫 Saanvi Sarkar 的工程师将成为 **Centaur** 的工程师主管，同时该工程师还参与了 **Unicorn** 项目。Saanvi 还将审查 **Peg** 项目的工作。此外，新聘用了几名工程师，其中包括 Nikhil Jayashankar，他仅参与 **Centaur** 项目。

**向 AWS 添加新项目**

1. 以 IAM 管理员登录，然后通过以下网址打开 IAM 控制台：[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)。

1. 在左侧导航窗格中，选择 **Roles**（角色），然后添加名为 `access-cen-engineering` 的 IAM 角色。将 **access-same-project-team** 权限策略附加到角色并添加以下角色标签：
   + `access-project` = `cen`
   + `access-team` = `eng`
   + `cost-center` = `101010`

1. 在左侧导航窗格中，请选择**用户**。

1. 添加一个名为 `access-Nikhil-cen-eng` 的新用户，并附加名为 `access-assume-role` 的策略，然后添加以下用户标签。
   + `access-project` = `cen`
   + `access-team` = `eng`
   + `cost-center` = `101010`

1. 使用[步骤 4：测试创建密钥](#tutorial_abac_step4)和[步骤 5：测试查看密钥](#tutorial_abac_step5)中的过程。在另一个浏览器窗口中，测试 Nikhil 是否能创建 **Centaur** 工程密钥并且是否能查看所有工程密钥。

1. 在您以管理员身份登录的主浏览器窗口中，选择用户 `access-Saanvi-uni-eng`。

1. 在 **Permissions (权限)** 选项卡上，删除 **access-assume-role** 权限策略。

1. 添加以下名为 `access-assume-specific-roles` 的内联策略。有关将内联策略添加到用户的更多信息，请参阅[为用户或角色嵌入内联策略（控制台）](access_policies_manage-attach-detach.md#embed-inline-policy-console)。

**ABAC 策略：仅代入特定角色**  
此策略允许 Saanvi 代入 **Pegasus** 或 **Centaur** 项目的工程角色。由于 IAM 不支持多值标签，因此有必要创建此自定义策略。不能使用 `access-project` = `peg` 和 `access-project` = `cen` 标记 Saanvi 用户。此外，AWS 授权模型不能同时与这两个值匹配。有关更多信息，请参阅 [在 IAM 和 AWS STS 中进行标记的规则](id_tags.md#id_tags_rules)。相反，您必须手动指定她可以代入的两个角色。

   要使用此策略，请将示例策略中的*斜体占位符文本*替换为您的账户信息。

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

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "TutorialAssumeSpecificRoles",
               "Effect": "Allow",
               "Action": "sts:AssumeRole",
               "Resource": [
                   "arn:aws:iam::111122223333:role/access-peg-engineering",
                   "arn:aws:iam::111122223333:role/access-cen-engineering"
               ]
           }
       ]
   }
   ```

------

1. 使用[步骤 4：测试创建密钥](#tutorial_abac_step4)和[步骤 5：测试查看密钥](#tutorial_abac_step5)中的过程。在另一个浏览器窗口中，确认 Saanvi 可以代入这两个角色。检查她是否只能根据角色的标签为项目、团队和成本中心创建密钥。此外，确认她能够查看有关工程团队拥有的所有密钥（包括她刚创建的密钥）的详细信息。

## 步骤 7：测试更新和删除密钥
<a name="tutorial_abac_step7"></a>

附加到角色的 `access-same-project-team` 策略允许员工更新和删除任何标记有项目、团队和成本中心的密钥。通过在 Secrets Manager 中测试您的角色来确认您的权限按预期工作。

**测试更新和删除带有和不带有所需标签的密钥**

1. 以下列某个 IAM 用户身份登录：
   + `access-Arnav-peg-eng`
   + `access-Mary-peg-qas`
   + `access-Saanvi-uni-eng`
   + `access-Carlos-uni-qas`
   + `access-Nikhil-cen-eng`

1. 切换到匹配的角色：
   + `access-peg-engineering`
   + `access-peg-quality-assurance`
   + `access-uni-engineering`
   + `access-peg-quality-assurance`
   + `access-cen-engineering`

   有关在 AWS 管理控制台中切换角色的更多信息，请参阅[从用户切换到 IAM 角色（控制台）](id_roles_use_switch-role-console.md)。

1. 对于每个角色，请尝试更新密钥描述，然后尝试删除以下密钥。有关更多信息，请参阅 *AWS Secrets Manager 用户指南*中的[修改密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_update-secret.html)和[删除和还原密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_delete-restore-secret.html)。

   下表显示每个角色的 ABAC 密钥更新和删除行为。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

## 摘要
<a name="tutorial-abac-summary"></a>

您现在已成功完成将标签用于基于属性的访问控制 (ABAC) 所需的所有步骤。您已了解如何定义标记策略。您已将该策略应用于主体和资源。您已创建并应用一个为 Secrets Manager 强制实施该策略的策略。您还了解到，在添加新项目和团队成员时，ABAC 可以轻松扩展。因此，您可以使用测试角色登录 IAM 控制台，并体验如何在 AWS 中将标签用于 ABAC。

**注意**  
您添加的策略仅允许在特定条件下执行操作。如果您将不同的策略应用于具有更广泛权限的用户或角色，则可能不会将操作限制为需要标记。例如，如果您使用 `AdministratorAccess`AWS 托管策略向用户授予完全管理权限，则这些策略不会限制该访问。有关在涉及多个策略时如何确定权限的更多信息，请参阅[AWS 执行代码逻辑如何评估允许或拒绝访问的请求](reference_policies_evaluation-logic_policy-eval-denyallow.md)。

## 相关资源
<a name="tutorial_abac_related"></a>

有关信息，请参阅以下资源：
+ [使用 ABAC 授权根据属性定义权限](introduction_attribute-based-access-control.md)
+ [AWS 全局条件上下文密钥](reference_policies_condition-keys.md)
+ [创建角色，向 IAM 用户授予权限](id_roles_create_for-user.md)
+ [AWS Identity and Access Management 资源的标签](id_tags.md)
+ [使用标签控制对 AWS 资源的访问](access_tags.md)
+ [从用户切换到 IAM 角色（控制台）](id_roles_use_switch-role-console.md)
+ [IAM 教程：将 SAML 会话标签用于 ABAC](tutorial_abac-saml.md)

要了解如何监控账户中的标签，请参阅[使用无服务器工作流程和 Amazon CloudWatch Events](https://aws.amazon.com/blogs/mt/monitor-tag-changes-on-aws-resources-with-serverless-workflows-and-amazon-cloudwatch-events/) 监控 AWS 资源的标签更改。

# IAM 教程：将 SAML 会话标签用于 ABAC
<a name="tutorial_abac-saml"></a>

基于属性的访问权限控制 (ABAC) 是一种授权策略，该策略基于属性来定义权限。在 AWS 中，这些属性称为标签。您可以将标签附加到 IAM 资源（包括 IAM 实体（用户和角色））以及 AWS 资源。将实体用于向 AWS 发出请求时，实体成为主体并且包含标签。

您也可以在代入角色或联合身份用户时传递[会话标签](id_session-tags.md)。然后，您可以定义策略，这些策略使用标签条件键来根据主体的标签向其授予权限。当您使用标签控制对 AWS 资源的访问时，可通过对 AWS 策略进行较少更改来实现团队和资源的增长。ABAC 策略比传统 AWS 策略更加灵活，后者需要您列出每个单独的资源。有关 ABAC 及其相对于传统策略的优势的更多信息，请参阅[使用 ABAC 授权根据属性定义权限](introduction_attribute-based-access-control.md)。

如果您的公司使用基于 SAML 的身份提供程序 (IdP) 管理公司用户身份，则可以在 AWS 中使用 SAML 属性进行细粒度访问控制。属性包括成本中心标识符、用户电子邮件地址、部门分类和项目分配等。当您将这些属性作为会话标签传递时，可以根据这些会话标签控制对 AWS 的访问权限。

要通过将 SAML 属性传递给会话主体来完成 [ABAC 教程](tutorial_attribute-based-access-control.md)，请完成 [IAM 教程：根据标签定义访问 AWS 资源的权限](tutorial_attribute-based-access-control.md) 中的任务以及本主题中介绍的更改。

## 先决条件
<a name="tutorial_abac-saml-prerequisites"></a>

要执行将 SAML 会话标签用于 ABAC 的步骤，您必须满足以下条件：
+ 对基于 SAML 的 IdP 的访问权限，您在其中可以创建具有特定属性的测试用户。
+ 能够以具有管理员权限的用户身份登录。
+ 体验在 AWS 管理控制台 中创建和编辑 IAM 用户、角色和策略。但是，如果您需要获得帮助以便记住 IAM 管理过程，请访问 ABAC 教程提供的链接来查看分步说明。
+ 在 IAM 中设置基于 SAML 的 IdP 的经验。要查看详细信息以及指向详细 IAM 文档的链接，请参阅 [使用 AssumeRoleWithSAML 传递会话标签](id_session-tags.md#id_session-tags_adding-assume-role-saml)。

## 步骤 1：创建测试用户
<a name="tutorial_abac-saml-step1"></a>

跳过[步骤 1：创建测试用户](tutorial_attribute-based-access-control.md#tutorial_abac_step1)中的说明。由于您在提供商中定义身份，因此无需为员工添加 IAM 用户。

## 步骤 2：创建 ABAC 策略
<a name="tutorial_abac-saml-step2"></a>

按照 [步骤 2：创建 ABAC 策略](tutorial_attribute-based-access-control.md#tutorial_abac_step2) 中的说明在 IAM 中创建指定的托管策略。

## 步骤 3：创建和配置 SAML 角色
<a name="tutorial_abac-saml-step3"></a>

为 SAML 使用 ABAC 教程时，您必须执行额外的步骤来创建角色、配置 SAML IdP 和启用 AWS 管理控制台 访问权限。有关更多信息，请参阅 [步骤 3：创建角色](tutorial_attribute-based-access-control.md#tutorial_abac_step3)。

### 步骤 3A：创建 SAML 角色
<a name="tutorial_abac-saml-step3a"></a>

创建一个信任 SAML 身份提供程序和在步骤 1 中创建的 `test-session-tags` 用户的角色。ABAC 教程使用具有不同角色标签的单独角色。由于您从 SAML IdP 传递会话标签，因此只需要一个角色。要了解如何创建基于 SAML 的角色，请参阅[创建用于 SAML 2.0 联合身份验证的角色（控制台）](id_roles_create_for-idp_saml.md)。

将角色命名为 `access-session-tags`。将 `access-same-project-team` 权限策略附加到角色。编辑角色信任策略来使用以下策略。有关如何编辑角色的信任关系的详细说明，请参阅[更新角色信任策略](id_roles_update-role-trust-policy.md)。

以下角色信任策略允许您的 SAML 身份提供程序和 `test-session-tags` 用户代入该角色。在代入角色时，他们必须传递三个指定的会话标签。`sts:TagSession` 操作是允许传递会话标签所必需的。

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowSamlIdentityAssumeRole",
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRoleWithSAML",
                "sts:TagSession"
            ],
            "Principal": {"Federated":"arn:aws:iam::123456789012:saml-provider/ExampleCorpProvider"},
            "Condition": {
                "StringLike": {
                    "aws:RequestTag/cost-center": "*",
                    "aws:RequestTag/access-project": "*",
                    "aws:RequestTag/access-team": [
                        "eng",
                        "qas"
                    ]
                },
                "StringEquals": {"SAML:aud": "https://signin.aws.amazon.com/saml"}
            }
        }
    ]
}
```

------

`AllowSamlIdentityAssumeRole` 语句允许工程和质量保证团队的成员在从示例公司 IdP 将身份联合到 AWS 中时代入此角色。`ExampleCorpProvider` SAML 提供商在 IAM 中定义。管理员已经设置 SAML 断言以传递三个必需的会话标签。断言可以传递额外的标签，但必须存在这三个标签。身份的属性可以具有 `cost-center` 和 `access-project` 标签的任何值。但是，`access-team` 属性值必须匹配 `eng` 或 `qas`，以指示位于工程或质量保证团队中的身份。

### 步骤 3B：配置 SAML IdP
<a name="tutorial_abac-saml-step3b"></a>

配置您的 SAML IdP 以将 `cost-center`、`access-project` 和 `access-team` 属性作为会话标签传递。有关更多信息，请参阅 [使用 AssumeRoleWithSAML 传递会话标签](id_session-tags.md#id_session-tags_adding-assume-role-saml)。

要将这些属性作为会话标签传递，请在 SAML 断言中包含以下元素。

```
<Attribute Name="https://aws.amazon.com/SAML/Attributes/PrincipalTag:cost-center">
  <AttributeValue>987654</AttributeValue>
</Attribute>
<Attribute Name="https://aws.amazon.com/SAML/Attributes/PrincipalTag:access-project">
  <AttributeValue>peg</AttributeValue>
</Attribute>
<Attribute Name="https://aws.amazon.com/SAML/Attributes/PrincipalTag:access-team">
  <AttributeValue>eng</AttributeValue>
</Attribute>
```

### 步骤 3C：启用控制台访问
<a name="tutorial_abac-saml-step3b"></a>

为联合身份 SAML 用户启用控制台访问权限。有关更多信息，请参阅 [使 SAML 2.0 联合主体能够访问 AWS 管理控制台](id_roles_providers_enable-console-saml.md)。

## 步骤 4：测试创建密钥
<a name="tutorial_abac-saml-step4"></a>

使用 `access-session-tags` 角色联合身份到 AWS 管理控制台中。有关更多信息，请参阅 [使 SAML 2.0 联合主体能够访问 AWS 管理控制台](id_roles_providers_enable-console-saml.md)。然后按照说明 [步骤 4：测试创建密钥](tutorial_attribute-based-access-control.md#tutorial_abac_step4) 创建密钥。使用不同的 SAML 身份，该身份的属性与 ABAC 教程中指示的标签匹配。有关更多信息，请参阅 [步骤 4：测试创建密钥](tutorial_attribute-based-access-control.md#tutorial_abac_step4)。

## 步骤 5：测试查看密钥
<a name="tutorial_abac-saml-step5"></a>

按照[步骤 5：测试查看密钥](tutorial_attribute-based-access-control.md#tutorial_abac_step5)中的说明查看在上一步中创建的密钥。使用不同的 SAML 身份，该身份的属性与 ABAC 教程中指示的标签匹配。

## 步骤 6：测试可扩展性
<a name="tutorial_abac-saml-step6"></a>

按照[步骤 6：测试可扩展性](tutorial_attribute-based-access-control.md#tutorial_abac_step6)中的说明测试可扩展性。要执行此操作，您可在基于 SAML 的 IdP 中添加具有以下属性的新身份：
+ `cost-center = 101010`
+ `access-project = cen`
+ `access-team = eng`

## 步骤 7：测试更新和删除密钥
<a name="tutorial_abac-saml-step7"></a>

按照[步骤 7：测试更新和删除密钥](tutorial_attribute-based-access-control.md#tutorial_abac_step7)中的说明更新和删除密钥。使用不同的 SAML 身份，该身份的属性与 ABAC 教程中指示的标签匹配。

**重要**  
删除您创建的所有密钥以避免产生费用。有关 Secrets Manager 中定价的详细信息，请参阅 [AWS Secrets Manager 定价](https://aws.amazon.com/secrets-manager/pricing/)。

## 摘要
<a name="tutorial-abac-saml-summary"></a>

您现在已成功完成使用 SAML 会话标签和资源标签进行权限管理所需的所有步骤。

**注意**  
您添加的策略仅允许在特定条件下执行操作。如果您将不同的策略应用于具有更广泛权限的用户或角色，则可能不会将操作限制为需要标记。例如，如果您使用 `AdministratorAccess`AWS 托管策略向用户授予完全管理权限，则这些策略不会限制该访问。有关在涉及多个策略时如何确定权限的更多信息，请参阅[AWS 执行代码逻辑如何评估允许或拒绝访问的请求](reference_policies_evaluation-logic_policy-eval-denyallow.md)。

# IAM 教程：允许用户管理其凭证和 MFA 设置
<a name="tutorial_users-self-manage-mfa-and-creds"></a>

您可以允许用户在**安全凭证**页面上管理自己的多重身份验证（MFA）设备和凭证。您可以使用 AWS 管理控制台为用户配置凭证（访问密钥、密码、签名证书和 SSH 公有密钥）、删除或停用不再需要的凭证，以及启用 MFA 设备。这在用户数量较少时较为实用，不过随着用户数量增加，这一任务很快会变得非常耗时。本教程旨在介绍如何实现这些最佳实践，而不给您的管理员带来负担。

本教程介绍如何允许用户访问 AWS 服务，不过此操作**仅**限于用户使用 MFA 登录的情况。如果未使用 MFA 设备登录，则用户无法访问其他服务。

此工作流程具有三个基本步骤。

**[步骤 1：创建策略以强制 MFA 登录](#tutorial_mfa_step1)**  
创建客户管理型策略以禁止***除***少量 IAM 操作以外的所有操作。这些例外允许用户在**安全凭证**页面上更改自己的凭证并管理其 MFA 设备。有关访问该页面的更多信息，请参阅[IAM 用户如何更改自己的密码（控制台）](id_credentials_passwords_user-change-own.md#ManagingUserPwdSelf-Console)。

**[步骤 2：将策略附加到您的测试用户组](#tutorial_mfa_step2)**  
创建一个用户组，在使用 MFA 登录时，该组的成员具有所有 Amazon EC2 操作的完全访问权限。要创建此类用户组，请附加名为 `AmazonEC2FullAccess` 的 AWS 托管策略和在步骤 1 中创建的客户托管策略。

**[步骤 3：测试您的用户的访问权限](#tutorial_mfa_step3)**  
以测试用户身份登录，验证对 Amazon EC2 的访问是否被阻止，*直*至该用户创建 MFA 设备为止。之后，用户可以使用该设备进行登录。

## 先决条件
<a name="tutorial_mfa_prereqs"></a>

要执行本教程中的步骤，您必须已具备以下内容：
+ 可作为 IAM 用户身份登录且具有管理权限的 AWS 账户。
+ 您在步骤 1 的策略中键入的账户 ID 号。

  要查找您的账户 ID 号，请在页面顶部的导航栏上，选择 **Support**，然后选择 **Support Center**。您可以在该页面的 **Support** 菜单下找到您的账户 ID。
+ [虚拟（基于软件的）MFA 设备](id_credentials_mfa_enable_virtual.md)、[FIDO 安全密钥](id_credentials_mfa_enable_fido.md)或[基于硬件的 MFA 设备](id_credentials_mfa_enable_physical.md)。
+ 一个作为组成员的测试 IAM 用户，如下所示：


| 用户名称 | 用户名说明 | 用户组名称 | 将用户添加为成员 | 用户组说明 | 
| --- | --- | --- | --- | --- | 
| MFAUser | 仅选择启用控制台访问 – 可选选项，然后分配密码。 | EC2MFA | MFAUser | 请勿向此用户组附加任何策略或授予任何权限。 | 

## 步骤 1：创建策略以强制 MFA 登录
<a name="tutorial_mfa_step1"></a>

首先创建一个 IAM 客户托管策略，除 IAM 用户管理其自有凭证和 MFA 设备所需的权限外，该策略拒绝其他所有权限。

1. 以具有管理员凭证的用户身份登录 AWS 管理控制台。根据 IAM 最佳实践，请勿使用 AWS 账户根用户凭证登录。
**重要**  
 IAM [最佳实践](best-practices.md)建议您您要求人类用户使用与身份提供商的联合身份验证才能使用临时凭证访问 AWS，而不是使用具有长期凭证的 IAM 用户。建议您仅在联合用户不支持的[特定用例](gs-identities-iam-users.md)中使用 IAM 用户。

1. 访问：[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)，打开 IAM 控制台。

   

1. 在导航窗格中，选择 **Policies (策略)**，然后选择 **Create policy (创建策略)**。

1. 选择 **JSON** 选项卡，然后复制以下 JSON 策略文档中的文本：[AWS：允许使用 MFA 完成身份验证的 IAM 用户在“安全凭证”页面上管理自己的凭证。](reference_policies_examples_aws_my-sec-creds-self-manage.md)。

1. 将该策略粘贴到 **JSON** 文本框中。解决策略验证过程中生成的任何安全警告、错误或常规警告，然后选择**下一步**。
**注意**  
您可以随时在**可视化编辑器**和 **JSON** 选项之间切换。但是，以上策略包含 `NotAction` 元素，该元素在可视化编辑器中不受支持。对于此策略，您在 **Visual editor** 选项卡上将看到一个通知。返回 **JSON** 以继续处理此策略。  
此示例策略不允许用户在首次登录 AWS 管理控制台 的同时重置密码。我们建议您在新用户登录并重置密码之前不要向他们授予权限。

1. 在**查看并创建**页面上，键入 **Force\$1MFA** 作为策略名称。对于策略描述，在**标签**区域键入 **This policy allows users to manage their own passwords and MFA devices but nothing else unless they authenticate with MFA.**，您可以有选择地将标签键值对添加到客户管理型策略。查看您的策略授予的权限，然后选择**创建策略**以保存您的工作。

   将在托管策略列表中显示新策略，并已准备好附加该策略。

## 步骤 2：将策略附加到您的测试用户组
<a name="tutorial_mfa_step2"></a>

接下来，您将两个策略附加到测试 IAM 用户组，将使用该组授予受 MFA 保护的权限。

1. 在导航窗格中，选择 **User groups**（用户组）。

1. 在搜索框中键入 **`EC2MFA`**，然后在列表中选择组名称（而不是复选框）。

1. 请选择**权限**选项卡，选择**添加权限**，然后选择**附加策略**。

1. 在 **Attach permission policies to EC2MFA group**（将权限策略附加到 EC2MFA 组）页面上，在搜索框中键入 **EC2Full**。然后，选中列表中 **AmazonEC2FullAccess** 旁边的复选框。暂不保存您的更改。

1. 在搜索框中键入 **Force**，然后选中列表中 **Force\$1MFA** 旁边的复选框。

1. 选择**附加策略**。

## 步骤 3：测试您的用户的访问权限
<a name="tutorial_mfa_step3"></a>

在本教程的这一部分中，您以测试用户身份登录并验证策略是否正常工作。

1. 使用上一部分中分配给您的密码，以 **MFAUser** 身份登录您的 AWS 账户。使用 URL：`https://<alias or account ID number>.signin.aws.amazon.com/console`

1. 选择 **EC2** 打开 Amazon EC2 控制台，验证此用户没有执行任何操作的权限。

1. 在右上角的导航栏中，选择 `MFAUser` 用户名，然后选择 **Security credentials**（安全凭证）。  
![\[AWS 管理控制台安全凭证链接。\]](http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/images/security-credentials-user.shared.console.png)

1. 现在添加一个 MFA 设备。在**多重身份验证 (MFA)** 部分中，选择**分配 MFA 设备**。
**注意**  
可能会出现未授权您执行 `iam:DeleteVirtualMFADevice` 的错误。如果某个人以前开始将虚拟 MFA 设备分配给该用户并取消了该过程，则可能会发生这种情况。要继续，您或其他管理员必须删除用户现有的未分配虚拟 MFA 设备。有关更多信息，请参阅 [我没有权限执行：iam:DeleteVirtualMFADevice](troubleshoot.md#troubleshoot_general_access-denied-delete-mfa)。

1. 对于本教程，我们使用一个虚拟 (基于软件的) MFA 设备，例如，手机上的 Google Authenticator 应用程序。选择 **Authenticator app**（身份验证器应用程序），然后单击 **Next**（下一步）。

   IAM 将生成并显示虚拟 MFA 设备的配置信息，包括 QR 代码图形。此图形是秘密配置密钥的表示形式，适用于不支持 QR 代码的设备上的手动输入。

1. 打开您的虚拟 MFA 应用程序。（有关可以用作托管虚拟 MFA 设备的应用程序的列表，请参阅[虚拟 MFA 应用程序](https://aws.amazon.com/iam/details/mfa/#Virtual_MFA_Applications)。） 如果虚拟 MFA 应用程序支持多个账户 (多个虚拟 MFA 设备)，请选择相应的选项以创建新账户 (新的虚拟 MFA 设备)。

1. 确定 MFA 应用程序是否支持 QR 代码，然后执行以下操作之一：
   + 在向导中，选择 **Show QR code (显示 QR 代码)**。使用此应用程序扫描 QR 代码。例如，您可选择摄像头图标或选择类似于 **Scan code** 的选项，然后使用设备的摄像头扫描此代码。
   + 在 **Set up device**（设置设备）向导中，选择 **Show secret key**（显示私有密钥），然后在您的 MFA 应用程序中键入私有密钥。

   完成操作后，虚拟 MFA 设备会开始生成一次性密码。

1. 在 **Set up device**（设置设备）向导的 **Enter the code from your authenticator app.**（键入身份验证器应用程序中的代码。）框中，键入虚拟 MFA 设备上当前显示的一次性密码。选择 **Register MFA**（注册 MFA）。
**重要**  
生成代码之后立即提交您的请求。如果在生成代码后等待很长时间才提交请求，MFA 设备将成功与用户关联，但 MFA 设备不同步。这是因为基于时间的一次性密码（TOTP）很快会过期。这种情况下，您可以[重新同步设备](id_credentials_mfa_sync.md)。

   虚拟 MFA 设备现已准备好与 AWS 一起使用。

1. 从控制台注销，然后重新以 **MFAUser** 身份登录。此时 AWS 会提示输入您手机中的 MFA 代码。收到该代码后，请将代码键入框中，然后选择 **Submit**。

1. 选择 **EC2** 以再次打开 Amazon EC2 控制台。请注意，这次您可以看到所有信息，并且可以执行所需的任何操作。如果您以该用户身份转至任何其他控制台，则会看到指示访问被拒绝的消息。导致出现此问题的原因是，本教程中的策略仅向 Amazon EC2 授予访问权限。

## 相关资源
<a name="tutorial_mfa_related"></a>

有关更多信息，请参阅以下主题：
+ [IAM 中的 AWS 多重身份验证](id_credentials_mfa.md)
+ [已启用 MFA 的登录](console_sign-in-mfa.md)

# IAM 教程：使用 CloudFormation 模板创建 SAML 身份提供者 (IdP)
<a name="tutorial_saml-idp"></a>

要为您的 AWS 账户设置 SAML 联合身份验证，需要创建 SAML 身份提供者 (IdP)。本教程展示如何使用 CloudFormation 模板创建 SAML IdP，以便在 AWS 和外部 IdP 之间建立信任。

该模板会创建一个使用 IdP 元数据文档进行配置的 SAML IdP。然后，联合 IAM 角色可引用此 IdP，以允许来自外部 IdP 的经过身份验证的用户访问 AWS 资源。

所部署的资源中含有一个配置了 IdP 元数据文档和可选加密设置的 SAML IdP。

## 先决条件
<a name="tutorial_saml-idp-prereqs"></a>

本教程假定您已准备好以下各项：
+ 本地计算机上安装了 Python 3.6 或更高版本，可运行本教程中用于对 IdP 的 SAML 元数据 XML 文件进行格式化的 Python 命令。
+ 来自外部 IdP 的 SAML 元数据文档，另存为 XML 文件。

## 使用 CloudFormation 创建 SAML IdP
<a name="tutorial_saml-idp-create"></a>

要创建 SAML IdP，您需要创建 CloudFormation 模板，并使用此模板创建包含 IdP 资源的堆栈。

### 创建模板
<a name="tutorial_saml-idp-file"></a>

首先，创建 CloudFormation 模板。

1. 在 [模板](#tutorial_saml-idp-template) 部分中，单击 **JSON** 或 **YAML** 选项卡上的复制图标，以复制模板内容。

1. 将模板内容粘贴到新文件中。

1. 将该文件保存在本地。

### 创建堆栈
<a name="tutorial_saml-idp-stack"></a>

接下来，使用已保存的模板来预置 CloudFormation 堆栈。

1. 通过以下网址打开 CloudFormation 控制台：[https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/)。

1. 在**堆栈**页面，从**创建堆栈**菜单中选择**（采用新资源（标准））**。

1. 指定模板：

   1. 在**先决条件**下，选择**选择现有模板**。

   1. 在**指定模板**下，选择**上传模板文件**。

   1. 选择**选择文件**，导航到模板文件并将其选中。

   1. 选择**下一步**。

1. 指定以下堆栈详细信息：

   1. 输入堆栈名称。

   1. 对于 **IdentityProviderName**，可将其留空以根据堆栈名称自动生成名称，也可以为 SAML IdP 输入自定义名称。自定义名称只能包含字母数字字符、句点、下划线和连字符。

   1. 对于 **IdentityProvidersamlMetadataDocument**，在将 SAML 元数据 XML 文件粘贴到此字段之前，需要将其格式化为单行。这是必要的，因为 CloudFormation 控制台要求 XML 内容在通过控制台参数传递时需格式化为单行。

      使用以下 Python 命令重新格式化 XML 文件：

      ```
      python3 -c "import sys, re; content=open(sys.argv[1]).read(); print(re.sub(r'>\s+<', '><', content.replace('\n', '').replace('\r', '').strip()))" saml-metadata.xml
      ```
**注意**  
IdP 的 SAML 元数据文档必须格式化为单行才能输入控制台参数。Python 命令删除了换行符和多余空格以创建所需的格式，同时保留所有原始内容和结构。

      复制 Python 命令的输出并将其粘贴到 **IdentityProviderSAMLMetadataDocument** 字段中。

      格式化的 SAML 元数据文档示例（缩减版）：

      ```
      <?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://portal.sso.example.com/saml/assertion/CompanyIdP"><md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDXTCCAkWgAwIBAgIJAJC1HiIAZAiIMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV...</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://portal.sso.example.com/saml/logout/CompanyIdP"/><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://portal.sso.example.com/saml/assertion/CompanyIdP"/></md:IDPSSODescriptor></md:EntityDescriptor>
      ```

   1. 对于其他参数，请接受默认值或根据需要输入自己的值：
      + **IdentityProviderAddPrivateKey** - 解密 SAML 断言的可选私钥
      + **IdentityProviderAssertionEncryptionMode** - 可选项，可设置 SAML 断言加密模式（“允许”、“必需”或空）

   1. 选择**下一步**。

1. 配置堆栈选项：

   1. 在**堆栈故障选项**下，选择**删除所有新创建的资源**。
**注意**  
如果选择此选项，即使堆栈创建失败，您可能也不会因为删除策略规定保留资源而向资源付费。

   1. 接受其他所有默认值。

   1. 在**功能**下勾选复选框，确认 CloudFormation 可能在您的账户中创建 IAM 资源。

   1. 选择**下一步**。

1. 查看堆栈详细信息并选择**提交**。

CloudFormation 将创建堆栈。一旦堆栈创建完成之后，堆栈资源就即可投入使用。可使用堆栈详细信息页面上的**资源**选项卡来查看账户中预置的资源。

堆栈将输出以下值，可参见**输出**选项卡：
+ **ProviderARN**：已创建的 SAML IdP 的 ARN（例如，`arn:aws:iam::123456789012:saml-provider/CompanyIdP`）。在创建信任此提供商的角色时需要此 ARN。
+ **ProviderName**：已创建的 SAML IdP 的名称（例如 `CompanyIdP`，如果指定自定义名称；或者 `my-saml-stack-saml-provider`，如果使用默认命名）。

这些输出还会被导出，以便由其他 CloudFormation 堆栈使用 `Fn::ImportValue` 函数进行导入。

## 验证 SAML IdP
<a name="tutorial_saml-idp-using"></a>

一旦创建 SAML IdP 后，即可验证其配置并记下其 ARN 以供联合角色使用。

1. 通过 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

1. 在导航窗格中，选择 **Identity providers**（身份提供程序）。

   您应该能在列表中看到新创建的 SAML IdP。

1. 选择 IdP 名称以查看其详细信息。

   在 IdP 详细信息页面上，可以看到 SAML 元数据文档和其他配置详细信息。

1. 记下详细信息页面上显示的**提供者 ARN**。

   在创建信任此 IdP 的联合 IAM 角色时需要此 ARN。

1. 查看元数据文档，确保其与您从外部 IdP 提供的文档相符。

您的 SAML IdP 现已准备好供联合 IAM 角色使用。您可以创建信任此 IdP 的角色，以允许来自外部 IdP 的经过身份验证的用户代入这些角色并访问 AWS 资源。

## 清理：删除资源
<a name="tutorial_saml-idp-delete"></a>

最后一步，您将删除该堆栈及其包含的资源。

1. 打开 CloudFormation 控制台。

1. 在**堆栈**页面上，选择根据该模板创建的堆栈，选择**删除**，然后确认**删除**。

   CloudFormation 启动删除堆栈及其包含的所有资源。

## CloudFormation 模板详细信息
<a name="tutorial_saml-idp-template-details"></a>

### 资源
<a name="tutorial_saml-idp-template-resources"></a>

本教程的 CloudFormation 模板将在您的账户中创建以下资源：

[https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-samlprovider.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-samlprovider.html)：一个在 AWS 和外部 IdP 之间建立信任的 SAML IdP。

### 配置
<a name="tutorial_saml-idp-template-config"></a>

模板包含如下可配置参数：
+ **IdentityProviderName** - SAML IdP 的名称（自动生成的名字请留空）

  示例：`CompanyIdP` 或 `EnterpriseSSO`
+ **IdentityProviderSAMLMetadataDocument** - 来自外部 IdP 的 SAML 元数据文档（格式化为单行）
+ **IdentityProviderAddPrivateKey** - 解密 SAML 断言的可选私钥
+ **IdentityProviderAssertionEncryptionMode** - 可选项，可设置 SAML 断言加密模式

## CloudFormation 模板
<a name="tutorial_saml-idp-template"></a>

将以下 JSON 或 YAML 代码另存为单独文件，以用作本教程的 CloudFormation 模板。

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

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "[AWSDocs] IAM: tutorial_saml-idp",
  "Parameters": {
    "IdentityProviderName": {
      "Type": "String",
      "Description": "Name of the SAML Identity Provider (leave empty for auto-generated name like '{StackName}-{UniqueId}')",
      "Default": "",
      "AllowedPattern": "^$|^[a-zA-Z0-9._-]+$",
      "ConstraintDescription": "Must be empty or contain only alphanumeric characters, periods, underscores, and hyphens"
    },
    "IdentityProviderSAMLMetadataDocument": {
      "Type": "String",
      "Description": "SAML metadata document from identity provider"
    },
    "IdentityProviderAddPrivateKey": {
      "Type": "String",
      "Description": "Optional private key for decrypting SAML assertions. The private key must be a .pem file that uses AES-GCM or AES-CBC encryption algorithm to decrypt SAML assertions.",
      "Default": ""
    },
    "IdentityProviderAssertionEncryptionMode": {
      "Type": "String",
      "Description": "Optional, sets encryption mode for SAML assertions",
      "Default": "",
      "AllowedValues": ["", "Allowed", "Required"]
    }
  },
  "Conditions": {
    "HasPrivateKey": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAddPrivateKey"}, ""]}]},
    "HasEncryptionMode": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAssertionEncryptionMode"}, ""]}]},
    "HasCustomName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderName"}, ""]}]}
  },
  "Resources": {
    "SAMLProvider": {
      "Type": "AWS::IAM::SAMLProvider",
      "Properties": {
        "Name": {"Fn::If": ["HasCustomName", {"Ref": "IdentityProviderName"}, {"Ref": "AWS::NoValue"}]},
        "SamlMetadataDocument": {"Ref": "IdentityProviderSAMLMetadataDocument"},
        "Tags": [
          {
            "Key": "Name",
            "Value": {"Fn::If": ["HasCustomName", {"Ref": "IdentityProviderName"}, {"Fn::Sub": "${AWS::StackName}-saml-provider"}]}
          }
        ],
        "AddPrivateKey": {"Fn::If": ["HasPrivateKey", {"Ref": "IdentityProviderAddPrivateKey"}, {"Ref": "AWS::NoValue"}]},
        "AssertionEncryptionMode": {"Fn::If": ["HasEncryptionMode", {"Ref": "IdentityProviderAssertionEncryptionMode"}, {"Ref": "AWS::NoValue"}]}
      }
    }
  },
  "Outputs": {
    "ProviderARN": {
      "Description": "ARN of the created SAML Identity Provider",
      "Value": {"Ref": "SAMLProvider"},
      "Export": {
        "Name": {"Fn::Sub": "${AWS::StackName}-ProviderARN"}
      }
    },
    "ProviderName": {
      "Description": "Name of the SAML Identity Provider",
      "Value": {"Fn::If": ["HasCustomName", {"Ref": "IdentityProviderName"}, {"Fn::Sub": "${AWS::StackName}-saml-provider"}]},
      "Export": {
        "Name": {"Fn::Sub": "${AWS::StackName}-ProviderName"}
      }
    }
  }
}
```

------
#### [ YAML ]

```
AWSTemplateFormatVersion: '2010-09-09'
Description: '[AWSDocs] IAM: tutorial_saml-idp'

Parameters:
  IdentityProviderName:
    Type: String
    Description: Name of the SAML Identity Provider (leave empty for auto-generated name like '{StackName}-{UniqueId}')
    Default: ""
    AllowedPattern: '^$|^[a-zA-Z0-9._-]+$'
    ConstraintDescription: 'Must be empty or contain only alphanumeric characters, periods, underscores, and hyphens'

  IdentityProviderSAMLMetadataDocument:
    Type: String
    Description: SAML metadata document from identity provider

  IdentityProviderAddPrivateKey:
    Type: String
    Description: Optional private key for decrypting SAML assertions. The private key must be a .pem file that uses AES-GCM or AES-CBC encryption algorithm to decrypt SAML assertions.
    Default: ""

  IdentityProviderAssertionEncryptionMode:
    Type: String
    Description: Optional, sets encryption mode for SAML assertions
    Default: ""
    AllowedValues:
      - ""
      - "Allowed"
      - "Required"

Conditions:
  HasPrivateKey: !Not [!Equals [!Ref IdentityProviderAddPrivateKey, ""]]
  HasEncryptionMode: !Not [!Equals [!Ref IdentityProviderAssertionEncryptionMode, ""]]
  HasCustomName: !Not [!Equals [!Ref IdentityProviderName, ""]]

Resources:
  SAMLProvider:
    Type: 'AWS::IAM::SAMLProvider'
    Properties:
      Name: !If
        - HasCustomName
        - !Ref IdentityProviderName
        - !Ref AWS::NoValue
      SamlMetadataDocument: !Ref IdentityProviderSAMLMetadataDocument
      Tags:
        - Key: Name
          Value: !If
            - HasCustomName
            - !Ref IdentityProviderName
            - !Sub '${AWS::StackName}-saml-provider'
      AddPrivateKey: !If
        - HasPrivateKey
        - !Ref IdentityProviderAddPrivateKey
        - !Ref AWS::NoValue
      AssertionEncryptionMode: !If
        - HasEncryptionMode
        - !Ref IdentityProviderAssertionEncryptionMode
        - !Ref AWS::NoValue

Outputs:
  ProviderARN:
    Description: 'ARN of the created SAML Identity Provider'
    Value: !Ref SAMLProvider
    Export:
      Name: !Sub '${AWS::StackName}-ProviderARN'
  
  ProviderName:
    Description: 'Name of the SAML Identity Provider'
    Value: !If
      - HasCustomName
      - !Ref IdentityProviderName
      - !Sub '${AWS::StackName}-saml-provider'
    Export:
      Name: !Sub '${AWS::StackName}-ProviderName'
```

------

# IAM 教程：使用 CloudFormation 模板创建 SAML 联合 IAM 角色
<a name="tutorial_saml-federated-role"></a>

当 AWS 账户中配置了现有 SAML 身份提供者 (IdP) 时，可创建信任该 IdP 的联合 IAM 角色。本教程展示如何使用 CloudFormation 模板，创建通过外部 IdP 进行身份验证的用户可代入的 SAML 联合 IAM 角色。

该模板使用允许 SAML IdP 代入该角色的信任策略创建联合 IAM 角色。经外部 IdP 进行身份验证的用户可以代入此角色，根据附加至该角色的权限访问 AWS 资源。

所部署的资源包括以下部分：
+ 信任现有 SAML IdP 的联合 IAM 角色。
+ 可配置的托管策略，可以附加到该角色以授予特定权限。
+ 可选的权限边界和会话持续时间设置。

## 先决条件
<a name="tutorial_saml-federated-role-prereqs"></a>

本教程假定您已准备好以下各项：
+ AWS 账户中配置的现有 SAML IdP。如果还没有，可以使用 [IAM 教程：使用 CloudFormation 模板创建 SAML 身份提供者 (IdP)](tutorial_saml-idp.md) 教程创建一个。
+ SAML IdP 的 ARN，需要在创建堆栈时将其指定为参数。
+ 本地计算机上安装了 Python 3.6 或更高版本，可运行本教程中用于对 IdP 的 SAML 元数据 XML 文件进行格式化的 Python 命令。

## 使用 CloudFormation 创建 SAML 联合角色
<a name="tutorial_saml-federated-role-create"></a>

要创建 SAML 联合角色，您需要创建 CloudFormation 模板，并使用此模板创建包含该角色的堆栈。

### 创建模板
<a name="tutorial_saml-federated-role-file"></a>

首先，创建 CloudFormation 模板。

1. 在 [模板](#tutorial_saml-federated-role-template) 部分中，单击 **JSON** 或 **YAML** 选项卡上的复制图标，以复制模板内容。

1. 将模板内容粘贴到新文件中。

1. 将该文件保存在本地。

### 创建堆栈
<a name="tutorial_saml-federated-role-stack"></a>

接下来，使用已保存的模板来预置 CloudFormation 堆栈。

1. 通过以下网址打开 CloudFormation 控制台：[https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/)。

1. 在**堆栈**页面，从**创建堆栈**菜单中选择**（采用新资源（标准））**。

1. 指定模板：

   1. 在**先决条件**下，选择**选择现有模板**。

   1. 在**指定模板**下，选择**上传模板文件**。

   1. 选择**选择文件**，导航到模板文件并将其选中。

   1. 选择**下一步**。

1. 指定以下堆栈详细信息：

   1. 输入堆栈名称。

   1. 对于 **SAMLProviderARN**，请输入现有 SAML IdP 的 ARN。其格式应为 `arn:aws:iam::123456789012:saml-provider/YourProviderName`。

      示例：`arn:aws:iam::123456789012:saml-provider/CompanyIdP`
**注意**  
如果使用 [IAM 教程：使用 CloudFormation 模板创建 SAML 身份提供者 (IdP)](tutorial_saml-idp.md) 教程创建了 SAML IdP，则可以在该 CloudFormation 堆栈的“输出”选项卡中找到提供者 ARN。

   1. 对于 **RoleName**，可将其留空以根据堆栈名称自动生成名称，也可以为 IAM 角色输入自定义名称。

      示例：`SAML-Developer-Access` 或 `SAML-ReadOnly-Role`

   1. 对于其他参数，请接受默认值或根据需要输入自己的值：
      + **RoleSessionDuration** - 最大会话持续时间，以秒为单位（3600-43200，默认为 7200）

        示例：`14400`（4 小时）
      + **RolePermissionsBoundary** - 权限边界策略的可选 ARN

        示例：`arn:aws:iam::123456789012:policy/DeveloperBoundary`
      + **RolePath** - IAM 角色的路径（默认为 /）

        示例：`/saml-roles/`
      + **ManagedPolicy1-5** - 最多 5 个待附加托管策略的可选 ARN

        ManagedPolicy1 示例：`arn:aws:iam::aws:policy/ReadOnlyAccess`

        ManagedPolicy2 示例：`arn:aws:iam::123456789012:policy/CustomPolicy`

   1. 选择**下一步**。

1. 配置堆栈选项：

   1. 在**堆栈故障选项**下，选择**删除所有新创建的资源**。
**注意**  
如果选择此选项，即使堆栈创建失败，您可能也不会因为删除策略规定保留资源而向资源付费。

   1. 接受其他所有默认值。

   1. 在**功能**下勾选复选框，确认 CloudFormation 可能在您的账户中创建 IAM 资源。

   1. 选择**下一步**。

1. 查看堆栈详细信息并选择**提交**。

CloudFormation 将创建堆栈。一旦堆栈创建完成之后，堆栈资源就即可投入使用。可使用堆栈详细信息页面上的**资源**选项卡来查看账户中预置的资源。

堆栈将输出以下值，可参见**输出**选项卡：
+ **RoleARN**：已创建的 IAM 角色的 ARN（例如，`arn:aws:iam::123456789012:role/SAML-Developer-Access` 或 `arn:aws:iam::123456789012:role/stack-name-a1b2c3d4`，如果使用自动生成的名称）。

在配置 IdP 以发送相应 SAML 属性进行角色代入时，需要此角色 ARN。

## 测试 SAML 联合角色
<a name="tutorial_saml-federated-role-using"></a>

一旦创建 SAML 联合角色后，可验证其配置并测试联合身份验证设置。

1. 通过以下网址打开 IAM 控制台：[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)。

1. 在导航窗格中，选择**角色**。

1. 找到并选择新创建的联合角色。

   如果提供了自定义角色名称，请查找该名称。如果将 RoleName 参数留空，则该角色将拥有一个基于堆栈名称和唯一标识符的自动生成名称。

1. 选择**信任关系**选项卡，查看信任策略。

   信任策略应表明在 SAML 受众 (`SAML:aud`) 匹配 `https://signin.aws.amazon.com/saml` 的条件下，信任您的 SAML IdP 代入此角色。

1. 选择**权限**选项卡，查看附加的策略。

   您可以看到在创建过程中附加至该角色的任何托管策略。

1. 记下角色摘要页面上显示的**角色 ARN**。

   您需要此 ARN 来配置外部 IdP，以允许用户代入此角色。

您的 SAML 联合角色已准备好投入使用。将外部 IdP 配置为在 SAML 断言中包含此角色的 ARN，经过身份验证的用户将能够代入此角色来访问 AWS 资源。

## 清理：删除资源
<a name="tutorial_saml-federated-role-delete"></a>

最后一步，您将删除该堆栈及其包含的资源。

1. 打开 CloudFormation 控制台。

1. 在**堆栈**页面上，选择根据该模板创建的堆栈，选择**删除**，然后确认**删除**。

   CloudFormation 启动删除堆栈及其包含的所有资源。

## CloudFormation 模板详细信息
<a name="tutorial_saml-federated-role-template-details"></a>

### 资源
<a name="tutorial_saml-federated-role-template-resources"></a>

本教程的 CloudFormation 模板将在您的账户中创建以下资源：
+ [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html)：一个可以由通过 SAML IdP 进行身份验证的用户代入的联合 IAM 角色。

### 配置
<a name="tutorial_saml-federated-role-configuration"></a>

模板包含如下可配置参数：
+ **RoleName** - IAM 角色的名称（自动生成的名称请留空）
+ **SAMLProviderARN** - SAML IdP 的 ARN（必需）
+ **RoleSessionDuration** - 最大会话持续时间，以秒为单位（3600-43200，默认为 7200）
+ **RolePermissionsBoundary** - 权限边界策略的可选 ARN
+ **RolePath** - IAM 角色的路径（默认为 /）
+ **ManagedPolicy1-5** - 最多 5 个待附加托管策略的可选 ARN

## CloudFormation 模板
<a name="tutorial_saml-federated-role-template"></a>

将以下 JSON 或 YAML 代码另存为单独文件，以用作本教程的 CloudFormation 模板。

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

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "[AWSDocs] IAM: tutorial_saml-federated-role",
  "Parameters": {
    "RoleName": {
      "Type": "String",
      "Description": "Name of the IAM Role (leave empty for auto-generated name like '{StackName}-{UniqueId}')",
      "Default": "",
      "AllowedPattern": "^$|^[\\w+=,.@-]{1,64}$",
      "ConstraintDescription": "Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-"
    },
    "SAMLProviderARN": {
      "Type": "String",
      "Description": "ARN of the SAML Identity Provider",
      "AllowedPattern": "^arn:aws:iam::\\d{12}:saml-provider/[a-zA-Z0-9._-]+$",
      "ConstraintDescription": "Must be a valid SAML provider ARN"
    },
    "RoleSessionDuration": {
      "Type": "Number",
      "Description": "The maximum session duration (in seconds) that you want to set for the specified role (3600-43200)",
      "MinValue": 3600,
      "MaxValue": 43200,
      "Default": 7200
    },
    "RolePermissionsBoundary": {
      "Type": "String",
      "Description": "Optional ARN of the permissions boundary policy (leave empty for none)",
      "Default": ""
    },
    "RolePath": {
      "Type": "String",
      "Description": "Path for the IAM role (must start and end with /)",
      "Default": "/",
      "AllowedPattern": "^\/.*\/$|^\/$",
      "ConstraintDescription": "Role path must start and end with forward slash (/)"
    },
    "RoleManagedPolicy1": {
      "Type": "String",
      "Description": "Optional managed policy ARN 1",
      "Default": ""
    },
    "RoleManagedPolicy2": {
      "Type": "String",
      "Description": "Optional managed policy ARN 2",
      "Default": ""
    },
    "RoleManagedPolicy3": {
      "Type": "String",
      "Description": "Optional managed policy ARN 3",
      "Default": ""
    },
    "RoleManagedPolicy4": {
      "Type": "String",
      "Description": "Optional managed policy ARN 4",
      "Default": ""
    },
    "RoleManagedPolicy5": {
      "Type": "String",
      "Description": "Optional managed policy ARN 5",
      "Default": ""
    }
  },
  "Conditions": {
    "HasCustomRoleName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleName"}, ""]}]},
    "HasPermissionsBoundary": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RolePermissionsBoundary"}, ""]}]},
    "HasPolicy1": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy1"}, ""]}]},
    "HasPolicy2": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy2"}, ""]}]},
    "HasPolicy3": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy3"}, ""]}]},
    "HasPolicy4": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy4"}, ""]}]},
    "HasPolicy5": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy5"}, ""]}]}
  },
  "Resources": {
    "SAMLFederatedRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {"Fn::If": ["HasCustomRoleName", {"Ref": "RoleName"}, {"Ref": "AWS::NoValue"}]},
        "Description": "IAM role with SAML provider trust",
        "MaxSessionDuration": {"Ref": "RoleSessionDuration"},
        "PermissionsBoundary": {"Fn::If": ["HasPermissionsBoundary", {"Ref": "RolePermissionsBoundary"}, {"Ref": "AWS::NoValue"}]},
        "Path": {"Ref": "RolePath"},
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",		 	 	 
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Federated": {"Ref": "SAMLProviderARN"}
              },
              "Action": "sts:AssumeRoleWithSAML",
              "Condition": {
                "StringEquals": {
                  "SAML:aud": "https://signin.aws.amazon.com/saml"
                }
              }
            }
          ]
        },
        "ManagedPolicyArns": {
          "Fn::Split": [
            ",",
            {
              "Fn::Join": [
                ",",
                [
                  {"Fn::If": ["HasPolicy1", {"Ref": "RoleManagedPolicy1"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy2", {"Ref": "RoleManagedPolicy2"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy3", {"Ref": "RoleManagedPolicy3"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy4", {"Ref": "RoleManagedPolicy4"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy5", {"Ref": "RoleManagedPolicy5"}, {"Ref": "AWS::NoValue"}]}
                ]
              ]
            }
          ]
        }
      }
    }
  },
  "Outputs": {
    "RoleARN": {
      "Description": "ARN of the created IAM Role",
      "Value": {"Fn::GetAtt": ["SAMLFederatedRole", "Arn"]},
      "Export": {
        "Name": {"Fn::Sub": "${AWS::StackName}-RoleARN"}
      }
    }
  }
}
```

------
#### [ YAML ]

```
AWSTemplateFormatVersion: '2010-09-09'
Description: '[AWSDocs] IAM: tutorial_saml-federated-role'

Parameters:
  RoleName:
    Type: String
    Description: 'Name of the IAM Role (leave empty for auto-generated name like ''{StackName}-{UniqueId}'')'
    Default: ""
    AllowedPattern: '^$|^[\w+=,.@-]{1,64}$'
    ConstraintDescription: 'Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-'
  
  SAMLProviderARN:
    Type: String
    Description: 'ARN of the SAML Identity Provider'
    AllowedPattern: '^arn:aws:iam::\d{12}:saml-provider/[a-zA-Z0-9._-]+$'
    ConstraintDescription: 'Must be a valid SAML provider ARN'
  
  RoleSessionDuration:
    Type: Number
    Description: 'The maximum session duration (in seconds) that you want to set for the specified role (3600-43200)'
    MinValue: 3600
    MaxValue: 43200
    Default: 7200
    
  RolePermissionsBoundary:
    Type: String
    Description: Optional ARN of the permissions boundary policy (leave empty for none)
    Default: ""

  RolePath:
    Type: String
    Description: 'Path for the IAM role (must start and end with /)'
    Default: "/"
    AllowedPattern: '^\/.*\/$|^\/$'
    ConstraintDescription: 'Role path must start and end with forward slash (/)'
  
  RoleManagedPolicy1:
    Type: String
    Description: Optional managed policy ARN 1
    Default: ""
  RoleManagedPolicy2:
    Type: String
    Description: Optional managed policy ARN 2
    Default: ""
  RoleManagedPolicy3:
    Type: String
    Description: Optional managed policy ARN 3
    Default: ""
  RoleManagedPolicy4:
    Type: String
    Description: Optional managed policy ARN 4
    Default: ""
  RoleManagedPolicy5:
    Type: String
    Description: Optional managed policy ARN 5
    Default: ""

Conditions:
  HasCustomRoleName: !Not [!Equals [!Ref RoleName, ""]]
  HasPermissionsBoundary: !Not [!Equals [!Ref RolePermissionsBoundary, ""]]
  HasPolicy1: !Not [!Equals [!Ref RoleManagedPolicy1, ""]]
  HasPolicy2: !Not [!Equals [!Ref RoleManagedPolicy2, ""]]
  HasPolicy3: !Not [!Equals [!Ref RoleManagedPolicy3, ""]]
  HasPolicy4: !Not [!Equals [!Ref RoleManagedPolicy4, ""]]
  HasPolicy5: !Not [!Equals [!Ref RoleManagedPolicy5, ""]]

Resources:
  SAMLFederatedRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: !If
        - HasCustomRoleName
        - !Ref RoleName
        - !Ref AWS::NoValue
      Description: 'IAM role with SAML provider trust'
      MaxSessionDuration: !Ref RoleSessionDuration
      PermissionsBoundary: !If
        - HasPermissionsBoundary
        - !Ref RolePermissionsBoundary
        - !Ref AWS::NoValue
      Path: !Ref RolePath
      AssumeRolePolicyDocument:
        Version: '2012-10-17		 	 	 '
        Statement:
          - Effect: Allow
            Principal:
              Federated: !Ref SAMLProviderARN
            Action: 'sts:AssumeRoleWithSAML'
            Condition:
              StringEquals:
                'SAML:aud': 'https://signin.aws.amazon.com/saml'
      ManagedPolicyArns:
        !Split
          - ','
          - !Join
            - ','
            - - !If [HasPolicy1, !Ref RoleManagedPolicy1, !Ref 'AWS::NoValue']
              - !If [HasPolicy2, !Ref RoleManagedPolicy2, !Ref 'AWS::NoValue']
              - !If [HasPolicy3, !Ref RoleManagedPolicy3, !Ref 'AWS::NoValue']
              - !If [HasPolicy4, !Ref RoleManagedPolicy4, !Ref 'AWS::NoValue']
              - !If [HasPolicy5, !Ref RoleManagedPolicy5, !Ref 'AWS::NoValue']

Outputs:
  RoleARN:
    Description: 'ARN of the created IAM Role'
    Value: !GetAtt SAMLFederatedRole.Arn
    Export:
      Name: !Sub '${AWS::StackName}-RoleARN'
```

------

# IAM 教程：使用 CloudFormation 模板创建 SAML 身份提供者 (IdP) 和 SAML 联合 IAM 角色
<a name="tutorial_saml-idp-and-federated-role"></a>

要熟悉 SAML 联合身份验证及其功能，则需使用 CloudFormation 模板设置 SAML 身份提供者 (IdP) 和相关的联合 IAM 角色。本教程介绍如何在单个堆栈中同时创建两种资源。

该模板创建一个可用于联合访问 AWS 资源的 SAML IdP，以及一个信任 SAML 提供者的 IAM 角色。经外部 IdP 进行身份验证的用户可代入此角色访问 AWS 资源。

所部署的资源包括以下部分：
+ 使用 IdP 的元数据文档配置的 SAML IdP。
+ 信任 SAML IdP 的联合 IAM 角色，可由经过身份验证的用户代入此角色。
+ 可配置的托管策略，可以附加到该角色以授予特定权限。

## 先决条件
<a name="tutorial_saml-idp-and-federated-role-prereqs"></a>

本教程假定您已准备好以下各项：
+ 本地计算机上安装了 Python 3.6 或更高版本，可运行本教程中用于对 IdP 的 SAML 元数据 XML 文件进行格式化的 Python 命令。
+ 来自外部 IdP 的 SAML 元数据文档，另存为 XML 文件。

## 使用 CloudFormation 创建 SAML IdP 和角色
<a name="tutorial_saml-idp-and-federated-role-create"></a>

要创建 SAML IdP 和联合角色，您需要创建 CloudFormation 模板，并使用此模板创建包含这两种资源的堆栈。

### 创建模板
<a name="tutorial_saml-idp-and-federated-role-file"></a>

首先，创建 CloudFormation 模板。

1. 在 [模板](#tutorial_saml-idp-and-federated-role-template) 部分中，单击 **JSON** 或 **YAML** 选项卡上的复制图标，以复制模板内容。

1. 将模板内容粘贴到新文件中。

1. 将该文件保存在本地。

### 创建堆栈
<a name="tutorial_saml-idp-and-federated-role-stack"></a>

接下来，使用已保存的模板来预置 CloudFormation 堆栈。

1. 通过以下网址打开 CloudFormation 控制台：[https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/)。

1. 在**堆栈**页面，从**创建堆栈**菜单中选择**（采用新资源（标准））**。

1. 指定模板：

   1. 在**先决条件**下，选择**选择现有模板**。

   1. 在**指定模板**下，选择**上传模板文件**。

   1. 选择**选择文件**，导航到模板文件并将其选中。

   1. 选择**下一步**。

1. 指定以下堆栈详细信息：

   1. 输入堆栈名称。

   1. 对于 **IdentityProviderName**，可将其留空以根据堆栈名称自动生成名称，也可以为 SAML IdP 输入自定义名称。

      示例：`CompanyIdP` 或 `EnterpriseSSO`

   1. 对于 **IdentityProvidersamlMetadataDocument**，在将 SAML 元数据 XML 文件粘贴到此字段之前，需要将其格式化为单行。这是必要的，因为 CloudFormation 控制台要求 XML 内容在通过控制台参数传递时需格式化为单行。

      使用以下 Python 命令重新格式化 XML 文件：

      ```
      python3 -c "import sys, re; content=open(sys.argv[1]).read(); print(re.sub(r'>\s+<', '><', content.replace('\n', '').replace('\r', '').strip()))" saml-metadata.xml
      ```
**注意**  
IdP 的 SAML 元数据文档必须格式化为单行才能输入控制台参数。Python 命令删除了换行符和多余空格以创建所需的格式，同时保留所有原始内容和结构。

      复制 Python 命令的输出并将其粘贴到 **IdentityProviderSAMLMetadataDocument** 字段中。

      格式化的 SAML 元数据文档示例（缩减版）：

      ```
      <?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://portal.sso.example.com/saml/assertion/CompanyIdP"><md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDXTCCAkWgAwIBAgIJAJC1HiIAZAiIMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV...</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://portal.sso.example.com/saml/logout/CompanyIdP"/><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://portal.sso.example.com/saml/assertion/CompanyIdP"/></md:IDPSSODescriptor></md:EntityDescriptor>
      ```

   1. 对于 **RoleName**，可将其留空以根据堆栈名称自动生成名称，也可以为联合 IAM 角色输入自定义名称。

      示例：`SAML-Developer-Access` 或 `SAML-ReadOnly-Role`

   1. 对于其他参数，请接受默认值或根据需要输入自己的值：
      + **IdentityProviderAddPrivateKey** - 解密 SAML 断言的可选私钥
      + **IdentityProviderAssertionEncryptionMode** - SAML 断言加密模式

        示例值：`Allowed`，`Required`，或者留空表示不加密
      + **RoleSessionDuration** - 最大会话持续时间，以秒为单位（3600-43200，默认为 7200）

        示例：`14400`（4 小时）
      + **RolePermissionsBoundary** - 权限边界策略的可选 ARN

        示例：`arn:aws:iam::123456789012:policy/DeveloperBoundary`
      + **RolePath** - IAM 角色的路径（默认为 /）

        示例：`/saml-roles/`
      + **RoleManagedPolicy1-5** - 最多 5 个待附加托管策略的可选 ARN

        RoleManagedPolicy1 示例：`arn:aws:iam::aws:policy/ReadOnlyAccess`

        RoleManagedPolicy2 示例：`arn:aws:iam::123456789012:policy/CustomPolicy`

   1. 选择**下一步**。

1. 配置堆栈选项：

   1. 在**堆栈故障选项**下，选择**删除所有新创建的资源**。
**注意**  
如果选择此选项，即使堆栈创建失败，您可能也不会因为删除策略规定保留资源而向资源付费。

   1. 接受其他所有默认值。

   1. 在**功能**下勾选复选框，确认 CloudFormation 可能在您的账户中创建 IAM 资源。

   1. 选择**下一步**。

1. 查看堆栈详细信息并选择**提交**。

CloudFormation 将创建堆栈。一旦堆栈创建完成之后，堆栈资源就即可投入使用。可使用堆栈详细信息页面上的**资源**选项卡来查看账户中预置的资源。

堆栈将输出以下值，可参见**输出**选项卡：
+ **RoleARN**：已创建的 IAM 角色的 ARN（例如，`arn:aws:iam::123456789012:role/SAML-Developer-Access` 或 `arn:aws:iam::123456789012:role/stack-name-a1b2c3d4`，如果使用自动生成的名称）。
+ **IdentityProviderARN**：已创建的 SAML IdP 的 ARN（例如，`arn:aws:iam::123456789012:saml-provider/CompanyIdP`）。

在配置 IdP 以发送相应 SAML 属性进行角色代入时，需要这两个 ARN。

## 测试 SAML 联合身份验证
<a name="tutorial_saml-idp-and-federated-role-using"></a>

一旦创建 SAML IdP 和联合角色后，可测试联合身份验证设置。

1. 通过 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

1. 在导航窗格中，选择 **Identity providers**（身份提供程序）。

   您应该能在列表中看到新创建的 SAML IdP。

1. 选择 IdP 名称以查看其详细信息。

   在 IdP 详细信息页面上，可以看到 SAML 元数据文档和其他配置详细信息。

1. 在导航窗格中，选择**角色**。

1. 找到并选择新创建的联合角色。

   在角色详细信息页面上，可以看到允许 SAML IdP 代入此角色的信任策略。

1. 选择**信任关系**选项卡，查看信任策略。

   信任策略应表明在 SAML 受众 (`SAML:aud`) 匹配 `https://signin.aws.amazon.com/saml` 的条件下，信任该 SAML IdP 代入此角色。

## 清理：删除资源
<a name="tutorial_saml-idp-and-federated-role-delete"></a>

最后一步，您将删除该堆栈及其包含的资源。

1. 打开 CloudFormation 控制台。

1. 在**堆栈**页面上，选择根据该模板创建的堆栈，选择**删除**，然后确认**删除**。

   CloudFormation 启动删除堆栈及其包含的所有资源。

## CloudFormation 模板详细信息
<a name="tutorial_saml-idp-and-federated-role-template-details"></a>

### 资源
<a name="tutorial_saml-idp-and-federated-role-template-resources"></a>

本教程的 CloudFormation 模板将在您的账户中创建以下资源：
+ [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-samlprovider.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-samlprovider.html)：一个在 AWS 和外部 IdP 之间建立信任的 SAML IdP。
+ [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html)：一个可以由通过 SAML IdP 进行身份验证的用户代入的联合 IAM 角色。

### 配置
<a name="tutorial_saml-idp-and-federated-role-configuration"></a>

模板包含如下可配置参数：
+ **IdentityProviderName** - SAML IdP 的名称（自动生成的名称请留空）
+ **IdentityProviderSAMLMetadataDocument** - 来自 IdP 的 SAML 元数据文档（必需）
+ **IdentityProviderAddPrivateKey** - 解密 SAML 断言的可选私钥
+ **IdentityProviderAssertionEncryptionMode** - SAML 断言加密模式
+ **RoleName** - IAM 角色的名称（自动生成的名称请留空）
+ **RolePath** - IAM 角色的路径（默认为 /）
+ **RolePermissionsBoundary** - 权限边界策略的可选 ARN
+ **RoleSessionDuration** - 最大会话持续时间，以秒为单位（3600-43200，默认为 7200）
+ **RoleManagedPolicy1-5** - 最多 5 个待附加托管策略的可选 ARN

## CloudFormation 模板
<a name="tutorial_saml-idp-and-federated-role-template"></a>

将以下 JSON 或 YAML 代码另存为单独文件，以用作本教程的 CloudFormation 模板。

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

```
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "[AWSDocs] IAM: tutorial_saml-idp-and-federated-role",
  "Parameters": {
    "IdentityProviderName": {
      "Type": "String",
      "Description": "Name of the SAML Identity Provider (leave empty for auto-generated name like '{StackName}-{UniqueId}')",
      "Default": "",
      "AllowedPattern": "^$|^[a-zA-Z0-9._-]+$",
      "ConstraintDescription": "Must be empty or contain only alphanumeric characters, periods, underscores, and hyphens"
    },
    "IdentityProviderSAMLMetadataDocument": {
      "Type": "String",
      "Description": "SAML metadata document from identity provider"
    },
    "IdentityProviderAddPrivateKey": {
      "Type": "String",
      "Description": "Optional private key for decrypting SAML assertions. The private key must be a .pem file that uses AES-GCM or AES-CBC encryption algorithm to decrypt SAML assertions.",
      "Default": ""
    },
    "IdentityProviderAssertionEncryptionMode": {
      "Type": "String",
      "Description": "Optional, sets encryption mode for SAML assertions",
      "Default": "",
      "AllowedValues": ["", "Allowed", "Required"]
    },
    "RoleName": {
      "Type": "String",
      "Description": "Name of the IAM Role (leave empty for auto-generated name like '{StackName}-{UniqueId}')",
      "Default": "",
      "AllowedPattern": "^$|^[\\w+=,.@-]{1,64}$",
      "ConstraintDescription": "Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-"
    },
    "RolePath": {
      "Type": "String",
      "Description": "Path for the IAM Role",
      "AllowedPattern": "(^\\/$)|(^\\/.*\\/$)",
      "Default": "/"
    },
    "RolePermissionsBoundary": {
      "Type": "String",
      "Description": "Optional ARN of the permissions boundary policy (leave empty for none)",
      "Default": ""
    },
    "RoleSessionDuration": {
      "Description": "The maximum session duration (in seconds) that you want to set for the specified role (3600-43200)",
      "Type": "Number",
      "MinValue": 3600,
      "MaxValue": 43200,
      "Default": 7200
    },
    "RoleManagedPolicy1": {
      "Type": "String",
      "Description": "Optional managed policy ARN 1",
      "Default": ""
    },
    "RoleManagedPolicy2": {
      "Type": "String",
      "Description": "Optional managed policy ARN 2",
      "Default": ""
    },
    "RoleManagedPolicy3": {
      "Type": "String",
      "Description": "Optional managed policy ARN 3",
      "Default": ""
    },
    "RoleManagedPolicy4": {
      "Type": "String",
      "Description": "Optional managed policy ARN 4",
      "Default": ""
    },
    "RoleManagedPolicy5": {
      "Type": "String",
      "Description": "Optional managed policy ARN 5",
      "Default": ""
    }
  },
  "Conditions": {
    "HasCustomProviderName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderName"}, ""]}]},
    "HasCustomRoleName": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleName"}, ""]}]},
    "HasPermissionsBoundary": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RolePermissionsBoundary"}, ""]}]},
    "HasPolicy1": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy1"}, ""]}]},
    "HasPolicy2": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy2"}, ""]}]},
    "HasPolicy3": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy3"}, ""]}]},
    "HasPolicy4": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy4"}, ""]}]},
    "HasPolicy5": {"Fn::Not": [{"Fn::Equals": [{"Ref": "RoleManagedPolicy5"}, ""]}]},
    "HasPrivateKey": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAddPrivateKey"}, ""]}]},
    "HasAssertionEncryptionMode": {"Fn::Not": [{"Fn::Equals": [{"Ref": "IdentityProviderAssertionEncryptionMode"}, ""]}]}
  },
  "Resources": {
    "SAMLProvider": {
      "Type": "AWS::IAM::SAMLProvider",
      "Properties": {
        "Name": {"Fn::If": ["HasCustomProviderName", {"Ref": "IdentityProviderName"}, {"Ref": "AWS::NoValue"}]},
        "SamlMetadataDocument": {"Ref": "IdentityProviderSAMLMetadataDocument"},
        "AddPrivateKey": {"Fn::If": ["HasPrivateKey", {"Ref": "IdentityProviderAddPrivateKey"}, {"Ref": "AWS::NoValue"}]},
        "AssertionEncryptionMode": {"Fn::If": ["HasAssertionEncryptionMode", {"Ref": "IdentityProviderAssertionEncryptionMode"}, {"Ref": "AWS::NoValue"}]}
      }
    },
    "SAMLFederatedRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {"Fn::If": ["HasCustomRoleName", {"Ref": "RoleName"}, {"Ref": "AWS::NoValue"}]},
        "Path": {"Ref": "RolePath"},
        "Description": "SAML federated IAM role for SSO access with specified permissions",
        "MaxSessionDuration": {"Ref": "RoleSessionDuration"},
        "PermissionsBoundary": {"Fn::If": ["HasPermissionsBoundary", {"Ref": "RolePermissionsBoundary"}, {"Ref": "AWS::NoValue"}]},
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",		 	 	 
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Federated": {"Ref": "SAMLProvider"}
              },
              "Action": [
                "sts:AssumeRole",
                "sts:SetSourceIdentity",
                "sts:TagSession"
              ],
              "Condition": {
                "StringEquals": {
                  "SAML:aud": "https://signin.aws.amazon.com/saml"
                }
              }
            }
          ]
        },
        "ManagedPolicyArns": {
          "Fn::Split": [
            ",",
            {
              "Fn::Join": [
                ",",
                [
                  {"Fn::If": ["HasPolicy1", {"Ref": "RoleManagedPolicy1"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy2", {"Ref": "RoleManagedPolicy2"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy3", {"Ref": "RoleManagedPolicy3"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy4", {"Ref": "RoleManagedPolicy4"}, {"Ref": "AWS::NoValue"}]},
                  {"Fn::If": ["HasPolicy5", {"Ref": "RoleManagedPolicy5"}, {"Ref": "AWS::NoValue"}]}
                ]
              ]
            }
          ]
        }
      }
    }
  },
  "Outputs": {
    "RoleARN": {
      "Description": "ARN of the created IAM Role",
      "Value": {"Fn::GetAtt": ["SAMLFederatedRole", "Arn"]},
      "Export": {
        "Name": {"Fn::Sub": "${AWS::StackName}-RoleARN"}
      }
    },
    "IdentityProviderARN": {
      "Description": "ARN of the created SAML Identity Provider",
      "Value": {"Ref": "SAMLProvider"},
      "Export": {
        "Name": {"Fn::Sub": "${AWS::StackName}-IdentityProviderARN"}
      }
    }
  }
}
```

------
#### [ YAML ]

```
AWSTemplateFormatVersion: '2010-09-09'
Description: '[AWSDocs] IAM: tutorial_saml-idp-and-federated-role'

Parameters:
  IdentityProviderName:
    Type: String
    Description: Name of the SAML Identity Provider (leave empty for auto-generated name like '{StackName}-{UniqueId}')
    Default: ""
    AllowedPattern: '^$|^[a-zA-Z0-9._-]+$'
    ConstraintDescription: Must be empty or contain only alphanumeric characters, periods, underscores, and hyphens

  IdentityProviderSAMLMetadataDocument:
    Type: String
    Description: SAML metadata document from identity provider

  IdentityProviderAddPrivateKey:
    Type: String
    Description: Optional private key for decrypting SAML assertions. The private key must be a .pem file that uses AES-GCM or AES-CBC encryption algorithm to decrypt SAML assertions.
    Default: ""

  IdentityProviderAssertionEncryptionMode:
    Type: String
    Description: Optional, sets encryption mode for SAML assertions
    Default: ""
    AllowedValues:
      - ""
      - "Allowed"
      - "Required"

  RoleName:
    Type: String
    Description: Name of the IAM Role (leave empty for auto-generated name like '{StackName}-{UniqueId}')
    Default: ""
    AllowedPattern: '^$|^[\w+=,.@-]{1,64}$'
    ConstraintDescription: "Must be empty or 1-64 characters and can contain alphanumeric characters and +=,.@-"

  RolePath:
    Type: String
    Description: Path for the IAM Role
    AllowedPattern: (^\/$)|(^\/.*\/$)
    Default: "/"

  RolePermissionsBoundary:
    Type: String
    Description: Optional ARN of the permissions boundary policy (leave empty for none)
    Default: ""
    
  RoleSessionDuration:
    Description: The maximum session duration (in seconds) that you want to set for the specified role (3600-43200)
    Type: Number
    MinValue: 3600
    MaxValue: 43200
    Default: 7200

  RoleManagedPolicy1:
    Type: String
    Description: Optional managed policy ARN 1
    Default: ""
  RoleManagedPolicy2:
    Type: String
    Description: Optional managed policy ARN 2
    Default: ""
  RoleManagedPolicy3:
    Type: String
    Description: Optional managed policy ARN 3
    Default: ""
  RoleManagedPolicy4:
    Type: String
    Description: Optional managed policy ARN 4
    Default: ""
  RoleManagedPolicy5:
    Type: String
    Description: Optional managed policy ARN 5
    Default: ""

Conditions:
  HasCustomProviderName: !Not [!Equals [!Ref IdentityProviderName, ""]]
  HasCustomRoleName: !Not [!Equals [!Ref RoleName, ""]]
  HasPermissionsBoundary: !Not [!Equals [!Ref RolePermissionsBoundary, ""]]
  HasPolicy1: !Not [!Equals [!Ref RoleManagedPolicy1, ""]]
  HasPolicy2: !Not [!Equals [!Ref RoleManagedPolicy2, ""]]
  HasPolicy3: !Not [!Equals [!Ref RoleManagedPolicy3, ""]]
  HasPolicy4: !Not [!Equals [!Ref RoleManagedPolicy4, ""]]
  HasPolicy5: !Not [!Equals [!Ref RoleManagedPolicy5, ""]]
  HasPrivateKey: !Not [!Equals [!Ref IdentityProviderAddPrivateKey, ""]]
  HasAssertionEncryptionMode: !Not [!Equals [!Ref IdentityProviderAssertionEncryptionMode, ""]]

Resources:
  SAMLProvider:
    Type: AWS::IAM::SAMLProvider
    Properties:
      Name: !If
        - HasCustomProviderName
        - !Ref IdentityProviderName
        - !Ref AWS::NoValue
      SamlMetadataDocument: !Ref IdentityProviderSAMLMetadataDocument
      AddPrivateKey: !If
        - HasPrivateKey
        - !Ref IdentityProviderAddPrivateKey
        - !Ref AWS::NoValue
      AssertionEncryptionMode: !If
        - HasAssertionEncryptionMode
        - !Ref IdentityProviderAssertionEncryptionMode
        - !Ref AWS::NoValue

  SAMLFederatedRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !If
        - HasCustomRoleName
        - !Ref RoleName
        - !Ref AWS::NoValue
      Path: !Ref RolePath
      Description: "SAML federated IAM role for SSO access with specified permissions"
      MaxSessionDuration: !Ref RoleSessionDuration
      PermissionsBoundary: !If
        - HasPermissionsBoundary
        - !Ref RolePermissionsBoundary
        - !Ref AWS::NoValue
      AssumeRolePolicyDocument:
        Version: '2012-10-17		 	 	 '
        Statement:
          - Effect: Allow
            Principal:
              Federated: !Ref SAMLProvider
            Action:
              - 'sts:AssumeRole'
              - 'sts:SetSourceIdentity'
              - 'sts:TagSession'
            Condition:
              StringEquals:
                'SAML:aud': 'https://signin.aws.amazon.com/saml'
      ManagedPolicyArns: !Split
        - ','
        - !Join
          - ','
          - - !If [HasPolicy1, !Ref RoleManagedPolicy1, !Ref "AWS::NoValue"]
            - !If [HasPolicy2, !Ref RoleManagedPolicy2, !Ref "AWS::NoValue"]
            - !If [HasPolicy3, !Ref RoleManagedPolicy3, !Ref "AWS::NoValue"]
            - !If [HasPolicy4, !Ref RoleManagedPolicy4, !Ref "AWS::NoValue"]
            - !If [HasPolicy5, !Ref RoleManagedPolicy5, !Ref "AWS::NoValue"]

Outputs:
  RoleARN:
    Description: ARN of the created IAM Role
    Value: !GetAtt SAMLFederatedRole.Arn
    Export:
      Name: !Sub '${AWS::StackName}-RoleARN'

  IdentityProviderARN:
    Description: ARN of the created SAML Identity Provider
    Value: !Ref SAMLProvider
    Export:
      Name: !Sub '${AWS::StackName}-IdentityProviderARN'
```

------