

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

The following tutorials present complete end-to-end procedures for common tasks for AWS Identity and Access Management (IAM). They are intended for a lab-type environment, with fictitious company names, user names, and so on. Their purpose is to provide general guidance. They are not intended for direct use in a production environment without careful review and adaptation to meet the unique needs of your organization's environment.

**Topics**
+ [Delegate access across AWS accounts using roles](tutorial_cross-account-with-roles.md)
+ [Create a customer managed policy](tutorial_managed-policies.md)
+ [Use attribute-based access control (ABAC)](tutorial_attribute-based-access-control.md)
+ [Permit users to manage their credentials and MFA settings](tutorial_users-self-manage-mfa-and-creds.md)
+ [Create SAML IdP with CloudFormation](tutorial_saml-idp.md)
+ [Create SAML federated role with CloudFormation](tutorial_saml-federated-role.md)
+ [Create SAML IdP and federated role with CloudFormation](tutorial_saml-idp-and-federated-role.md)

# IAM tutorial: Delegate access across AWS accounts using IAM roles
<a name="tutorial_cross-account-with-roles"></a>

**Important**  
 IAM [best practices](best-practices.md) recommend that you require human users to use federation with an identity provider to access AWS using temporary credentials instead of using IAM users with long-term credentials. We recommend that you only use IAM users for [specific use cases](gs-identities-iam-users.md) not supported by federated users.

This tutorial teaches you how to use a role to delegate access to resources in different AWS accounts called **Destination** and **Originating**. You share resources in one account with users in a different account. By setting up cross-account access in this way, you don't have to create individual IAM users in each account. In addition, users don't have to sign out of one account and sign in to another account to access resources in different AWS accounts. After configuring the role, you see how to use the role from the AWS Management Console, the AWS CLI, and the API.

In this tutorial, the **Destination** account manages application data accessed by different applications and teams. In each account, you store application information in Amazon S3 buckets. You manage IAM users in the **Originating** account, where you have two IAM user roles: **Developers** and **Analysts**. Developers and Analysts use the **Originating** account to generate data shared by multiple microservices. Both roles have permissions to work in the Originating account and access resources there. From time to time, a developer must update the shared data in the **Destination** account. The developers store this data in an Amazon S3 bucket called `amzn-s3-demo-bucket-shared-container`. 

At the end of this tutorial, you have the following:
+ Users in the **Originating** account (the trusted account) allowed to assume a specific role in the **Destination** account.
+ A role in the **Destination** account (the trusting account) allowed to access a specific Amazon S3 bucket. 
+ The `amzn-s3-demo-bucket-shared-container` bucket in the **Destination** account.

Developers can use the role in the AWS Management Console to access the `amzn-s3-demo-bucket-shared-container` bucket in the **Destination** account. They can also access the bucket by using API calls authenticated by temporary credentials provided by the role. Similar attempts by an Analyst to use the role fail.

This workflow has three basic steps:

**[Create a role in the Destination Account](#tutorial_cross-account-with-roles-1)**  
First, you use the AWS Management Console to establish trust between the **Destination** account (ID number 999999999999) and the **Originating** account (ID number 111111111111). You start by creating an IAM role named *UpdateData*. When you create the role, you define the **Originating** account as a trusted entity and specify a permissions policy that allows trusted users to update the `amzn-s3-demo-bucket-shared-container` bucket.

**[Grant access to the role](#tutorial_cross-account-with-roles-2)**  
In this section, you modify the role policy to deny Analysts access to the `UpdateData` role. Because Analysts have PowerUser access in this scenario, and you must explicitly *deny* the ability to use the role.

**[Test access by switching roles](#tutorial_cross-account-with-roles-3)**  
Finally, as a Developer, you use the `UpdateData` role to update the `amzn-s3-demo-bucket-shared-container` bucket in the **Destination** account. You see how to access the role through the AWS console, the AWS CLI, and the API.

## Considerations
<a name="tutorial_cross-account-with-roles-considerations"></a>

Before you use IAM roles to delegate resource access across AWS accounts, it's important to consider the following:
+ You cannot switch to a role when you sign in as the AWS account root user.
+ IAM roles and resource-based policies delegate access across accounts only within a single partition. For example, assume that you have an account in US West (N. California) in the standard `aws` partition. You also have an account in China (Beijing) in the `aws-cn` partition. You can't use an Amazon S3 resource-based policy in your account in China (Beijing) to allow access for users in your standard `aws` account.
+ You can use AWS IAM Identity Center to facilitate single sign-on (SSO) for external AWS accounts (accounts outside your AWS Organizations) using Security Assertion Markup Language (SAML). For details, see [ Integrate external AWS accounts 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) 
+ You can associate roles to AWS resources like Amazon EC2 instances or AWS Lambda functions. For details, see [Create a role to delegate permissions to an AWS service](id_roles_create_for-service.md).
+ If you want to have an application assume a role in another AWS account, you can use the AWS SDK for cross account role assumption. For more information, see [Authentication and access](https://docs.aws.amazon.com//sdkref/latest/guide/access.html) in the *AWS SDKs and Tools Reference Guide*.
+ Switching roles using the AWS Management Console only works with accounts that do not require an `ExternalId`. For example, assume that you grant access to your account to a third party and require an `ExternalId` in a `Condition` element in your permissions policy. In that case, the third party can access your account only by using the AWS API or a command line tool. The third party cannot use the console because it must supply a value for `ExternalId`. For more information about this scenario, see [Access to AWS accounts owned by third parties](id_roles_common-scenarios_third-party.md), and [How to enable cross account access to the AWS Management Console](https://aws.amazon.com/blogs/security/how-to-enable-cross-account-access-to-the-aws-management-console) in the AWS Security Blog.

## Prerequisites
<a name="tutorial_cross-account-with-roles-prereqs"></a>

This tutorial assumes that you have the following already in place:
+ **Two** separate AWS accounts that you can use, one to represent the **Originating** account, and one to represent the **Destination** account.
+ Users and roles in the **Originating** account created and configured as follows:  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html)
+ You do not need to create any users in the **Destination** account.
+ An Amazon S3 bucket created in the **Destination** account. You can call it `amzn-s3-demo-bucket-shared-container` in this tutorial, but because S3 bucket names must be globally unique, you must use a bucket with a different name.

## Create a role in the Destination Account
<a name="tutorial_cross-account-with-roles-1"></a>

You can allow users from one AWS account to access resources in another AWS account. In this tutorial, we'll do this by creating a role that defines who can access it and what permissions it grants to users that switch to it.

In this step of the tutorial, you create the role in the **Destination** account and specify the **Originating** account as a trusted entity. You also limit the role permissions to only read and write access to the `amzn-s3-demo-bucket-shared-container` bucket. Anyone granted permission to use the role can read and write to the `shared-container` bucket.

Before you can create a role, you need the *account ID* of the **Originating** AWS account. Each AWS account has a unique account ID identifier assigned to it.

**To obtain the Originating AWS account ID**

1. Sign in to the AWS Management Console as an administrator of the **Originating** account, and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. In the IAM console, choose your user name on the navigation bar in the upper right. It typically looks like this: ***username*@*account\$1ID\$1number\$1or\$1alias***.

   For this scenario, you can use the account ID 111111111111 for the **Originating** account. However, you should use a valid account ID if you use this scenario in your test environment.

**To create a role in the Destination account that can be used by the Originating account**

1. Sign in to the AWS Management Console as an administrator of the **Destination** account, and open the IAM console.

1. Before creating the role, prepare the managed policy that defines the permissions for the role requirements. You attach this policy to the role in a later step. 

   You want to set read and write access to the `amzn-s3-demo-bucket-shared-container` bucket. Although AWS provides some Amazon S3 managed policies, there isn't one that provides read and write access to a single Amazon S3 bucket. You can create your own policy instead.

   In the navigation pane, choose **Policies** and then choose **Create policy**.

1. Choose the **JSON** tab and copy the text from the following JSON policy document. Paste this text into the **JSON** text box, replacing the resource ARN (`arn:aws:s3:::shared-container`) with the real one for your Amazon S3 bucket.

------
#### [ 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/*"
       }
     ]
   }
   ```

------

   The `ListAllMyBuckets` action grants permission to list all buckets owned by the authenticated sender of the request. The `ListBucket` permission allows users to view objects in the `amzn-s3-demo-bucket-shared-container` bucket. The `GetObject`, `PutObject`, `DeleteObject` permissions allows users to view, update, and delete contents in the `amzn-s3-demo-bucket-shared-container` bucket.
**Note**  
You can switch between the **Visual** and **JSON** editor options anytime. However, if you make changes or choose **Next** in the **Visual** editor, IAM might restructure your policy to optimize it for the visual editor. For more information, see [Policy restructuring](troubleshoot_policies.md#troubleshoot_viseditor-restructure).

1. On the **Review and create** page, type **read-write-app-bucket** for the policy name. Review the permissions granted by your policy, and then choose **Create policy** to save your work.

   The new policy appears in the list of managed policies.

1. In the navigation pane, choose **Roles** and then choose **Create role**.

1. Choose the **An AWS account** role type.

1. For **Account ID**, type the **Originating** account ID.

   This tutorial uses the example account ID **111111111111** for the **Originating** account. You should use a valid account ID. If you use an invalid account ID, such as **111111111111**, IAM does not let you create the new role.

   For now you do not need to require an external ID, or require users to have multi-factor authentication (MFA) in order to assume the role. Leave these options unselected. For more information, see [AWS Multi-factor authentication in IAM](id_credentials_mfa.md).

1. Choose **Next: Permissions** to set the permissions associated with the role.

1. Select the checkbox next to the policy that you created previously.
**Tip**  
For **Filter**, choose **Customer managed** to filter the list to include only the policies that you created. This hides the AWS created policies and makes it much easier to find the one you need.

   Then, choose **Next**. 

1. (Optional) Add metadata to the role by attaching tags as key-value pairs. For more information about using tags in IAM, see [Tags for AWS Identity and Access Management resources](id_tags.md).

1. (Optional) For **Description**, enter a description for the new role.

1. After reviewing the role, choose **Create role**.

    

   The `UpdateData` role appears in the list of roles.

Now you must obtain the Amazon Resource Name (ARN) of the role, a unique identifier for the role. When you modify the Developer's role in the Originating account, you specify the role ARN from the Destination account to grant or deny permissions.

**To obtain the ARN for UpdateData**

1. In the navigation pane of the IAM console, choose **Roles**.

1. In the list of roles, choose the `UpdateData` role.

1. In the **Summary** section of the details pane, copy the **Role ARN** value.

   The Destination account has an account ID of 999999999999, so the role ARN is `arn:aws:iam::999999999999:role/UpdateData`. Ensure that you provide the real AWS account ID for the Destination account.

At this point, you have established trust between the **Destination** and **Originating** accounts. You did this by creating a role in the **Destination** account that identifies the **Originating** account as a trusted principal. You also defined what the users who switch to the `UpdateData` role can do.

Next, modify the permissions for the Developer role.

## Grant access to the role
<a name="tutorial_cross-account-with-roles-2"></a>

At this point, both Analysts and Developers have permissions that allow them to manage data in the **Originating** account. Use the following required steps for adding permissions to allow switching to the role.

**To modify the Developers role to allow them to switch to the UpdateData role**

1. Sign in as an administrator in the **Originating** account, and open the IAM console.

1. Choose **Roles**, and then choose **Developers**.

1. Choose the **Permissions** tab, choose **Add permissions**, and then choose **Create inline policy**.

1. Choose the **JSON** tab.

1. Add the following policy statement to allow the `AssumeRole` action on the `UpdateData` role in the Destination account. Be sure that you change *DESTINATION-ACCOUNT-ID* in the `Resource` element to the actual AWS account ID of the Destination account.

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

****  

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

------

   The `Allow` effect explicitly allows the Developers group access to the `UpdateData` role in the Destination account. Any developer who tries to access the role succeeds.

1. Choose **Review policy**.

1. Type a **Name** such as **allow-assume-S3-role-in-destination**.

1. Choose **Create policy**.

In most environments, you may not need the following procedure. If, however, you use PowerUserAccess permissions, then some groups might already be able to switch roles. The following procedure shows how to add a `"Deny"` permission to the Analysts group to ensure that they cannot assume the role. If you do not need this procedure in your environment, then we recommend that you do not add it. `"Deny"` permissions make the overall permissions picture more complicated to manage and understand. Use `"Deny"` permissions only when you do not have a better option.

**To modify the Analysts role to deny permission to assume the `UpdateData` role**

1. Choose **Roles**, and then choose **Analysts**.

1. Choose the **Permissions** tab, choose **Add permissions**, and then choose **Create inline policy**.

1. Choose the **JSON** tab.

1. Add the following policy statement to deny the `AssumeRole` action on the `UpdateData` role. Be sure that you change *DESTINATION-ACCOUNT-ID* in the `Resource` element to the actual AWS account ID of the Destination account.

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

****  

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

------

   The `Deny` effect explicitly denies the Analysts group access to the `UpdateData` role in the Destination account. Any analyst who tries to access the role receives an access denied message.

1. Choose **Review policy**.

1. Type a **Name** like **deny-assume-S3-role-in-destination**.

1. Choose **Create policy**.

The Developers role now has permissions to use the `UpdateData` role in the Destination account. The Analysts role is prevented from using the `UpdateData` role.

Next, you can see how David, a developer, can access the `amzn-s3-demo-bucket-shared-container` bucket in the Destination account. David can access the bucket from the AWS Management Console, the AWS CLI, or the AWS API.

## Test access by switching roles
<a name="tutorial_cross-account-with-roles-3"></a>

After completing the first two steps of this tutorial, you have a role that grants access to a resource in the **Destination** account. You also have one role in the **Originating** account with users allowed to use that role. This step discusses how to test switching to that role from the AWS Management Console, the AWS CLI, and the AWS API.

To get help with common issues that you might encounter when working with IAM roles, see [Troubleshoot IAM roles](troubleshoot_roles.md).

### Switch roles (console)
<a name="switch-tutorial_cross-account-with-roles"></a>

If David needs to update data in the **Destination** account in the AWS Management Console, he can do so by using **Switch Role**. He specifies the account ID or alias and the role name, and his permissions immediately switch to those permitted by the role. He can then use the console to work with the `amzn-s3-demo-bucket-shared-container` bucket, but cannot work with any other resources in **Destination**. While David uses the role, he also cannot make use of his power-user privileges in the **Originating** account. That's because only one set of permissions can be in effect at a time.

IAM provides two ways that David can use to enter the **Switch Role** page:
+ David receives a link from their administrator that points to a predefined Switch Role configuration. The link is provided to the administrator on the final page of the **Create role** wizard or on the **Role Summary** page for a cross-account role. Choosing this link takes David to the **Switch Role** page with the **Account ID** and **Role name** fields already filled in. All David needs to do is choose **Switch Roles**.
+ The administrator does not send the link in email, but instead sends the **Account ID** number and **Role Name** values. To switch roles, David must manually enter the values. This is illustrated in the following procedure.

**To assume a role**

1. David signs into the AWS Management Console using his normal user in the **Originating** account.

1. They choose the link that the administrator emailed to them. This takes David to the **Switch Role** page with the account ID or alias and the role name information already filled in.

   —or—

   David chooses their name (the Identity menu) on the navigation bar, and then chooses **Switch Roles**. 

   If this is the first time that David tries to access the Switch Role page this way, he first lands on a first-run **Switch Role** page. This page provides additional information on how switching roles can permit users to manage resources across AWS accounts. David must choose **Switch Role** on this page to complete the rest of this procedure.

1. Next, in order to access the role, David must manually type the Destination account ID number (`999999999999`) and the role name (`UpdateData`).

   Also, David wants to monitor which roles and associated permissions currently active in IAM. To keep track of this information, he types `Destination` in the **Display Name** text box, chooses the red color option, and then chooses **Switch Role**.

1. David can now use the Amazon S3 console to work with the Amazon S3 bucket, or any other resource to which the `UpdateData` role has permissions.

1. When done, David can return to their original permissions. To do that, they choose the **Destination **role display name on the navigation bar and then choose **Back to David @ 111111111111**.

1. The next time that David wants to switch roles and chooses the **Identity** menu in the navigation bar, he sees the Destination entry still there from last time. He can simply choose that entry to switch roles immediately without reentering the account ID and role name.

### Switch roles (AWS CLI)
<a name="switch-cli-tutorial_cross-account-with-roles"></a>

 If David needs to work in the **Destination** environment at the command line, he can do so by using the [AWS CLI](http://aws.amazon.com/cli/). He runs the `aws sts assume-role` command and passes the role ARN to get temporary security credentials for that role. He then configures those credentials in environment variables so subsequent AWS CLI commands work using the role's permissions. While David uses the role, he cannot use his power-user privileges in the **Originating** account, because only one set of permissions can be in effect at a time.

Note that all access keys and tokens are examples only and cannot be used as shown. Replace with the appropriate values from your live environment.

**To assume a role**

1. David opens a command prompt window, and confirms that the AWS CLI client is working by running the command:

   ```
   aws help
   ```
**Note**  
David's default environment uses the `David` user credentials from his default profile that he created with the `aws configure` command. For more information, see [Configuring the AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-quick-configuration) in the *AWS Command Line Interface User Guide*.

1. He begins the switch role process by running the following command to switch to the `UpdateData` role in the **Destination** account. He received the role ARN from the administrator that created the role. The command requires that you provide a session name as well, you can choose any text you like for that.

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

   David then sees the following in the output:

   ```
   {
       "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 sees the three pieces that they need in the Credentials section of the output.
   + `AccessKeyId`
   + `SecretAccessKey`
   + `SessionToken`

   David needs to configure the AWS CLI environment to use these parameters in subsequent calls. For information about the various ways to configure your credentials, see [Configuring the AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#config-settings-and-precedence). You cannot use the `aws configure` command because it does not support capturing the session token. However, you can manually enter the information into a configuration file. Because these are temporary credentials with a relatively short expiration time, it is easiest to add them to the environment of your current command line session.

1. To add the three values to the environment, David cuts and pastes the output of the previous step into the following commands. You might want to cut and paste into a simple text editor to address line wrap issues in the output of the session token. It must be added as a single long string, even though it is shown line wrapped here for clarity.

   The following example shows commands given in the Windows environment, where "set" is the command to create an environment variable. On a Linux or macOS computer, you would use the command "export" instead. All other parts of the example are valid in all three environments.

   For details on using Tools for Windows Powershell, see [Switch to an IAM role (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==
   ```

   At this point, any following commands run under the permissions of the role identified by those credentials. In David's case, the `UpdateData` role.
**Important**  
You can save your frequently used configuration settings and credentials in files that are maintained by the AWS CLI. For more information, see [Using existing configuration and credentials files](https://docs.aws.amazon.com//cli/latest/userguide/getting-started-quickstart.html#getting-started-quickstart-existing) in the *AWS Command Line Interface User Guide*. 

1. Run the command to access the resources in the Destination account. In this example, David lists the contents of their S3 bucket with the following command.

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

   Because Amazon S3 bucket names are universally unique, there is no need to specify the account ID that owns the bucket. To access resources for other AWS services, refer to the AWS CLI documentation for that service for the commands and syntax required to reference its resources.

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

When David needs to make an update to the **Destination** account from code, he makes an `AssumeRole` call to assume the `UpdateData` role. The call returns temporary credentials that he can use to access the `amzn-s3-demo-bucket-shared-container` bucket in the **Destination** account. With those credentials, David can make API calls to update the `amzn-s3-demo-bucket-shared-container` bucket. However, he cannot make API calls to access any other resources in the **Destination** account, even though he has power-user permissions in the **Originating** account.

**To assume a role**

1. David calls `AssumeRole` as part of an application. They must specify the `UpdateData` ARN: `arn:aws:iam::999999999999:role/UpdateData`.

   The response from the `AssumeRole` call includes the temporary credentials with an `AccessKeyId` and a `SecretAccessKey`. It also includes an `Expiration` time that indicates when the credentials expire and you must request new ones. When you set up role chaining with the AWS SDK, many credential providers automatically refresh credentials before they expire.

1. With the temporary credentials, David makes an `s3:PutObject` call to update the `amzn-s3-demo-bucket-shared-container` bucket. They would pass the credentials to the API call as the `AuthParams` parameter. Because the temporary role credentials have only read and write access to the `amzn-s3-demo-bucket-shared-container` bucket, any other actions in the Destination account are denied.

For a code example (using Python), see [Switch to an IAM role (AWS API)](id_roles_use_switch-role-api.md).

## Additional resources
<a name="tutorial_cross-account-with-roles-related"></a>

The following resources can help you learn more about topics in this tutorial:
+ For more information about IAM users, see [IAM Identities](id.md).
+ For more information about Amazon S3 buckets, see [Create a Bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/CreatingABucket.html) in the *Amazon Simple Storage Service User Guide*.
+  To learn whether principals in accounts outside of your zone of trust (trusted organization or account) have access to assume your roles, see [What is IAM Access Analyzer?](https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html).

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

You have completed the cross-account API access tutorial. You created a role to establish trust with another account and defined what actions trusted entities can take. Then, you modified a role policy to control which IAM users can access the role. As a result, developers from the **Originating** account can make updates to the `amzn-s3-demo-bucket-shared-container` bucket in the **Destination** account by using temporary credentials.

# IAM tutorial: Create and attach your first customer managed policy
<a name="tutorial_managed-policies"></a>

In this tutorial, you use the AWS Management Console to create a [customer managed policy](access_policies_managed-vs-inline.md#customer-managed-policies) and then attach that policy to an IAM user in your AWS account. The policy you create allows an IAM test user to sign in directly to the AWS Management Console with read-only permissions. 

This workflow has three basic steps:

**[Step 1: Create the policy](#step1-create-policy)**  
By default, IAM users do not have permissions to do anything. They cannot access the AWS Management Console or manage the data within unless you allow it. In this step, you create a customer managed policy that allows any attached user to sign in to the console.

**[Step 2: Attach the policy](#step2-attach-policy)**  
When you attach a policy to a user, the user inherits all of the access permissions that are associated with that policy. In this step, you attach the new policy to a test user.

**[Step 3: Test user access](#step3-test-access)**  
Once the policy is attached, you can sign in as the user and test the policy. 

## Prerequisites
<a name="tutorial-managed-policies-prereqs"></a>

To perform the steps in this tutorial, you need to already have the following:
+ An AWS account that you can sign in to as an IAM user with administrative permissions.
+ A test IAM user that has no permissions assigned or group memberships as follows:  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_managed-policies.html)

## Step 1: Create the policy
<a name="step1-create-policy"></a>

In this step, you create a customer managed policy that allows any attached user to sign in to the AWS Management Console with read-only access to IAM data.

**To create the policy for your test user**

1. Sign in to the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) with your user that has administrator permissions.

1. In the navigation pane, choose **Policies**. 

1. In the content pane, choose **Create policy**. 

1. Choose the **JSON** option and copy the text from the following JSON policy document. Paste this text into the **JSON** text box. 

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

****  

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

------

1.  Resolve any security warnings, errors, or general warnings generated during [policy validation](access_policies_policy-validator.md), and then choose **Next**. 
**Note**  
You can switch between the **Visual** and **JSON** editor options anytime. However, if you make changes or choose **Review policy** in the **Visual** editor tab, IAM might restructure your policy to optimize it for the visual editor. For more information, see [Policy restructuring](troubleshoot_policies.md#troubleshoot_viseditor-restructure).

1. On the **Review and create** page, type **UsersReadOnlyAccessToIAMConsole** for the policy name. Review the permissions granted by your policy, and then choose **Create policy** to save your work.

   The new policy appears in the list of managed policies and is ready to attach.

## Step 2: Attach the policy
<a name="step2-attach-policy"></a>

Next you attach the policy you just created to your test IAM user. 

**To attach the policy to your test user**

1. In the IAM console, in the navigation pane, choose **Policies**.

1. At the top of the policy list, in the search box, start typing **UsersReadOnlyAccessToIAMConsole** until you can see your policy. Then choose the radio button next to **UsersReadOnlyAccessToIAMConsole** in the list. 

1. Choose the **Actions** button, and then choose **Attach**. 

1. In IAM entities   choose the option to filter for **Users**. 

1. In the search box, start typing **PolicyUser** until that user is visible on the list. Then check the box next to that user in the list.

1. Choose **Attach policy**. 

You have attached the policy to your IAM test user, which means that user now has read-only access to the IAM console. 

## Step 3: Test user access
<a name="step3-test-access"></a>

For this tutorial, we recommend that you test access by signing in as the test user so you can see what your users might experience. 

**To test access by signing in with your test user**

1. Sign in to the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) with your `PolicyUser` test user.

1. Browse through the pages of the console and try to create a new user or group. Notice that `PolicyUser` can display data but cannot create or modify existing IAM data.

## Related resources
<a name="tutorial-managed-policies-addl-resources"></a>

For related information, see the following resources:
+ [Managed policies and inline policies](access_policies_managed-vs-inline.md)
+ [Control IAM user access to the AWS Management Console](console_controlling-access.md)

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

You've now successfully completed all of the steps necessary to create and attach a customer managed policy. As a result, you are able to sign in to the IAM console with your test account to see what the experience is like for your users.

# IAM tutorial: Define permissions to access AWS resources based on tags
<a name="tutorial_attribute-based-access-control"></a>

Attribute-based access control (ABAC) is an authorization strategy that defines permissions based on attributes. In AWS, these attributes are called *tags*. You can attach tags to IAM resources, including IAM entities (users or roles) and to AWS resources. You can define policies that use tag condition keys to grant permissions to your principals based on their tags. When you use tags to control access to your AWS resources, you allow your teams and resources to grow with fewer changes to AWS policies. ABAC policies are more flexible than traditional AWS policies, which require you to list each individual resource. For more information about ABAC and its advantage over traditional policies, see [Define permissions based on attributes with ABAC authorization](introduction_attribute-based-access-control.md).

**Note**  
You must pass a single value for each session tag. AWS Security Token Service does not support multi-valued session tags.

**Topics**
+ [Tutorial overview](#tutorial_attribute-based-access-control-overview)
+ [Prerequisites](#tutorial_abac_prereqs)
+ [Step 1: Create test users](#tutorial_abac_step1)
+ [Step 2: Create the ABAC policy](#tutorial_abac_step2)
+ [Step 3: Create roles](#tutorial_abac_step3)
+ [Step 4: Test creating secrets](#tutorial_abac_step4)
+ [Step 5: Test viewing secrets](#tutorial_abac_step5)
+ [Step 6: Test scalability](#tutorial_abac_step6)
+ [Step 7: Test updating and deleting secrets](#tutorial_abac_step7)
+ [Summary](#tutorial-abac-summary)
+ [Related resources](#tutorial_abac_related)
+ [IAM tutorial: Use SAML session tags for ABAC](tutorial_abac-saml.md)

## Tutorial overview
<a name="tutorial_attribute-based-access-control-overview"></a>

This tutorial shows how to create and test a policy that allows IAM roles with principal tags to access resources with matching tags. When a principal makes a request to AWS, their permissions are granted based on whether the principal and resource tags match. This strategy allows individuals to view or edit only the AWS resources required for their jobs. 

**Scenario**  
Assume that you're a lead developer at a large company named Example Corporation, and you're an experienced IAM administrator. You're familiar with creating and managing IAM users, roles, and policies. You want to ensure that your development engineers and quality assurance team members can access the resources they need. You also need a strategy that scales as your company grows.

You choose to use AWS resource tags and IAM role principal tags to implement an ABAC strategy for services that support it, beginning with AWS Secrets Manager. To learn which services support authorization based on tags, see [AWS services that work with IAM](reference_aws-services-that-work-with-iam.md). To learn which tagging condition keys you can use in a policy with each service's actions and resources, see [Actions, Resources, and Condition Keys for AWS Services](reference_policies_actions-resources-contextkeys.html). You can configure your SAML-based or web identity provider to pass [session tags](id_session-tags.md) to AWS. When your employees federate into AWS, their attributes are applied to their resulting principal in AWS. You can then use ABAC to allow or deny permissions based on those attributes. To learn how using session tags with a SAML federated identity differs from this tutorial, see [IAM tutorial: Use SAML session tags for ABAC](tutorial_abac-saml.md).

Your Engineering and Quality Assurance team members are on either the **Pegasus** or **Unicorn** project. You choose the following 3-character project and team tag values:
+ `access-project` = `peg` for the **Pegasus** project
+ `access-project` = `uni` for the **Unicorn** project
+ `access-team` = `eng` for the Engineering team
+ `access-team` = `qas` for the Quality Assurance team

Additionally, you choose to require the `cost-center` cost allocation tag to enable custom AWS billing reports. For more information, see [Using Cost Allocation Tags](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html) in the *AWS Billing and Cost Management User Guide*.

**Summary of key decisions**
+ Employees sign in with IAM user credentials and then assume the IAM role for their team and project. If your company has its own identity system, you can set up federation to allow employees to assume a role without IAM users. For more information, see [IAM tutorial: Use SAML session tags for ABAC](tutorial_abac-saml.md).
+ The same policy is attached to all of the roles. Actions are allowed or denied based on tags.
+ Employees can create new resources, but only if they attach the same tags to the resource that are applied to their role. This ensures that employees can view the resource after they create it. Administrators are no longer required to update policies with the ARN of new resources.
+ Employees can read resources owned by their team, regardless of the project.
+ Employees can update and delete resources owned by their own team and project. 
+ IAM administrators can add a new role for new projects. They can create and tag a new IAM user to allow access to the appropriate role. Administrators are not required to edit a policy to support a new project or team member.

In this tutorial, you will tag each resource, tag your project roles, and add policies to the roles to allow the behavior previously described. The resulting policy allows the roles `Create`, `Read`, `Update`, and `Delete` access to resources that are tagged with the same project and team tags. The policy also allows cross-project `Read` access for resources that are tagged with the same team.

![\[The diagram shows two projects where roles are limited to read only access outside of their project while have permissions to create, read, update, and delete resources in their own project.\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/images/tutorial-abac-cross-project.png)


## Prerequisites
<a name="tutorial_abac_prereqs"></a>

To perform the steps in this tutorial, you must already have the following:
+ An AWS account that you can sign in to as a user with administrative permissions.
+ Your 12-digit account ID, which you use to create the roles in step 3.

  To find your AWS account ID number using the AWS Management Console, choose **Support** on the navigation bar on the upper right, and then choose **Support Center**. The account number (ID) appears in the navigation pane on the left.  
![\[Support Center page showing the account number.\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/images/account-id-support-center.console.png)
+ Experience creating and editing IAM users, roles, and policies in the AWS Management Console. However, if you need help remembering an IAM management process, this tutorial provides links where you can view step-by-step instructions.

## Step 1: Create test users
<a name="tutorial_abac_step1"></a>

For testing, create four IAM users with permissions to assume roles with the same tags. This makes it easier to add more users to your teams. When you tag the users, they automatically get access to assume the correct role. You don't have to add the users to the trust policy of the role if they work on only one project and team.

1. Create the following customer managed policy named `access-assume-role`. For more information about creating a JSON policy, see [Creating IAM policies](access_policies_create-console.md#access_policies_create-start).

**ABAC policy: Assume any ABAC role, but only when the user and role tags match**  
The following policy allows a user to assume any role in your account with the `access-` name prefix. The role must also be tagged with the same project, team, and cost center tags as the user.

   To use this policy, replace the *italicized placeholder text* with your account information.

------
#### [ 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}"
                   }
               }
           }
       ]
   }
   ```

------

   To scale this tutorial to a large number of users, you can attach the policy to a group and add each user to the group. For more information, see [Create IAM groups](id_groups_create.md) and [Edit users in IAM groups](id_groups_manage_add-remove-users.md).

1. Create the following IAM users, attach the `access-assume-role` permissions policy. Make sure you select **Provide user access to the AWS Management Console**, and then add the following tags.

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

## Step 2: Create the ABAC policy
<a name="tutorial_abac_step2"></a>

Create the following policy named **access-same-project-team**. You will add this policy to the roles in a later step. For more information about creating a JSON policy, see [Creating IAM policies](access_policies_create-console.md#access_policies_create-start).

For additional policies that you can adapt for this tutorial, see the following pages:
+ [Controlling access for IAM principals](access_iam-tags.md#access_iam-tags_control-principals)
+ [Amazon EC2: Allows starting or stopping EC2 instances a user has tagged, programmatically and in the console](reference_policies_examples_ec2_tag-owner.md)
+ [EC2: Start or stop instances based on matching principal and resource tags](reference_policies_examples_ec2-start-stop-match-tags.md)
+ [EC2: Start or stop instances based on tags](reference_policies_examples_ec2-start-stop-tags.md)
+ [IAM: Assume roles that have a specific tag](reference_policies_examples_iam-assume-tagged-role.md)

**ABAC Policy: Access Secrets Manager Resources Only When the Principal and Resource Tags Match**  
The following policy allows principals to create, read, edit, and delete resources, but only when those resources are tagged with the same key-value pairs as the principal. When a principal creates a resource, they must add `access-project`, `access-team`, and `cost-center` tags with values that match the principal's tags. The policy also allows adding optional `Name` or `OwnedBy` tags.

------
#### [ 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": "*"
     }
 ]
}
```

------

**What does this policy do?**
+ The `AllActionsSecretsManagerSameProjectSameTeam` statement allows all of this service's actions on all related resources, but only if the resource tags match the principal tags. By adding `"Action": "secretsmanager:*"` to the policy, the policy grows as Secrets Manager grows. If Secrets Manager adds a new API operation, you are not required to add that action to the statement. The statement implements ABAC using three condition blocks. The request is allowed only if all three blocks return true.
  + The first condition block of this statement returns true if the specified tag keys are present on the resource, and their values match the principal's tags. This block returns false for mismatched tags, or for actions that don't support resource tagging. To learn which actions are not allowed by this block, see [Actions, Resources, and Condition Keys for AWS Secrets Manager](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awssecretsmanager.html). That page shows that actions performed on the [**Secret** resource type](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awssecretsmanager.html#awssecretsmanager-resources-for-iam-policies) support the `secretsmanager:ResourceTag/tag-key` condition key. Some [Secrets Manager actions](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_awssecretsmanager.html#awssecretsmanager-actions-as-permissions) don't support that resource type, including `GetRandomPassword` and `ListSecrets`. You must create additional statements to allow those actions.
  + The second condition block returns true if every tag key passed in the request is included in the specified list. This is done using `ForAllValues` with the `StringEquals` condition operator. If no keys or a subset of the set of keys is passed, then the condition returns true. This allows `Get*` operations that do not allow passing tags in the request. If the requester includes a tag key that is not in the list, the condition returns false. Every tag key that is passed in the request must match a member of this list. For more information, see [Set operators for multivalued context keys](reference_policies_condition-single-vs-multi-valued-context-keys.md#reference_policies_condition-multi-valued-context-keys).
  + The third condition block returns true if the request supports passing tags, if all three of the tags are present, and if they match the principal tag values. This block also returns true if the request does not support passing tags. This is thanks to [`...IfExists`](reference_policies_elements_condition_operators.md#Conditions_IfExists) in the condition operator. The block returns false if there is no tag passed during an action that supports it, or if the tag keys and values don't match.
+ The `AllResourcesSecretsManagerNoTags` statement allows the `GetRandomPassword` and `ListSecrets` actions that are not allowed by the first statement.
+ The `ReadSecretsManagerSameTeam` statement allows read-only operations if the principal is tagged with the same access-team tag as the resource. This is allowed regardless of the project or cost-center tag. 
+ The `DenyUntagSecretsManagerReservedTags` statement denies requests to remove tags with keys that begin with "access-" from Secrets Manager. These tags are used to control access to resources, therefore removing tags might remove permissions.
+ The `DenyPermissionsManagement` statement denies access to create, edit, or delete Secrets Manager resource-based policies. These policies could be used to change the permissions of the secret. 

**Important**  
This policy uses a strategy to allow all actions for a service, but explicitly deny permissions-altering actions. Denying an action overrides any other policy that allows the principal to perform that action. This can have unintended results. As a best practice, use explicit denies only when there is no circumstance that should allow that action. Otherwise, allow a list of individual actions, and the unwanted actions are denied by default.

## Step 3: Create roles
<a name="tutorial_abac_step3"></a>

Create the following IAM roles and attach the **access-same-project-team** policy that you created in the previous step. For more information about creating IAM roles, see [Create a role to give permissions to an IAM user](id_roles_create_for-user.md). If you choose to use federation instead of IAM users and roles, see [IAM tutorial: Use SAML session tags for ABAC](tutorial_abac-saml.md).


| Job function | Role name | Role tags | Role description | 
| --- | --- | --- | --- | 
|  Project Pegasus Engineering  |  access-peg-engineering  |  access-project = `peg` access-team = `eng` cost-center = `987654`   | Allows engineers to read all engineering resources and create and manage Pegasus engineering resources. | 
|  Project Pegasus Quality Assurance  |  access-peg-quality-assurance  |  access-project = `peg` access-team = `qas` cost-center = `987654`  |  Allows the QA team to read all QA resources and create and manage all Pegasus QA resources.  | 
|  Project Unicorn Engineering  |  access-uni-engineering  |  access-project= `uni` access-team = `eng` cost-center = `123456`  | Allows engineers to read all engineering resources and create and manage Unicorn engineering resources. | 
|  Project Unicorn Quality Assurance  |  access-uni-quality-assurance  |  access-project = `uni` access-team = `qas` cost-center = `123456`   |  Allows the QA team to read all QA resources and create and manage all Unicorn QA resources.  | 

## Step 4: Test creating secrets
<a name="tutorial_abac_step4"></a>

The permissions policy attached to the roles allows the employees to create secrets. This is allowed only if the secret is tagged with their project, team, and cost center. Confirm that your permissions are working as expected by signing in as your users, assuming the correct role, and testing activity in Secrets Manager.

**To test creating a secret with and without the required tags**

1. In your main browser window, remain signed in as the administrator user so that you can review users, roles, and policies in IAM. Use a browser incognito window or separate browser for your testing. There, sign in as the `access-Arnav-peg-eng` IAM user and open the Secrets Manager console at [https://console.aws.amazon.com/secretsmanager/](https://console.aws.amazon.com/secretsmanager/).

1. Attempt to switch to the `access-uni-engineering` role.

   This operation fails because the `access-project` and `cost-center` tag values do not match for the `access-Arnav-peg-eng` user and `access-uni-engineering` role.

   For more information about switching roles in the AWS Management Console, see [Switch from a user to an IAM role (console)](id_roles_use_switch-role-console.md)

1. Switch to the `access-peg-engineering` role.

1. Store a new secret using the following information. To learn how to store a secret, see [Creating a Basic Secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html) in the *AWS Secrets Manager User Guide*.
**Important**  
Secrets Manager displays alerts that you don't have permissions for additional AWS services that work with Secrets Manager. For example, to create credentials for an Amazon RDS database, you must have permission to describe RDS instances, RDS clusters, and Amazon Redshift clusters. You can ignore these alerts since you aren't using these specific AWS services in this tutorial. 

   1. In the **Select secret type** section, choose **Other type of secrets**. In the two text boxes, enter `test-access-key` and `test-access-secret`.

   1. Enter `test-access-peg-eng` for the **Secret name** field. 

   1. Add different tag combinations from the following table and view the expected behavior.

   1. Choose **Store** to attempt to create the secret. When the storage fails, return to the previous Secrets Manager console pages and use the next tag set from the following table. The last tag set is allowed and will successfully create the secret.

   The following table shows ABAC tag combinations for the `test-access-peg-eng` role.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

1. Sign out and repeat the first three steps of this procedure for each of the following roles and tag values. In the fourth step in this procedure, test any set of missing tags, optional tags, disallowed tags, and invalid tag values that you choose. Then use the required tags to create a secret with the following tags and name.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

## Step 5: Test viewing secrets
<a name="tutorial_abac_step5"></a>

The policy that you attached to each role allows the employees to view any secrets tagged with their team name, regardless of their project. Confirm that your permissions are working as expected by testing your roles in Secrets Manager. 

**To test viewing a secret with and without the required tags**

1. Sign in as one of the following IAM users:
   + `access-Arnav-peg-eng`
   + `access-Mary-peg-qas`
   + `access-Saanvi-uni-eng`
   + `access-Carlos-uni-qas`

1. Switch to the matching role:
   + `access-peg-engineering`
   + `access-peg-quality-assurance`
   + `access-uni-engineering`
   + `access-uni-quality-assurance`

   For more information about switching roles in the AWS Management Console, see [Switch from a user to an IAM role (console)](id_roles_use_switch-role-console.md).

1. In the navigation pane on the left, choose the menu icon to expand the menu and then choose **Secrets**. 

1. You should see all four secrets in the table, regardless of your current role. This is expected because the policy named `access-same-project-team` allows the `secretsmanager:ListSecrets` action for all resources.

1. Choose the name of one of the secrets.

1. On the details page for the secret, your role's tags determine whether you can view the page content. Compare the name of your role to the name of your secret. If they share the same team name, then the `access-team` tags match. If they don't match, then access is denied.

   The following table shows ABAC secret viewing behavior for each role.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

1. From the breadcrumbs at the top of the page, choose **Secrets** to return to the list of secrets. Repeat the steps in this procedure using different roles to test whether you can view each of the secrets.

## Step 6: Test scalability
<a name="tutorial_abac_step6"></a>

An important reason for using attribute-based access control (ABAC) over role-based access control (RBAC) is scalability. As your company adds new projects, teams, or people to AWS, you don't need to update your ABAC-driven policies. For example, assume that Example Company is funding a new project, code named **Centaur**. An engineer named Saanvi Sarkar will be the lead engineer for **Centaur** while continuing to work on the **Unicorn** project. Saanvi will also review work for the **Peg** project. There are also several newly hired engineers, including Nikhil Jayashankar, who will work on only the **Centaur** project.

**To add the new project to AWS**

1. Sign in as the IAM administrator user and open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. In the navigation pane on the left, choose **Roles** and add an IAM role named `access-cen-engineering`. Attach the **access-same-project-team** permissions policy to the role and add the following role tags:
   + `access-project` = `cen`
   + `access-team` = `eng`
   + `cost-center` = `101010`

1. In the navigation pane on the left, choose **Users**.

1. Add a new user named `access-Nikhil-cen-eng`, attach the policy named `access-assume-role`, and add the following user tags.
   + `access-project` = `cen`
   + `access-team` = `eng`
   + `cost-center` = `101010`

1. Use the procedures in [Step 4: Test creating secrets](#tutorial_abac_step4) and [Step 5: Test viewing secrets](#tutorial_abac_step5). In another browser window, test that Nikhil can create only **Centaur** engineering secrets, and that he can view all engineering secrets.

1. In the main browser window where you signed in as the administrator, choose the user `access-Saanvi-uni-eng`.

1. On the **Permissions** tab, remove the **access-assume-role** permissions policy.

1. Add the following inline policy named `access-assume-specific-roles`. For more information about adding an inline policy to a user, see [To embed an inline policy for a user or role (console)](access_policies_manage-attach-detach.md#embed-inline-policy-console).

**ABAC policy: Assume only specific roles**  
This policy allows Saanvi to assume the engineering roles for the **Pegasus** and **Centaur** projects. It is necessary to create this custom policy because IAM does not support multivalued tags. You can't tag Saanvi's user with `access-project` = `peg` and `access-project` = `cen`. Additionally, the AWS authorization model can't match both values. For more information, see [Rules for tagging in IAM and AWS STS](id_tags.md#id_tags_rules). Instead, you must manually specify the two roles that she can assume.

   To use this policy, replace the *italicized placeholder text* with your account information.

------
#### [ 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. Use the procedures in [Step 4: Test creating secrets](#tutorial_abac_step4) and [Step 5: Test viewing secrets](#tutorial_abac_step5). In another browser window, confirm that Saanvi can assume both roles. Check that she can create secrets for only her project, team, and cost center, depending on the role's tags. Also confirm that she can view details about any secrets owned by the engineering team, including the ones that she just created.

## Step 7: Test updating and deleting secrets
<a name="tutorial_abac_step7"></a>

The `access-same-project-team` policy that is attached to the roles allows the employees to update and delete any secrets tagged with their project, team, and cost center. Confirm that your permissions are working as expected by testing your roles in Secrets Manager.

**To test updating and deleting a secret with and without the required tags**

1. Sign in as one of the following IAM users:
   + `access-Arnav-peg-eng`
   + `access-Mary-peg-qas`
   + `access-Saanvi-uni-eng`
   + `access-Carlos-uni-qas`
   + `access-Nikhil-cen-eng`

1. Switch to the matching role:
   + `access-peg-engineering`
   + `access-peg-quality-assurance`
   + `access-uni-engineering`
   + `access-peg-quality-assurance`
   + `access-cen-engineering`

   For more information about switching roles in the AWS Management Console, see [Switch from a user to an IAM role (console)](id_roles_use_switch-role-console.md).

1. For each role, try to update the secret description and then try to delete the following secrets. For more information, see [Modifying a Secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_update-secret.html) and [Deleting and Restoring a Secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_delete-restore-secret.html) in the *AWS Secrets Manager User Guide*.

   The following table shows ABAC secret updating and deleting behavior for each role.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)

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

You've now successfully completed all of the steps necessary to use tags for attribute-based access control (ABAC). You've learned how to define a tagging strategy. You applied that strategy to your principals and resources. You created and applied a policy that enforces the strategy for Secrets Manager. You also learned that ABAC scales easily when you add new projects and team members. As a result, you are able to sign in to the IAM console with your test roles and experience how to use tags for ABAC in AWS.

**Note**  
You added policies that allow actions only under specific conditions. If you apply a different policy to your users or roles that has broader permissions, then the actions might not be limited to require tagging. For example, if you give a user full administrative permissions using the `AdministratorAccess` AWS managed policy, then these policies don't restrict that access. For more information about how permissions are determined when multiple policies are involved, see [How AWS enforcement code logic evaluates requests to allow or deny access](reference_policies_evaluation-logic_policy-eval-denyallow.md).

## Related resources
<a name="tutorial_abac_related"></a>

For related information, see the following resources:
+ [Define permissions based on attributes with ABAC authorization](introduction_attribute-based-access-control.md)
+ [AWS global condition context keys](reference_policies_condition-keys.md)
+ [Create a role to give permissions to an IAM user](id_roles_create_for-user.md)
+ [Tags for AWS Identity and Access Management resources](id_tags.md)
+ [Controlling access to AWS resources using tags](access_tags.md)
+ [Switch from a user to an IAM role (console)](id_roles_use_switch-role-console.md)
+ [IAM tutorial: Use SAML session tags for ABAC](tutorial_abac-saml.md)

To learn how to monitor the tags in your account, see [Monitor tag changes on AWS resources with serverless workflows and Amazon CloudWatch Events](https://aws.amazon.com/blogs/mt/monitor-tag-changes-on-aws-resources-with-serverless-workflows-and-amazon-cloudwatch-events/).

# IAM tutorial: Use SAML session tags for ABAC
<a name="tutorial_abac-saml"></a>

Attribute-based access control (ABAC) is an authorization strategy that defines permissions based on attributes. In AWS, these attributes are called tags. You can attach tags to IAM resources, including IAM entities (users or roles), and to AWS resources. When the entities are used to make requests to AWS, they become principals and those principals include tags.

You can also pass [session tags](id_session-tags.md) when you assume a role or federate a user. You can then define policies that use tag condition keys to grant permissions to your principals based on their tags. When you use tags to control access to your AWS resources, you allow your teams and resources to grow with fewer changes to AWS policies. ABAC policies are more flexible than traditional AWS policies, which require you to list each individual resource. For more information about ABAC and its advantage over traditional policies, see [Define permissions based on attributes with ABAC authorization](introduction_attribute-based-access-control.md).

If your company uses a SAML-based identity provider (IdP) to manage corporate user identities, you can use SAML attributes for fine-grained access control in AWS. Attributes can include cost center identifiers, user email addresses, department classifications, and project assignments. When you pass these attributes as session tags, you can then control access to AWS based on these session tags.

To complete the [ABAC tutorial](tutorial_attribute-based-access-control.md) by passing SAML attributes to your session principal, complete the tasks in [IAM tutorial: Define permissions to access AWS resources based on tags](tutorial_attribute-based-access-control.md), with the changes that are included in this topic.

## Prerequisites
<a name="tutorial_abac-saml-prerequisites"></a>

To perform the steps to use SAML session tags for ABAC, you must already have the following:
+ Access to a SAML-based IdP where you can create test users with specific attributes. 
+ The ability to sign in as a user with administrative permissions.
+ Experience creating and editing IAM users, roles, and policies in the AWS Management Console. However, if you need help remembering an IAM management process, the ABAC tutorial provides links where you can view step-by-step instructions.
+ Experience setting up a SAML-based IdP in IAM. To view more details and links to detailed IAM documentation, see [Passing session tags using AssumeRoleWithSAML](id_session-tags.md#id_session-tags_adding-assume-role-saml).

## Step 1: Create test users
<a name="tutorial_abac-saml-step1"></a>

Skip the instructions in [Step 1: Create test users](tutorial_attribute-based-access-control.md#tutorial_abac_step1). Because your identities are defined in your provider, it's not necessary for you to add IAM users for your employees. 

## Step 2: Create the ABAC policy
<a name="tutorial_abac-saml-step2"></a>

Follow the instructions in [Step 2: Create the ABAC policy](tutorial_attribute-based-access-control.md#tutorial_abac_step2) to create the specified managed policy in IAM. 

## Step 3: Create and configure the SAML role
<a name="tutorial_abac-saml-step3"></a>

When you use the ABAC tutorial for SAML, you must perform additional steps to create the role, configure the SAML IdP, and enable AWS Management Console access. For more information, see [Step 3: Create roles](tutorial_attribute-based-access-control.md#tutorial_abac_step3).

### Step 3A: Create the SAML role
<a name="tutorial_abac-saml-step3a"></a>

Create a single role that trusts your SAML identity provider and the `test-session-tags` user that you created in step 1. The ABAC tutorial uses separate roles with different role tags. Because you are passing session tags from your SAML IdP, you need only one role. To learn how to create a SAML-based role, see [Create a role for SAML 2.0 federation (console)](id_roles_create_for-idp_saml.md). 

Name the role `access-session-tags`. Attach the `access-same-project-team` permissions policy to the role. Edit the role trust policy to use the following policy. For detailed instructions on how to edit the trust relationship of a role, see [Update a role trust policy](id_roles_update-role-trust-policy.md).

The following role trust policy allows your SAML identity provider and the `test-session-tags` user to assume the role. When they assume the role, they must pass the three specified session tags. The `sts:TagSession` action is required to allow passing session tags.

------
#### [ 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"}
            }
        }
    ]
}
```

------

The `AllowSamlIdentityAssumeRole` statement allows members of the Engineering and Quality Assurance teams to assume this role when they federate into AWS from the Example Corporation IdP. The `ExampleCorpProvider` SAML provider is defined in IAM. The administrator has already set up the SAML assertion to pass the three required session tags. The assertion can pass additional tags, but these three must be present. The identity's attributes can have any value for the `cost-center` and `access-project` tags. However, the `access-team` attribute value must match `eng` or `qas` to indicate that the identity is on the Engineering or Quality Assurance team. 

### Step 3B: Configure the SAML IdP
<a name="tutorial_abac-saml-step3b"></a>

Configure your SAML IdP to pass the `cost-center`, `access-project`, and `access-team` attributes as session tags. For more information, see [Passing session tags using AssumeRoleWithSAML](id_session-tags.md#id_session-tags_adding-assume-role-saml).

To pass these attributes as session tags, include the following elements in your SAML assertion.

```
<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>
```

### Step 3C: Enable console access
<a name="tutorial_abac-saml-step3b"></a>

Enable console access for your federated SAML users. For more information, see [Enabling SAML 2.0 federated principals to access the AWS Management Console](id_roles_providers_enable-console-saml.md).

## Step 4: Test creating secrets
<a name="tutorial_abac-saml-step4"></a>

Federate into the AWS Management Console using the `access-session-tags` role. For more information, see [Enabling SAML 2.0 federated principals to access the AWS Management Console](id_roles_providers_enable-console-saml.md). Then follow the instructions in [Step 4: Test creating secrets](tutorial_attribute-based-access-control.md#tutorial_abac_step4) to create secrets. Use different SAML identities with attributes to match the tags that are indicated in the ABAC tutorial. For more information, see [Step 4: Test creating secrets](tutorial_attribute-based-access-control.md#tutorial_abac_step4).

## Step 5: Test viewing secrets
<a name="tutorial_abac-saml-step5"></a>

Follow the instructions in [Step 5: Test viewing secrets](tutorial_attribute-based-access-control.md#tutorial_abac_step5) to view the secrets that you created in the previous step. Use different SAML identities with attributes to match the tags that are indicated in the ABAC tutorial.

## Step 6: Test scalability
<a name="tutorial_abac-saml-step6"></a>

Follow the instructions in [Step 6: Test scalability](tutorial_attribute-based-access-control.md#tutorial_abac_step6) to test scalability. Do this by adding a new identity in your SAML-based IdP with the following attributes:
+ `cost-center = 101010`
+ `access-project = cen`
+ `access-team = eng`

## Step 7: Test updating and deleting secrets
<a name="tutorial_abac-saml-step7"></a>

Follow the instructions in [Step 7: Test updating and deleting secrets](tutorial_attribute-based-access-control.md#tutorial_abac_step7) to update and delete secrets. Use different SAML identities with attributes to match the tags that are indicated in the ABAC tutorial.

**Important**  
Delete all of the secrets that you created to avoid billing charges. For details about pricing in Secrets Manager, see [AWS Secrets Manager Pricing](https://aws.amazon.com/secrets-manager/pricing/).

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

You've now successfully completed all of the steps necessary to use SAML session tags and resource tags for permissions management.

**Note**  
You added policies that allow actions only under specific conditions. If you apply a different policy to your users or roles that has broader permissions, then the actions might not be limited to require tagging. For example, if you give a user full administrative permissions using the `AdministratorAccess` AWS managed policy, then these policies don't restrict that access. For more information about how permissions are determined when multiple policies are involved, see [How AWS enforcement code logic evaluates requests to allow or deny access](reference_policies_evaluation-logic_policy-eval-denyallow.md).

# IAM tutorial: Permit users to manage their credentials and MFA settings
<a name="tutorial_users-self-manage-mfa-and-creds"></a>

You can permit your users to manage their own multi-factor authentication (MFA) devices and credentials on the **Security credentials** page. You can use the AWS Management Console to configure credentials (access keys, passwords, signing certificates, and SSH public keys), delete or deactivate credentials that are not needed, and enable MFA devices for your users. This is useful for a small number of users, but that task could quickly become time consuming as the number of users grows. This tutorial shows you how to enable these best practices without burdening your administrators.

This tutorial shows how to allow users to access AWS services, but **only** when they sign in with MFA. If they are not signed in with an MFA device, then users cannot access other services.

This workflow has three basic steps. 

**[Step 1: Create a policy to enforce MFA sign-in](#tutorial_mfa_step1)**  
Create a customer managed policy that prohibits all actions ***except*** the few IAM actions. These exceptions allow a user to change their own credentials and manage their MFA devices on the **Security credentials** page. For more information about accessing that page, see [How IAM users change their own password (console)](id_credentials_passwords_user-change-own.md#ManagingUserPwdSelf-Console).

**[Step 2: Attach policies to your test user group](#tutorial_mfa_step2)**  
Create a user group whose members have full access to all Amazon EC2 actions if they sign in with MFA. To create such a user group, you attach both the AWS managed policy called `AmazonEC2FullAccess` and the customer managed policy you created in the first step.

**[Step 3: Test your user's access](#tutorial_mfa_step3)**  
Sign in as the test user to verify that access to Amazon EC2 is blocked *until* the user creates an MFA device. The user can then sign in using that device. 

## Prerequisites
<a name="tutorial_mfa_prereqs"></a>

To perform the steps in this tutorial, you must already have the following:
+ An AWS account that you can sign in to as an IAM user with administrative permissions.
+ Your account ID number, which you type into the policy in Step 1. 

  To find your account ID number, on the navigation bar at the top of the page, choose **Support** and then choose **Support Center**. You can find your account ID under this page's **Support** menu. 
+ A [virtual (software-based) MFA device](id_credentials_mfa_enable_virtual.md), [FIDO security key](id_credentials_mfa_enable_fido.md), or [hardware-based MFA device](id_credentials_mfa_enable_physical.md).
+ A test IAM user who is a member of a user group as follows:


| User name | User name instructions | User group name | Add user as a member | User group instructions | 
| --- | --- | --- | --- | --- | 
| MFAUser | Choose only the option for Enable console access – optional, and assign a password. | EC2MFA | MFAUser | Do NOT attach any policies or otherwise grant permissions to this user group. | 

## Step 1: Create a policy to enforce MFA sign-in
<a name="tutorial_mfa_step1"></a>

You begin by creating an IAM customer managed policy that denies all permissions except those required for IAM users to manage their own credentials and MFA devices.

1. Sign in to the AWS Management Console as a user with administrator credentials. To adhere to IAM best practices, don't sign in with your AWS account root user credentials.
**Important**  
 IAM [best practices](best-practices.md) recommend that you require human users to use federation with an identity provider to access AWS using temporary credentials instead of using IAM users with long-term credentials. We recommend that you only use IAM users for [specific use cases](gs-identities-iam-users.md) not supported by federated users.

1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

   

1. In the navigation pane, choose **Policies**, and then choose **Create policy**.

1. Choose the **JSON** tab and copy the text from the following JSON policy document: [AWS: Allows MFA-authenticated IAM users to manage their own credentials on the Security credentials page](reference_policies_examples_aws_my-sec-creds-self-manage.md).

1. Paste the policy text into the **JSON** text box. Resolve any security warnings, errors, or general warnings generated during policy validation, and then choose **Next**.
**Note**  
You can switch between the **Visual editor** and **JSON** options anytime. However, the policy above includes the `NotAction` element, which is not supported in the visual editor. For this policy, you will see a notification on the **Visual editor** tab. Return to **JSON** to continue working with this policy.  
This example policy does not allow users to reset a password while signing in to the AWS Management Console for the first time. We recommend that you do not grant permissions to new users until after they sign in and reset their password.

1. On the **Review and create** page, type **Force\$1MFA** for the policy name. For the policy description, type **This policy allows users to manage their own passwords and MFA devices but nothing else unless they authenticate with MFA.** In the **Tags** area, you can optionally add tag key-value pairs to the customer managed policy. Review the permissions granted by your policy, and then choose **Create policy** to save your work.

   The new policy appears in the list of managed policies and is ready to attach.

## Step 2: Attach policies to your test user group
<a name="tutorial_mfa_step2"></a>

Next you attach two policies to the test IAM user group, which will be used to grant the MFA-protected permissions.

1. In the navigation pane, choose **User groups**.

1. In the search box, type **`EC2MFA`**, and then choose the group name (not the checkbox) in the list. 

1. Choose the **Permissions** tab, choose **Add permissions**, and then choose **Attach policies**.

1. On the **Attach permission policies to EC2MFA group** page, in the search box, type **EC2Full**. Then select the checkbox next to **AmazonEC2FullAccess** in the list. Don't save your changes yet.

1. In the search box, type **Force**, and then select the checkbox next to **Force\$1MFA** in the list. 

1. Choose **Attach policies**.

## Step 3: Test your user's access
<a name="tutorial_mfa_step3"></a>

In this part of the tutorial, you sign in as the test user and verify that the policy works as intended.

1. Sign in to your AWS account as **MFAUser** with the password you assigned in the previous section. Use the URL: `https://<alias or account ID number>.signin.aws.amazon.com/console`

1. Choose **EC2** to open the Amazon EC2 console and verify that the user has no permissions to do anything.

1. In the navigation bar on the upper right, choose the `MFAUser` user name, and then choose **Security credentials**.   
![\[AWS Management Console Security credentials link.\]](http://docs.aws.amazon.com/IAM/latest/UserGuide/images/security-credentials-user.shared.console.png)

1. Now add an MFA device. In the **Multi-factor Authentication (MFA)** section, choose **Assign MFA device**.
**Note**  
You might receive an error that you are not authorized to perform `iam:DeleteVirtualMFADevice`. This could happen if someone previously began assigning a virtual MFA device to this user and cancelled the process. To continue, you or another administrator must delete the user's existing unassigned virtual MFA device. For more information, see [I am not authorized to perform: iam:DeleteVirtualMFADevice](troubleshoot.md#troubleshoot_general_access-denied-delete-mfa).

1. For this tutorial, we use a virtual (software-based) MFA device, such as the Google Authenticator app on a mobile phone. Choose **Authenticator app**, and then click **Next**.

   IAM generates and displays configuration information for the virtual MFA device, including a QR code graphic. The graphic is a representation of the secret configuration key that is available for manual entry on devices that do not support QR codes.

1. Open your virtual MFA app. (For a list of apps that you can use for hosting virtual MFA devices, see [Virtual MFA Applications](https://aws.amazon.com/iam/details/mfa/#Virtual_MFA_Applications).) If the virtual MFA app supports multiple accounts (multiple virtual MFA devices), choose the option to create a new account (a new virtual MFA device).

1. Determine whether the MFA app supports QR codes, and then do one of the following:
   + From the wizard, choose **Show QR code**. Then use the app to scan the QR code. For example, you might choose the camera icon or choose an option similar to **Scan code**, and then use the device's camera to scan the code.
   + In the **Set up device** wizard, choose **Show secret key**, and then type the secret key into your MFA app.

   When you are finished, the virtual MFA device starts generating one-time passwords. 

1. In the **Set up device** wizard, in the **Enter the code from your authenticator app.** box, type the one-time password that currently appears in the virtual MFA device. Choose **Register MFA**. 
**Important**  
Submit your request immediately after generating the code. If you generate the codes and then wait too long to submit the request, the MFA device is successfully associated with the user. However, the MFA device is out of sync. This happens because time-based one-time passwords (TOTP) expire after a short period of time. If this happens, you can [resync the device](id_credentials_mfa_sync.md).

   The virtual MFA device is now ready to use with AWS. 

1. Sign out of the console and then sign in as **MFAUser** again. This time AWS prompts you for an MFA code from your phone. When you get it, type the code in the box and then choose **Submit**.

1. Choose **EC2** to open the Amazon EC2 console again. Note that this time you can see all the information and perform any actions you want. If you go to any other console as this user, you see access denied messages. The reason is that the policies in this tutorial grant access only to Amazon EC2. 

## Related resources
<a name="tutorial_mfa_related"></a>

For additional information, see the following topics:
+ [AWS Multi-factor authentication in IAM](id_credentials_mfa.md)
+ [MFA enabled sign-in](console_sign-in-mfa.md)

# IAM tutorial: Use an CloudFormation template to create a SAML Identity Provider (IdP)
<a name="tutorial_saml-idp"></a>

To set up SAML federation for your AWS account, you need to create a SAML Identity Provider (IdP). This tutorial shows you how to use an CloudFormation template to create a SAML IdP that establishes trust between AWS and your external IdP.

The template creates a SAML IdP configured with your IdP's metadata document. Federated IAM roles can then reference this IdP to allow authenticated users from your external IdP to access AWS resources.

The deployed resource consists of a SAML IdP configured with your IdP's metadata document and optional encryption settings.

## Prerequisites
<a name="tutorial_saml-idp-prereqs"></a>

This tutorial assumes that you have the following already in place:
+ Python 3.6 or later installed on your local machine to run the Python command used in this tutorial for formatting your IdP's SAML metadata XML file.
+ A SAML metadata document from your external IdP saved as an XML file.

## Create a SAML IdP using CloudFormation
<a name="tutorial_saml-idp-create"></a>

To create the SAML IdP, you'll create an CloudFormation template and use it to create a stack containing the IdP resource.

### Create the template
<a name="tutorial_saml-idp-file"></a>

First, create the CloudFormation template.

1. In the [Template](#tutorial_saml-idp-template) section, click the copy icon on the **JSON** or **YAML** tab to copy the template contents.

1. Paste the template contents into a new file.

1. Save the file locally.

### Create the stack
<a name="tutorial_saml-idp-stack"></a>

Next, use the template you've saved to provision a CloudFormation stack.

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. On the **Stacks** page, from the **Create stack** menu, choose **with new resources (standard)**.

1. Specify the template:

   1. Under **Prerequisite**, choose **Choose an existing template**.

   1. Under **Specify template**, choose **Upload a template file**.

   1. Choose **Choose file**, navigate to the template file, and choose it.

   1. Choose **Next**.

1. Specify the following stack details:

   1. Enter a stack name.

   1. For **IdentityProviderName**, you can leave this empty to auto-generate a name based on the stack name, or enter a custom name for your SAML IdP. Custom names must contain only alphanumeric characters, periods, underscores, and hyphens.

   1. For **IdentityProviderSAMLMetadataDocument**, you need to format your SAML metadata XML file as a single line before pasting it into this field. This is necessary because the CloudFormation console requires XML content to be formatted as a single line when passed through console parameters.

      Use the following Python command to reformat your XML file:

      ```
      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
      ```
**Note**  
The IdP's SAML metadata document must be formatted as a single line for console parameter input. The Python command removes line breaks and extra whitespace to create the required format while maintaining all original content and structure.

      Copy the output from the Python command and paste it into the **IdentityProviderSAMLMetadataDocument** field.

      Example of formatted SAML metadata document (abbreviated):

      ```
      <?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. For other parameters, accept the default values or enter your own based on your requirements:
      + **IdentityProviderAddPrivateKey** - Optional private key for decrypting SAML assertions
      + **IdentityProviderAssertionEncryptionMode** - Optional, sets encryption mode for SAML assertions (Allowed, Required, or empty)

   1. Choose **Next**.

1. Configure the stack options:

   1. Under **Stack failure options**, choose **Delete all newly created resources**.
**Note**  
Choosing this option prevents you from possibly being billed for resources whose deletion policy specifies they be retained even if the stack creation fails.

   1. Accept all other default values.

   1. Under **Capabilities**, check the box to acknowledge that CloudFormation might create IAM resources in your account.

   1. Choose **Next**.

1. Review the stack details and choose **Submit**.

CloudFormation creates the stack. Once the stack creation is complete, the stack resources are ready to use. You can use the **Resources** tab on the stack detail page to view the resources that were provisioned in your account.

The stack will output the following values, which you can view on the **Outputs** tab:
+ **ProviderARN**: The ARN of the created SAML IdP (for example, `arn:aws:iam::123456789012:saml-provider/CompanyIdP`). You'll need this ARN when creating roles that trust this provider.
+ **ProviderName**: The name of the created SAML IdP (for example, `CompanyIdP` if you specified a custom name, or `my-saml-stack-saml-provider` if you used the default naming).

These outputs are also exported, allowing them to be imported by other CloudFormation stacks using the `Fn::ImportValue` function.

## Verify the SAML IdP
<a name="tutorial_saml-idp-using"></a>

Once the SAML IdP has been created, you can verify its configuration and note its ARN for use with federated roles.

1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. In the navigation pane, choose **Identity providers**.

   You should see your newly created SAML IdP in the list.

1. Choose the IdP name to view its details.

   On the IdP detail page, you can see the SAML metadata document and other configuration details.

1. Note the **Provider ARN** displayed on the details page.

   You will need this ARN when creating federated IAM roles that trust this IdP.

1. Review the metadata document to ensure it matches what you provided from your external IdP.

Your SAML IdP is now ready to be used by federated IAM roles. You can create roles that trust this IdP to allow authenticated users from your external IdP to assume those roles and access AWS resources.

## Clean up: delete resources
<a name="tutorial_saml-idp-delete"></a>

As a final step, you'll delete the stack and the resources it contains.

1. Open the CloudFormation console.

1. On the **Stacks** page, choose the stack created from the template, and choose **Delete**, then confirm **Delete**.

   CloudFormation initiates deletion of the stack and all resources it includes.

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

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

The CloudFormation template for this tutorial will create the following resource in your account:

[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): A SAML IdP that establishes trust between AWS and your external IdP.

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

The template includes the following configurable parameters:
+ **IdentityProviderName** - The name for your SAML IdP (leave empty for auto-generated name)

  Example: `CompanyIdP` or `EnterpriseSSO`
+ **IdentityProviderSAMLMetadataDocument** - The SAML metadata document from your external IdP (formatted as a single line)
+ **IdentityProviderAddPrivateKey** - Optional private key for decrypting SAML assertions
+ **IdentityProviderAssertionEncryptionMode** - Optional, sets encryption mode for SAML assertions

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

Save the following JSON or YAML code as a separate file to use as the CloudFormation template for this tutorial.

------
#### [ 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 tutorial: Use an CloudFormation template to create a SAML federated IAM role
<a name="tutorial_saml-federated-role"></a>

When you have an existing SAML Identity Provider (IdP) configured in your AWS account, you can create federated IAM roles that trust that IdP. This tutorial shows you how to use an CloudFormation template to create a SAML federated IAM role that can be assumed by users authenticated through your external IdP.

The template creates a federated IAM role with a trust policy that allows your SAML IdP to assume the role. Users authenticated by your external IdP can assume this role to access AWS resources based on the permissions attached to the role.

The deployed resource consists of the following:
+ A federated IAM role that trusts your existing SAML IdP.
+ Configurable managed policies that can be attached to the role to grant specific permissions.
+ Optional permissions boundary and session duration settings.

## Prerequisites
<a name="tutorial_saml-federated-role-prereqs"></a>

This tutorial assumes that you have the following already in place:
+ An existing SAML IdP configured in your AWS account. If you don't have one, you can create it using the [IAM tutorial: Use an CloudFormation template to create a SAML Identity Provider (IdP)](tutorial_saml-idp.md) tutorial.
+ The ARN of your SAML IdP, which you'll need to specify as a parameter when creating the stack.
+ Python 3.6 or later installed on your local machine to run the Python command used in this tutorial for formatting your IdP's SAML metadata XML file.

## Create a SAML federated role using CloudFormation
<a name="tutorial_saml-federated-role-create"></a>

To create the SAML federated role, you'll create an CloudFormation template and use it to create a stack containing the role.

### Create the template
<a name="tutorial_saml-federated-role-file"></a>

First, create the CloudFormation template.

1. In the [Template](#tutorial_saml-federated-role-template) section, click the copy icon on the **JSON** or **YAML** tab to copy the template contents.

1. Paste the template contents into a new file.

1. Save the file locally.

### Create the stack
<a name="tutorial_saml-federated-role-stack"></a>

Next, use the template you've saved to provision a CloudFormation stack.

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. On the **Stacks** page, from the **Create stack** menu, choose **with new resources (standard)**.

1. Specify the template:

   1. Under **Prerequisite**, choose **Choose an existing template**.

   1. Under **Specify template**, choose **Upload a template file**.

   1. Choose **Choose file**, navigate to the template file, and choose it.

   1. Choose **Next**.

1. Specify the following stack details:

   1. Enter a stack name.

   1. For **SAMLProviderARN**, enter the ARN of your existing SAML IdP. This should be in the format `arn:aws:iam::123456789012:saml-provider/YourProviderName`.

      Example: `arn:aws:iam::123456789012:saml-provider/CompanyIdP`
**Note**  
If you created your SAML IdP using the [IAM tutorial: Use an CloudFormation template to create a SAML Identity Provider (IdP)](tutorial_saml-idp.md) tutorial, you can find the provider ARN in the Outputs tab of that CloudFormation stack.

   1. For **RoleName**, you can leave this empty to auto-generate a name based on the stack name, or enter a custom name for the IAM role.

      Example: `SAML-Developer-Access` or `SAML-ReadOnly-Role`

   1. For other parameters, accept the default values or enter your own based on your requirements:
      + **RoleSessionDuration** - Maximum session duration in seconds (3600-43200, default 7200)

        Example: `14400` (4 hours)
      + **RolePermissionsBoundary** - Optional ARN of a permissions boundary policy

        Example: `arn:aws:iam::123456789012:policy/DeveloperBoundary`
      + **RolePath** - Path for the IAM role (default is /)

        Example: `/saml-roles/`
      + **ManagedPolicy1-5** - Optional ARNs of up to 5 managed policies to attach

        Example for ManagedPolicy1: `arn:aws:iam::aws:policy/ReadOnlyAccess`

        Example for ManagedPolicy2: `arn:aws:iam::123456789012:policy/CustomPolicy`

   1. Choose **Next**.

1. Configure the stack options:

   1. Under **Stack failure options**, choose **Delete all newly created resources**.
**Note**  
Choosing this option prevents you from possibly being billed for resources whose deletion policy specifies they be retained even if the stack creation fails.

   1. Accept all other default values.

   1. Under **Capabilities**, check the box to acknowledge that CloudFormation might create IAM resources in your account.

   1. Choose **Next**.

1. Review the stack details and choose **Submit**.

CloudFormation creates the stack. Once the stack creation is complete, the stack resources are ready to use. You can use the **Resources** tab on the stack detail page to view the resources that were provisioned in your account.

The stack will output the following value, which you can view on the **Outputs** tab:
+ **RoleARN**: The ARN of the created IAM role (for example, `arn:aws:iam::123456789012:role/SAML-Developer-Access` or `arn:aws:iam::123456789012:role/stack-name-a1b2c3d4` if using auto-generated name).

You'll need this role ARN when configuring your IdP to send the appropriate SAML attributes for role assumption.

## Test the SAML federated role
<a name="tutorial_saml-federated-role-using"></a>

Once the SAML federated role has been created, you can verify its configuration and test the federation setup.

1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. In the navigation pane, choose **Roles**.

1. Find and choose your newly created federated role.

   If you provided a custom role name, look for that name. If you left the RoleName parameter empty, the role will have an auto-generated name based on the stack name and a unique identifier.

1. Choose the **Trust relationships** tab to review the trust policy.

   The trust policy should show that your SAML IdP is trusted to assume this role with the condition that the SAML audience (`SAML:aud`) matches `https://signin.aws.amazon.com/saml`.

1. Choose the **Permissions** tab to review the attached policies.

   You can see any managed policies that were attached to the role during creation.

1. Note the **Role ARN** displayed on the role summary page.

   You will need this ARN to configure your external IdP to allow users to assume this role.

Your SAML federated role is now ready to be used. Configure your external IdP to include this role's ARN in SAML assertions, and authenticated users will be able to assume this role to access AWS resources.

## Clean up: delete resources
<a name="tutorial_saml-federated-role-delete"></a>

As a final step, you'll delete the stack and the resources it contains.

1. Open the CloudFormation console.

1. On the **Stacks** page, choose the stack created from the template, and choose **Delete**, then confirm **Delete**.

   CloudFormation initiates deletion of the stack and all resources it includes.

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

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

The CloudFormation template for this tutorial will create the following resource in your account:
+ [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): A federated IAM role that can be assumed by users authenticated through your SAML IdP.

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

The template includes the following configurable parameters:
+ **RoleName** - Name of the IAM Role (leave empty for auto-generated name)
+ **SAMLProviderARN** - ARN of the SAML IdP (required)
+ **RoleSessionDuration** - Maximum session duration in seconds (3600-43200, default 7200)
+ **RolePermissionsBoundary** - Optional ARN of permissions boundary policy
+ **RolePath** - Path for the IAM role (default /)
+ **ManagedPolicy1-5** - Optional ARNs of up to 5 managed policies to attach

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

Save the following JSON or YAML code as a separate file to use as the CloudFormation template for this tutorial.

------
#### [ 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 tutorial: Use an CloudFormation template to create a SAML Identity Provider (IdP) and SAML federated IAM role
<a name="tutorial_saml-idp-and-federated-role"></a>

To get familiar with SAML federation and its capabilities, you'll use an CloudFormation template to set up a SAML Identity Provider (IdP) and associated federated IAM role. This tutorial shows you how to create both resources together in a single stack.

The template creates a SAML IdP that can be used for federated access to AWS resources, along with an IAM role that trusts the SAML provider. Users authenticated by your external IdP can assume this role to access AWS resources.

The deployed resources consist of the following:
+ A SAML IdP configured with your IdP's metadata document.
+ A federated IAM role that trusts the SAML IdP and can be assumed by authenticated users.
+ Configurable managed policies that can be attached to the role to grant specific permissions.

## Prerequisites
<a name="tutorial_saml-idp-and-federated-role-prereqs"></a>

This tutorial assumes that you have the following already in place:
+ Python 3.6 or later installed on your local machine to run the Python command used in this tutorial for formatting your IdP's SAML metadata XML file.
+ A SAML metadata document from your external IdP saved as an XML file.

## Create a SAML IdP and role using CloudFormation
<a name="tutorial_saml-idp-and-federated-role-create"></a>

To create the SAML IdP and federated role, you'll create an CloudFormation template and use it to create a stack containing both resources.

### Create the template
<a name="tutorial_saml-idp-and-federated-role-file"></a>

First, create the CloudFormation template.

1. In the [Template](#tutorial_saml-idp-and-federated-role-template) section, click the copy icon on the **JSON** or **YAML** tab to copy the template contents.

1. Paste the template contents into a new file.

1. Save the file locally.

### Create the stack
<a name="tutorial_saml-idp-and-federated-role-stack"></a>

Next, use the template you've saved to provision a CloudFormation stack.

1. Open the CloudFormation console at [https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/).

1. On the **Stacks** page, from the **Create stack** menu, choose **with new resources (standard)**.

1. Specify the template:

   1. Under **Prerequisite**, choose **Choose an existing template**.

   1. Under **Specify template**, choose **Upload a template file**.

   1. Choose **Choose file**, navigate to the template file, and choose it.

   1. Choose **Next**.

1. Specify the following stack details:

   1. Enter a stack name.

   1. For **IdentityProviderName**, you can leave this empty to auto-generate a name based on the stack name, or enter a custom name for your SAML IdP.

      Example: `CompanyIdP` or `EnterpriseSSO`

   1. For **IdentityProviderSAMLMetadataDocument**, you need to format your SAML metadata XML file as a single line before pasting it into this field. This is necessary because the CloudFormation console requires XML content to be formatted as a single line when passed through console parameters.

      Use the following Python command to reformat your XML file:

      ```
      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
      ```
**Note**  
The IdP's SAML metadata document must be formatted as a single line for console parameter input. The Python command removes line breaks and extra whitespace to create the required format while maintaining all original content and structure.

      Copy the output from the Python command and paste it into the **IdentityProviderSAMLMetadataDocument** field.

      Example of formatted SAML metadata document (abbreviated):

      ```
      <?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. For **RoleName**, you can leave this empty to auto-generate a name based on the stack name, or enter a custom name for the federated IAM role.

      Example: `SAML-Developer-Access` or `SAML-ReadOnly-Role`

   1. For other parameters, accept the default values or enter your own based on your requirements:
      + **IdentityProviderAddPrivateKey** - Optional private key for decrypting SAML assertions
      + **IdentityProviderAssertionEncryptionMode** - Encryption mode for SAML assertions

        Example values: `Allowed`, `Required`, or leave empty for no encryption
      + **RoleSessionDuration** - Maximum session duration in seconds (3600-43200, default 7200)

        Example: `14400` (4 hours)
      + **RolePermissionsBoundary** - Optional ARN of a permissions boundary policy

        Example: `arn:aws:iam::123456789012:policy/DeveloperBoundary`
      + **RolePath** - Path for the IAM role (default is /)

        Example: `/saml-roles/`
      + **RoleManagedPolicy1-5** - Optional ARNs of up to 5 managed policies to attach

        Example for RoleManagedPolicy1: `arn:aws:iam::aws:policy/ReadOnlyAccess`

        Example for RoleManagedPolicy2: `arn:aws:iam::123456789012:policy/CustomPolicy`

   1. Choose **Next**.

1. Configure the stack options:

   1. Under **Stack failure options**, choose **Delete all newly created resources**.
**Note**  
Choosing this option prevents you from possibly being billed for resources whose deletion policy specifies they be retained even if the stack creation fails.

   1. Accept all other default values.

   1. Under **Capabilities**, check the box to acknowledge that CloudFormation might create IAM resources in your account.

   1. Choose **Next**.

1. Review the stack details and choose **Submit**.

CloudFormation creates the stack. Once the stack creation is complete, the stack resources are ready to use. You can use the **Resources** tab on the stack detail page to view the resources that were provisioned in your account.

The stack will output the following values, which you can view on the **Outputs** tab:
+ **RoleARN**: The ARN of the created IAM role (for example, `arn:aws:iam::123456789012:role/SAML-Developer-Access` or `arn:aws:iam::123456789012:role/stack-name-a1b2c3d4` if using auto-generated name).
+ **IdentityProviderARN**: The ARN of the created SAML IdP (for example, `arn:aws:iam::123456789012:saml-provider/CompanyIdP`).

You'll need both of these ARNs when configuring your IdP to send the appropriate SAML attributes for role assumption.

## Test the SAML federation
<a name="tutorial_saml-idp-and-federated-role-using"></a>

Once the SAML IdP and federated role have been created, you can test the federation setup.

1. Open the IAM console at [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/).

1. In the navigation pane, choose **Identity providers**.

   You should see your newly created SAML IdP in the list.

1. Choose the IdP name to view its details.

   On the IdP detail page, you can see the SAML metadata document and other configuration details.

1. In the navigation pane, choose **Roles**.

1. Find and choose your newly created federated role.

   On the role detail page, you can see the trust policy that allows the SAML IdP to assume this role.

1. Choose the **Trust relationships** tab to review the trust policy.

   The trust policy should show that the SAML IdP is trusted to assume this role with the condition that the SAML audience (`SAML:aud`) matches `https://signin.aws.amazon.com/saml`.

## Clean up: delete resources
<a name="tutorial_saml-idp-and-federated-role-delete"></a>

As a final step, you'll delete the stack and the resources it contains.

1. Open the CloudFormation console.

1. On the **Stacks** page, choose the stack created from the template, and choose **Delete**, then confirm **Delete**.

   CloudFormation initiates deletion of the stack and all resources it includes.

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

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

The CloudFormation template for this tutorial will create the following resources in your account:
+ [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): A SAML IdP that establishes trust between AWS and your external 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): A federated IAM role that can be assumed by users authenticated through the SAML IdP.

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

The template includes the following configurable parameters:
+ **IdentityProviderName** - Name of the SAML IdP (leave empty for auto-generated name)
+ **IdentityProviderSAMLMetadataDocument** - SAML metadata document from your IdP (required)
+ **IdentityProviderAddPrivateKey** - Optional private key for decrypting SAML assertions
+ **IdentityProviderAssertionEncryptionMode** - Encryption mode for SAML assertions
+ **RoleName** - Name of the IAM Role (leave empty for auto-generated name)
+ **RolePath** - Path for the IAM role (default /)
+ **RolePermissionsBoundary** - Optional ARN of permissions boundary policy
+ **RoleSessionDuration** - Maximum session duration in seconds (3600-43200, default 7200)
+ **RoleManagedPolicy1-5** - Optional ARNs of up to 5 managed policies to attach

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

Save the following JSON or YAML code as a separate file to use as the CloudFormation template for this tutorial.

------
#### [ 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'
```

------