AWS Identity and Access Management (IAM) allows customers to provide granular access control to resources in AWS. One approach to granting access to resources is to use attribute-based access control (ABAC) to centrally govern and manage access to your AWS resources across accounts. Using ABAC enables you to simplify your authentication strategy by enabling you to scale your authorization strategy by granting access to groups of resources, as specified by tags, as opposed to managing long lists of individual resources. The new ability to include tags in sessions—combined with the ability to tag IAM users and roles—means that you can now incorporate user attributes from your AD FS environment as part of your tagging and authorization strategy.
In other words, you can use ABAC to simplify permissions management at scale. This means administrators can create a reusable policy that applies permissions based on the attributes of the IAM principal (such as tags). For example, as an administrator you can use a single IAM policy that grants developers in your organization access to AWS resources that match the developers’ project tag. As the team of developers adds resources to projects, permissions are automatically applied based on attributes (tags, in this case). As a result, each new resource that gets added requires no update to the IAM permissions policy.
In this blog post, I walk you through how to enable AD FS to pass tags as part of the SAML 2.0 token, so that you can enable ABAC for your AWS resources.
AD FS federated authentication process
The following diagram describes the process that a user follows to authenticate to AWS by using Active Directory and AD FS as the identity provider:
Figure 1: AD FS federation to AWS
A corporate user accesses the corporate Active Directory Federation Services (AD FS) portal sign-in page and provides their Active Directory authentication credentials.
AD FS authenticates the user against Active Directory.
Active Directory returns the user’s information, including Active Directory group membership information.
AD FS dynamically builds a list of Amazon Resource Names (ARNs) for IAM Roles in one or more AWS accounts; these mappings are defined in advance by the administrator and rely on user attributes and Active Directory group memberships.
AD FS sends a signed SAML 2.0 token to the user’s browser with a redirect to post the token to AWS Security Token Service (STS) including the attributes that use define in the claim rules.
The user is authenticated and provided access to the AWS Management Console.
Prerequisites
Attribute-based access control in AWS relies on the use of tags for access-control decisions. Therefore, it’s important to have in place a tagging strategy for your resources. Please see AWS Tagging Strategies.
Implementing ABAC enables organizations to enhance the use of tags from an operational and billing construct to a security construct. Ensuring that tagging is enforced and secure is essential to an enterprise-wide strategy.
Follow these steps to send standard Active Directory attributes to AWS in the SAML token:
Open Server Manager, choose Tools, then choose AD FS Management.
Under Relying Party Trusts, choose AWS.
Choose Edit Claim Issuance Policy, choose Add Rule, choose Send LDAP Attributes as Claims, then choose Next.
On the Edit Rule page, add the requested details. For example, to create a Department Attribute claim rule, add the following details:
Claim rule name: Department Attribute
Attribute Store: Active Directory
LDAP Attribute: Department
Outgoing Claim Type: https://aws.amazon.com/SAML/Attributes/PrincipalTag:<department> (where <department> is the tag that will be passed in the session)
Figure 2: Claim Rule
Repeat the previous step for each attribute you want to send, modifying the details as necessary. For more information about how to configure claim rules, see Configuring Claim Rules in the Windows Server 2012 AD FS Deployment Guide.
Send custom attributes to AWS as part of a federated session
Session Tags in AWS can be derived from Active Directory custom attributes as well as standard attributes, which we demonstrated in the example above. For more information on custom attributes, please How to Create a Custom Attribute in Active Directory.
To ensure that your setup is correct, you should confirm that AD FS is configured correctly:
Perform an identity provider (IdP) initiated authentication. Go to the following URL: https://<your.domain.name>/adfs/ls/idpinitiatedsignon.aspx, where <your.domain.name> is the DNS name of your AD FS server.
Select Sign in to one of the following sites, then choose AWS from the dropdown:
Figure 3: Choose AWS
Choose Sign in, then enter your credentials.
After you’ve successfully logged into AWS, navigate to AWS CloudTrail events within 15 minutes of your login event.
Filter on AssumeRoleWithSAML, then locate your login event and look under principalTags to ensure you see the tags that you configured.
Figure 4: CloudTrail – AssumeRoleWithSAML Event
After you see the tags were sent, you’re ready to use the tags to build your IAM policies.
The following is an example policy that uses multiple tags.
Example: grant IAM users access to your AWS resources by using tags
In this example I will assume that two tags will be passed from AD FS to enable you to build your ABAC tagging strategy: Project and Department. This example assumes that you have multiple teams of developers who need permissions to start and stop specific Amazon Elastic Compute Cloud (Amazon EC2) instances, based on their project allocation. Because these EC2 instances are part of AWS Autoscaling Groups, they come and go depending on scaling conditions; therefore, it would be impractical to try to write policies that refers to lists of individual EC2 instances; writing policies against the tags on the EC2 instances is a more manageable approach. In the following policy, I specify the EC2 actions ec2:StartInstances and ec2:StopInstances in the Action element, and all resources in the Resource element of the policy. In the Condition element of the policy, I use two conditions:
Matching statement where the resource tag project ec2:ResourceTag/project matches the key aws:PrincipalTag for project.
Matching statement where the resource tag project ec2:ResourceTag/department matches the key aws:PrincipalTag for department.
This ensures that the principal is able to start and stop an instance only if the project and department tags match value of the tags on the principal. Attaching this policy to your developer roles or groups simplifies permissions management, because you only need to manage a single policy for all your development teams that require permissions to start and stop instances, and you can rely on tag values to specify the resources.
This policy will ensure that the user can only start and stop EC2 instances for the resources that are assigned to their department and project.
Conclusion
In this post, I’ve shown how you can enable AD FS to pass tags as part of the SAML token, so that you can enable ABAC for your AWS resources to simplify permissions management at scale.
If you have feedback about this blog post, submit comments in the Comments section below. If you have questions about this blog post, start a new thread on the AWS Single Sign-On forum.
Want more AWS Security news? Follow us on Twitter.
Now, your applications and federated users can complete longer running workloads in a single session by increasing the maximum session duration up to 12 hours for an IAM role. Users and applications still retrieve temporary credentials by assuming roles using AWS Security Token Service (AWS STS), but these credentials can now be valid for up to 12 hours when using the AWS SDK or CLI. This change allows your users and applications to perform longer running workloads, such as a batch upload to S3 or a CloudFormation template, using a single session. You can extend the maximum session duration using the IAM console or CLI. Once you increase the maximum session duration, users and applications assuming the IAM role can request temporary credentials that expire when the IAM role session expires.
In this post, I show you how to configure the maximum session duration for an existing IAM role to 4 hours (maximum allowed duration is 12 hours) using the IAM console. I’ll use 4 hours because AWS recommends configuring the session duration for a role to the shortest duration that your federated users would require to access your AWS resources. I’ll then show how existing federated users can use the AWS SDK or CLI to request temporary security credentials that are valid until the role session expires.
Configure the maximum session duration for an existing IAM role to 4 hours
Let’s assume you have an existing IAM role called ADFS-Production that allows your federated users to upload objects to an S3 bucket in your AWS account. You want to extend the maximum session duration for this role to 4 hours. By default, IAM roles in your AWS accounts have a maximum session duration of one hour. To extend a role’s maximum session duration to 4 hours, follow the steps below:
In the left navigation pane, select Roles and then select the role for which you want to increase the maximum session duration. For this example, I select ADFS-Production and verify the maximum session duration for this role. This value is set to 1 hour (3,600 seconds) by default.
Select Edit, and then define the maximum session duration.
Select one of the predefined durations or provide a custom duration. For this example, I set the maximum session duration to be 4 hours.
Select Save changes.
Alternatively, you can use the latest AWS CLI and call Update-Role to set the maximum session duration for the role ADFS-Production. Here’s an example to set the maximum session duration to 14,400 seconds (4 hours).
$ aws iam update-role -–role-name ADFS-Production -–MaxSessionDuration 14400
Now that you’ve successfully extended the maximum session for your IAM role, ADFS-Production, your federated users can use AWS STS to retrieve temporary credentials that are valid for 4 hours to access your S3 buckets.
Access AWS resources with temporary security credentials using AWS CLI/SDK
To enable federated SDK and CLI access for your users who use temporary security credentials, you might have implemented the solution described in the blog post on How to Implement Federated API and CLI Access Using SAML 2.0 and AD FS. That blog post demonstrates how to use the AWS Python SDK and some additional client-side integration code provided in the post to implement federated SDK and CLI access for your users. To enable your users to request longer temporary security credentials, you can make the following changes suggested in this blog to the solution provided in that post.
When calling AssumeRoleWithSAML API to request AWS temporary security credentials, you need to include the DurationSeconds parameter. The value of this parameter is the duration the user requests and, therefore, the duration their temporary security credentials are valid. In this example, I am using boto to request the maximum length of 14,400 seconds (4 hours) using code from the How to Implement Federated API and CLI Access Using SAML 2.0 and AD FS post that I have updated:
# Use the assertion to get an AWS STS token using Assume Role with SAML conn = boto.sts.connect_to_region(region) token = conn.assume_role_with_saml(role_arn, principal_arn, assertion, 14400)
By adding a value for the DurationSeconds parameter in the AssumeRoleWithSAML call, your federated user can retrieve temporary security credentials that are valid for up to 14,400 seconds (4 hours). If you don’t provide this value, the default session duration is 1 hour. If you provide a value of 5 hours for your temporary security credentials, AWS STS will throw an error since this is longer than the role session duration of 4 hours.
Conclusion
I demonstrated how you can configure the maximum session duration for a role from 1 hour (default) up to 12 hours. Then, I showed you how your federated users can retrieve temporary security credentials that are valid for longer durations to access AWS resources using AWS CLI/SDK for up to 12 hours.
Similarly, you can also increase the maximum role session duration for your applications and users who use Web Identity or OpenID Connect Federation or Cross-Account Access with Assume Role. If you have comments about this blog, submit them in the Comments section below. If you have questions or suggestions, please start a new thread on the IAM forum.
Today we’d like to walk you through AWS Identity and Access Management (IAM), federated sign-in through Active Directory (AD) and Active Directory Federation Services (ADFS). With IAM, you can centrally manage users, security credentials such as access keys, and permissions that control which resources users can access. Customers have the option of creating users and group objects within IAM or they can utilize a third-party federation service to assign external directory users access to AWS resources. To streamline the administration of user access in AWS, organizations can utilize a federated solution with an external directory, allowing them to minimize administrative overhead. Benefits of this approach include leveraging existing passwords and password policies, roles and groups. This guide provides a walk-through on how to automate the federation setup across multiple accounts/roles with an Active Directory backing identity store. This will establish the minimum baseline for the authentication architecture, including the initial IdP deployment and elements for federation.
ADFS Federated Authentication Process
The following describes the process a user will follow to authenticate to AWS using Active Directory and ADFS as the identity provider and identity brokers:
Corporate user accesses the corporate Active Directory Federation Services portal sign-in page and provides Active Directory authentication credentials.
AD FS authenticates the user against Active Directory.
Active Directory returns the user’s information, including AD group membership information.
AD FS dynamically builds ARNs by using Active Directory group memberships for the IAM roles and user attributes for the AWS account IDs, and sends a signed assertion to the users browser with a redirect to post the assertion to AWS STS.
Temporary credentials are returned using STS AssumeRoleWithSAML.
The user is authenticated and provided access to the AWS management console.
Configuration Steps
Configuration requires setup in the Identity Provider store (e.g. Active Directory), the identity broker (e.g. Active Directory Federation Services), and AWS. It is possible to configure AWS to federate authentication using a variety of third-party SAML 2.0 compliant identity providers, more information can be found here.
AWS Configuration
The configuration steps outlined in this document can be completed to enable federated access to multiple AWS accounts, facilitating a single sign on process across a multi-account AWS environment. Access can also be provided to multiple roles in each AWS account. The roles available to a user are based on their group memberships in the identity provider (IdP). In a multi-role and/or multi-account scenario, role assumption requires the user to select the account and role they wish to assume during the authentication process.
Identity Provider
A SAML 2.0 identity provider is an IAM resource that describes an identity provider (IdP) service that supports the SAML 2.0 (Security Assertion Markup Language 2.0) standard. AWS SAML identity provider configurations can be used to establish trust between AWS and SAML-compatible identity providers, such as Shibboleth or Microsoft Active Directory Federation Services. These enable users in an organization to access AWS resources using existing credentials from the identity provider.
A SAML identify provider can be configured using the AWS console by completing the following steps.
2. Select SAML for the provider type. Select a provider name of your choosing (this will become the logical name used in the identity provider ARN). Lastly, download the FederationMetadata.xml file from your ADFS server to your client system file (https://yourADFSserverFQDN/FederationMetadata/2007-06/FederationMetadata.xml). Click “Choose File” and upload it to AWS.
3. Click “Next Step” and then verify the information you have entered. Click “Create” to complete the AWS identity provider configuration process.
IAM Role Naming Convention for User Access Once the AWS identity provider configuration is complete, it is necessary to create the roles in AWS that federated users can assume via SAML 2.0. An IAM role is an AWS identity with permission policies that determine what the identity can and cannot do in AWS. In a federated authentication scenario, users (as defined in the IdP) assume an AWS role during the sign-in process. A role should be defined for each access delineation that you wish to define. For example, create a role for each line of business (LOB), or each function within a LOB. Each role will then be assigned a set of policies that define what privileges the users who will be assuming that role will have.
The following steps detail how to create a single role. These steps should be completed multiple times to enable assumption of different roles within AWS, as required.
2. Select “SAML” as the trusted entity type. Click Next Step.
3. Select your previously created identity provider. Click Next: Permissions.
4. The next step requires selection of policies that represent the desired permissions the user should obtain in AWS, once they have authenticated and successfully assumed the role. This can be either a custom policy or preferably an AWS managed policy. AWS recommends leveraging existing AWS access policies for job functions for common levels of access. For example, the “Billing” AWS Managed policy should be utilized to provide financial analyst access to AWS billing and cost information.
5. Provide a name for your role. All roles should be created with the prefix ADFS-<rolename> to simplify the identification of roles in AWS that are accessed through the federated authentication process. Next click, “Create Role”.
Active Directory Configuration
Determining how you will create and delineate your AD groups and IAM roles in AWS is crucial to how you secure access to your account and manage resources. SAML assertions to the AWS environment and the respective IAM role access will be managed through regular expression (regex) matching between your on-premises AD group name to an AWS IAM role.
One approach for creating the AD groups that uniquely identify the AWS IAM role mapping is by selecting a common group naming convention. For example, your AD groups would start with an identifier, for example AWS-, as this will distinguish your AWS groups from others within the organization. Next, include the 12-digit AWS account number. Finally, add the matching role name within the AWS account. Here is an example:
You should do this for each role and corresponding AWS account you wish to support with federated access. Users in Active Directory can subsequently be added to the groups, providing the ability to assume access to the corresponding roles in AWS. If a user is associated with multiple Active Directory groups and AWS accounts, they will see a list of roles by AWS account and will have the option to choose which role to assume. A user will not be able to assume more than one role at a time, but has the ability to switch between them as needed.
Note: Microsoft imposes a limit on the number of groups a user can be a member of (approximately 1,015 groups) due to the size limit for the access token that is created for each security principal. This limitation, however, is not affected by how the groups may or may not be nested.
Active Directory Federation Services Configuration
ADFS federation occurs with the participation of two parties; the identity or claims provider (in this case the owner of the identity repository – Active Directory) and the relying party, which is another application that wishes to outsource authentication to the identity provider; in this case Amazon Secure Token Service (STS). The relying party is a federation partner that is represented by a claims provider trust in the federation service.
Relying Party
You can configure a new relying party in Active Directory Federation Services by doing the following.
1. From the ADFS Management Console, right-click ADFS and select Add Relying Party Trust.
2. In the Add Relying Party Trust Wizard, click Start.
3. Check Import data about the relying party published online or on a local network, enter https://signin.aws.amazon.com/static/saml-metadata.xml, and then click Next. The metadata XML file is a standard SAML metadata document that describes AWS as a relying party.
Note: SAML federations use metadata documents to maintain information about the public keys and certificates that each party utilizes. At run time, each member of the federation can then use this information to validate that the cryptographic elements of the distributed transactions come from the expected actors and haven’t been tampered with. Since these metadata documents do not contain any sensitive cryptographic material, AWS publishes federation metadata at https://signin.aws.amazon.com/static/saml-metadata.xml
4. Set the display name for the relying party and then click Next.
5. We will not choose to enable/configure the MFA settings at this time.
6. Select “Permit all users to access this relying party” and click Next.
7. Review your settings and then click Next.
8. Choose Close on the Finish page to complete the Add Relying Party Trust Wizard. AWS is now configured as a relying party.
Custom Claim Rules
Microsoft Active Directory Federation Services (AD FS) uses Claims Rule Language to issue and transform claims between claims providers and relying parties. A claim is information about a user from a trusted source. The trusted source is asserting that the information is true, and that source has authenticated the user in some manner. The claims provider is the source of the claim. This can be information pulled from an attribute store such as Active Directory (AD). The relying party is the destination for the claims, in this case AWS.
AD FS provides administrators with the option to define custom rules that they can use to determine the behavior of identity claims with the claim rule language. The Active Directory Federation Services (AD FS) claim rule language acts as the administrative building block to help manage the behavior of incoming and outgoing claims. There are four claim rules that need to be created to effectively enable Active Directory users to assume roles in AWS based on group membership in Active Directory.
Right-click on the relying party (in this case Amazon Web Services) and then click Edit Claim Rules
Here are the steps used to create the claim rules for NameId, RoleSessionName, Get AD Groups and Roles.
1. NameId
a) In the Edit Claim Rules for <relying party> dialog box, click Add Rule. b) Select Transform an Incoming Claim and then click Next. c) Use the following settings:
i) Claim rule name: NameId ii) Incoming claim type: Windows Account Name iii) Outgoing claim type: Name ID iv) Outgoing name ID format: Persistent Identifier v) Pass through all claim values: checked
a) Click Add Rule. b) In the Claim rule template list, select Send Claims Using a Custom Rule and then click Next. c) For Claim Rule Name, select Get AD Groups, and then in Custom rule, enter the following:
This custom rule uses a script in the claim rule language that retrieves all the groups the authenticated user is a member of and places them into a temporary claim named http://temp/variable. Think of this as a variable you can access later.
Note: Ensure there’s no trailing whitespace to avoid unexpected results.
4. Role Attributes
a) Unlike the two previous claims, here we used custom rules to send role attributes. This is done by retrieving all the authenticated user’s AD groups and then matching the groups that start with to IAM roles of a similar name. I used the names of these groups to create Amazon Resource Names (ARNs) of IAM roles in my AWS account (i.e., those that start with AWS-). Sending role attributes requires two custom rules. The first rule retrieves all the authenticated user’s AD group memberships and the second rule performs the transformation to the roles claim.
i) Click Add Rule. ii) In the Claim rule template list, select Send Claims Using a Custom Rule and then click Next. iii) For Claim Rule Name, enter Roles, and then in Custom rule, enter the following:
Rule language: c:[Type == "http://temp/variable", Value =~ "(?i)^AWS-([\d]{12})"] => issue(Type = "https://aws.amazon.com/SAML/Attributes/Role", Value = RegExReplace(c.Value, "AWS-([\d]{12})-", "arn:aws:iam::$1:saml-provider/idp1,arn:aws:iam::$1:role/"));
This custom rule uses regular expressions to transform each of the group memberships of the form AWS-<Account Number>-<Role Name> into in the IAM role ARN, IAM federation provider ARN form AWS expects.
Note: In the example rule language above idp1 represents the logical name given to the SAML identity provider in the AWS identity provider setup. Please change this based on the logical name you chose in the IAM console for your identity provider.
Adjusting Session Duration
By default, the temporary credentials that are issued by AWS IAM for SAML federation are valid for an hour. Depending on your organizations security stance, you may wish to adjust. You can allow your federated users to work in the AWS Management Console for up to 12 hours. This can be accomplished by adding another claim rule in your ADFS configuration. To add the rule, do the following:
1. Access ADFS Management Tool on your ADFS Server. 2. Choose Relying Party Trusts, then select your AWS Relying Party configuration. 3. Choose Edit Claim Rules. 4. Choose Add Rule to configure a new rule, and then choose Send claims using a custom rule. Finally, choose Next. 5. Name your Rule “Session Duration” and add the following rule syntax. 6. Adjust the value of 28800 seconds (8 hours) as appropriate.
Rule language: => issue(Type = "https://aws.amazon.com/SAML/Attributes/SessionDuration", Value = "28800");
Note: AD FS 2012 R2 and AD FS 2016 tokens have a sixty-minute validity period by default. This value is configurable on a per-relying party trust basis. In addition to adding the “Session Duration” claim rule, you will also need to update the security token created by AD FS. To update this value, run the following command:
The Parameter “-TokenLifetime” determines the Lifetime in Minutes. In this example, we set the Lifetime to 480 minutes, eight hours.
These are the main settings related to session lifetimes and user authentication. Once updated, any new console session your federated users initiate will be valid for the duration specified in the SessionDuration claim.
API/CLI Access Access to the AWS API and command-line tools using federated access can be accomplished using techniques in the following blog article:
This will enable your users to access your AWS environment using their domain credentials through the AWS CLI or one of the AWS SDKs.
Conclusion In this post, I’ve shown you how to provide identity federation, and thus SSO, to the AWS Management Console for multiple accounts using SAML assertions. With this approach, the AWS Security Token service (STS) will provide temporary credentials (via SAML) for the user to ‘assume’ a role (that they have access to use, as denoted by AD Group membership) that has specific permissions associated; as opposed to providing long-term access credentials to the AWS resources. By adopting this model, you will have a secure and robust IAM approach for accessing AWS resources that align with AWS security best practices.
The following 10 posts were the most viewed AWS Security Blog posts that we published during 2017. You can use this list as a guide to catch up on your AWS Security Blog reading or read a post again that you found particularly useful.
Managing database users though federation allows you to manage authentication and authorization procedures centrally. Amazon Redshift now supports database authentication with IAM, enabling user authentication though enterprise federation. No need to manage separate database users and passwords to further ease the database administration. You can now manage users outside of AWS and authenticate them for access to an Amazon Redshift data warehouse. Do this by integrating IAM authentication and a third-party SAML-2.0 identity provider (IdP), such as AD FS, PingFederate, or Okta. In addition, database users can also be automatically created at their first login based on corporate permissions.
In this post, I demonstrate how you can extend the federation to enable single sign-on (SSO) to the Amazon Redshift data warehouse.
SAML and Amazon Redshift
AWS supports Security Assertion Markup Language (SAML) 2.0, which is an open standard for identity federation used by many IdPs. SAML enables federated SSO, which enables your users to sign in to the AWS Management Console. Users can also make programmatic calls to AWS API actions by using assertions from a SAML-compliant IdP. For example, if you use Microsoft Active Directory for corporate directories, you may be familiar with how Active Directory and AD FS work together to enable federation. For more information, see the Enabling Federation to AWS Using Windows Active Directory, AD FS, and SAML 2.0 AWS Security Blog post.
Amazon Redshift now provides the GetClusterCredentials API operation that allows you to generate temporary database user credentials for authentication. You can set up an IAM permissions policy that generates these credentials for connecting to Amazon Redshift. Extending the IAM authentication, you can configure the federation of AWS access though a SAML 2.0–compliant IdP. An IAM role can be configured to permit the federated users call the GetClusterCredentials action and generate temporary credentials to log in to Amazon Redshift databases. You can also set up policies to restrict access to Amazon Redshift clusters, databases, database user names, and user group.
Amazon Redshift federation workflow
In this post, I demonstrate how you can use a JDBC– or ODBC-based SQL client to log in to the Amazon Redshift cluster using this feature. The SQL clients used with Amazon Redshift JDBC or ODBC drivers automatically manage the process of calling the GetClusterCredentials action, retrieving the database user credentials, and establishing a connection to your Amazon Redshift database. You can also use your database application to programmatically call the GetClusterCredentials action, retrieve database user credentials, and connect to the database. I demonstrate these features using an example company to show how different database users accounts can be managed easily using federation.
The following diagram shows how the SSO process works:
JDBC/ODBC
Authenticate using Corp Username/Password
IdP sends SAML assertion
Call STS to assume role with SAML
STS Returns Temp Credentials
Use Temp Credentials to get Temp cluster credentials
Connect to Amazon Redshift using temp credentials
Walkthrough
Example Corp. is using Active Directory (idp host:demo.examplecorp.com) to manage federated access for users in its organization. It has an AWS account: 123456789012 and currently manages an Amazon Redshift cluster with the cluster ID “examplecorp-dw”, database “analytics” in us-west-2 region for its Sales and Data Science teams. It wants the following access:
Sales users can access the examplecorp-dw cluster using the sales_grp database group
Sales users access examplecorp-dw through a JDBC-based SQL client
Sales users access examplecorp-dw through an ODBC connection, for their reporting tools
Data Science users access the examplecorp-dw cluster using the data_science_grp database group.
Partners access the examplecorp-dw cluster and query using the partner_grp database group.
Partners are not federated through Active Directory and are provided with separate IAM user credentials (with IAM user name examplecorpsalespartner).
Partners can connect to the examplecorp-dw cluster programmatically, using language such as Python.
All users are automatically created in Amazon Redshift when they log in for the first time.
(Optional) Internal users do not specify database user or group information in their connection string. It is automatically assigned.
Data warehouse users can use SSO for the Amazon Redshift data warehouse using the preceding permissions.
For this walkthrough, assume that this company has already configured SSO to their AWS account: 123456789012 for their Active Directory domain demo.examplecorp.com. The Sales and Data Science teams are not required to specify database user and group information in the connection string. The connection string can be configured by adding SAML Attribute elements to your IdP. Configuring these optional attributes enables internal users to conveniently avoid providing the DbUser and DbGroup parameters when they log in to Amazon Redshift.
The user-name attribute can be set up as follows, with a user ID (for example, nancy) or an email address (for example. [email protected]):
Step 2: Create IAM roles for access to the Amazon Redshift cluster
The next step is to create IAM policies with permissions to call GetClusterCredentials and provide authorization for Amazon Redshift resources. To grant a SQL client the ability to retrieve the cluster endpoint, region, and port automatically, include the redshift:DescribeClusters action with the Amazon Redshift cluster resource in the IAM role. For example, users can connect to the Amazon Redshift cluster using a JDBC URL without the need to hardcode the Amazon Redshift endpoint:
Use IAM to create the following policies. You can also use an existing user or role and assign these policies. For example, if you already created an IAM role for IdP access, you can attach the necessary policies to that role. Here is the policy created for sales users for this example:
Allow users to retrieve the cluster endpoint, region, and port automatically for the Amazon Redshift cluster examplecorp-dw. This specification uses the resource format arn:aws:redshift:region:account-id:cluster:clustername. For example, the SQL client JDBC can be specified in the format jdbc:redshift:iam://clustername:region/dbname.
Generates a temporary token to authenticate into the examplecorp-dw cluster. “arn:aws:redshift:us-west-2:123456789012:dbuser:examplecorp-dw/${redshift:DbUser}” restricts the corporate user name to the database user name for that user. This resource is specified using the format: arn:aws:redshift:region:account-id:dbuser:clustername/dbusername.
The Condition block enforces that the AWS user ID should match “AIDIODR4TAW7CSEXAMPLE:${redshift:DbUser}@examplecorp.com”, so that individual users can authenticate only as themselves. The AIDIODR4TAW7CSEXAMPLE role has the Sales_DW_IAM_Policy policy attached.
Allows sales users to join the sales_grp database group through the resource “arn:aws:redshift:us-west-2:123456789012:dbgroup:examplecorp-dw/sales_grp” that is specified in the format arn:aws:redshift:region:account-id:dbgroup:clustername/dbgroupname.
Similar policies can be created for Data Science users with access to join the data_science_grp group in examplecorp-dw. You can now attach the Sales_DW_IAM_Policy policy to the role that is mapped to IdP application for SSO. For more information about how to define the claim rules, see Configuring SAML Assertions for the Authentication Response.
Because partners are not authorized using Active Directory, they are provided with IAM credentials and added to the partner_grp database group. The Partner_DW_IAM_Policy is attached to the IAM users for partners. The following policy allows partners to log in using the IAM user name as the database user name.
“redshift:DbUser“: “${aws:username}” forces an IAM user to use the IAM user name as the database user name.
With the previous steps configured, you can now establish the connection to Amazon Redshift through JDBC– or ODBC-supported clients.
Step 3: Set up database user access
Before you start connecting to Amazon Redshift using the SQL client, set up the database groups for appropriate data access. Log in to your Amazon Redshift database as superuser to create a database group, using CREATE GROUP.
Log in to examplecorp-dw/analytics as superuser and create the following groups and users:
CREATE GROUP sales_grp;
CREATE GROUP datascience_grp;
CREATE GROUP partner_grp;
Use the GRANT command to define access permissions to database objects (tables/views) for the preceding groups.
Step 4: Connect to Amazon Redshift using the JDBC SQL client
Assume that sales user “nancy” is using the SQL Workbench client and JDBC driver to log in to the Amazon Redshift data warehouse. The following steps help set up the client and establish the connection:
Build the JDBC URL with the IAM option in the following format: jdbc:redshift:iam://examplecorp-dw:us-west-2/sales_db
Because the redshift:DescribeClusters action is assigned to the preceding IAM roles, it automatically resolves the cluster endpoints and the port. Otherwise, you can specify the endpoint and port information in the JDBC URL, as described in Configure a JDBC Connection.
Identify the following JDBC options for providing the IAM credentials (see the “Prepare your environment” section) and configure in the SQL Workbench Connection Profile:
plugin_name=com.amazon.redshift.plugin.AdfsCredentialsProvider
idp_host=demo.examplecorp.com (The name of the corporate identity provider host)
idp_port=443 (The port of the corporate identity provider host)
user=examplecorp\nancy(corporate user name)
password=***(corporate user password)
The SQL workbench configuration looks similar to the following screenshot:
Now, “nancy” can connect to examplecorp-dw by authenticating using the corporate Active Directory. Because the SAML attributes elements are already configured for nancy, she logs in as database user nancy and is assigned the sales_grp. Similarly, other Sales and Data Science users can connect to the examplecorp-dw cluster. A custom Amazon Redshift ODBC driver can also be used to connect using a SQL client. For more information, see Configure an ODBC Connection.
Step 5: Connecting to Amazon Redshift using JDBC SQL Client and IAM Credentials
This optional step is necessary only when you want to enable users that are not authenticated with Active Directory. Partners are provided with IAM credentials that they can use to connect to the examplecorp-dw Amazon Redshift clusters. These IAM users are attached to Partner_DW_IAM_Policy that assigns them to be assigned to the public database group in Amazon Redshift. The following JDBC URLs enable them to connect to the Amazon Redshift cluster:
The AutoCreate option automatically creates a new database user the first time the partner logs in. There are several other options available to conveniently specify the IAM user credentials. For more information, see Options for providing IAM credentials.
Step 6: Connecting to Amazon Redshift using an ODBC client for Microsoft Windows
Assume that another sales user “uma” is using an ODBC-based client to log in to the Amazon Redshift data warehouse using Example Corp Active Directory. The following steps help set up the ODBC client and establish the Amazon Redshift connection in a Microsoft Windows operating system connected to your corporate network:
In the Start menu, locate the driver folder or folders:
Amazon Redshift ODBC Driver (32-bit)
Amazon Redshift ODBC Driver (64-bit)
If you installed both drivers, you have a folder for each driver.
Choose ODBC Administrator, and then type your administrator credentials.
To configure the driver for all users on the computer, choose System DSN. To configure the driver for your user account only, choose User DSN.
Choose Add.
Select the Amazon Redshift ODBC driver, and choose Finish. Configure the following attributes:
Data Source Name =any friendly name to identify the ODBC connection
Database=analytics
user=uma(corporate user name)
Auth Type-Identity Provider: AD FS
password=leave blank (Windows automatically authenticates)
Cluster ID: examplecorp-dw
idp_host=demo.examplecorp.com (The name of the corporate IdP host)
This configuration looks like the following:
Choose OK to save the ODBC connection.
Verify that uma is set up with the SAML attributes, as described in the “Set up IdPs and federation” section.
The user uma can now use this ODBC connection to establish the connection to the Amazon Redshift cluster using any ODBC-based tools or reporting tools such as Tableau. Internally, uma authenticates using the Sales_DW_IAM_Policy IAM role and is assigned the sales_grp database group.
Step 7: Connecting to Amazon Redshift using Python and IAM credentials
To enable partners, connect to the examplecorp-dw cluster programmatically, using Python on a computer such as Amazon EC2 instance. Reuse the IAM users that are attached to the Partner_DW_IAM_Policy policy defined in Step 2.
The following steps show this set up on an EC2 instance:
This example uses Python PostgreSQL Driver (PyGreSQL) to connect to your Amazon Redshift clusters. To install PyGreSQL on Amazon Linux, use the following command as the ec2-user:
The following code snippet demonstrates programmatic access to Amazon Redshift for partner users:
#!/usr/bin/env python
"""
Usage:
python redshift-unload-copy.py <config file> <region>
* Copyright 2014, Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Amazon Software License (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/asl/
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
"""
import sys
import pg
import boto3
REGION = 'us-west-2'
CLUSTER_IDENTIFIER = 'examplecorp-dw'
DB_NAME = 'sales_db'
DB_USER = 'examplecorpsalespartner'
options = """keepalives=1 keepalives_idle=200 keepalives_interval=200
keepalives_count=6"""
set_timeout_stmt = "set statement_timeout = 1200000"
def conn_to_rs(host, port, db, usr, pwd, opt=options, timeout=set_timeout_stmt):
rs_conn_string = """host=%s port=%s dbname=%s user=%s password=%s
%s""" % (host, port, db, usr, pwd, opt)
print "Connecting to %s:%s:%s as %s" % (host, port, db, usr)
rs_conn = pg.connect(dbname=rs_conn_string)
rs_conn.query(timeout)
return rs_conn
def main():
# describe the cluster and fetch the IAM temporary credentials
global redshift_client
redshift_client = boto3.client('redshift', region_name=REGION)
response_cluster_details = redshift_client.describe_clusters(ClusterIdentifier=CLUSTER_IDENTIFIER)
response_credentials = redshift_client.get_cluster_credentials(DbUser=DB_USER,DbName=DB_NAME,ClusterIdentifier=CLUSTER_IDENTIFIER,DurationSeconds=3600)
rs_host = response_cluster_details['Clusters'][0]['Endpoint']['Address']
rs_port = response_cluster_details['Clusters'][0]['Endpoint']['Port']
rs_db = DB_NAME
rs_iam_user = response_credentials['DbUser']
rs_iam_pwd = response_credentials['DbPassword']
# connect to the Amazon Redshift cluster
conn = conn_to_rs(rs_host, rs_port, rs_db, rs_iam_user,rs_iam_pwd)
# execute a query
result = conn.query("SELECT sysdate as dt")
# fetch results from the query
for dt_val in result.getresult() :
print dt_val
# close the Amazon Redshift connection
conn.close()
if __name__ == "__main__":
main()
You can save this Python program in a file (redshiftscript.py) and execute it at the command line as ec2-user:
python redshiftscript.py
Now partners can connect to the Amazon Redshift cluster using the Python script, and authentication is federated through the IAM user.
Summary
In this post, I demonstrated how to use federated access using Active Directory and IAM roles to enable single sign-on to an Amazon Redshift cluster. I also showed how partners outside an organization can be managed easily using IAM credentials. Using the GetClusterCredentials API action, now supported by Amazon Redshift, lets you manage a large number of database users and have them use corporate credentials to log in. You don’t have to maintain separate database user accounts.
Although this post demonstrated the integration of IAM with AD FS and Active Directory, you can replicate this solution across with your choice of SAML 2.0 third-party identity providers (IdP), such as PingFederate or Okta. For the different supported federation options, see Configure SAML Assertions for Your IdP.
If you have questions or suggestions, please comment below.
Thiyagarajan Arumugam is a Big Data Solutions Architect at Amazon Web Services and designs customer architectures to process data at scale. Prior to AWS, he built data warehouse solutions at Amazon.com. In his free time, he enjoys all outdoor sports and practices the Indian classical drum mridangam.
You can now enable your users to access Microsoft Office 365 with credentials that you manage in AWS Directory Service for Microsoft Active Directory, also known as AWS Microsoft AD. You can accomplish this by deploying Microsoft Azure Active Directory (AD) Connect and Active Directory Federation Services for Windows Server 2016 (AD FS 2016) with AWS Microsoft AD. AWS Microsoft AD makes it possible and easy for you to build a Windows environment in the AWS Cloud, synchronize your AWS Microsoft AD users into Microsoft Azure AD, and use Office 365, all without needing to create and manage AD domain controllers. Now you can also benefit from the broad set of AWS Cloud services for compute, storage, database, and Internet of Things (IoT) while continuing to use Office 365 business productivity apps—all with a single AD domain.
Office 365 provides different options to support user authentication with identities that come from AD. One common way to do this is to use Azure AD Connect and AD FS together with your AD directory. In this model, you use Azure AD Connect to synchronize user names from AD into Azure AD so that Office 365 can use those identities. To complete this solution, you use AD FS to enable Office 365 to authenticate the identities against your AD directory. Good news: AWS Microsoft AD now supports this model!
In this blog post, we show how to use Azure AD Connect and AD FS with AWS Microsoft AD so that your employees can access Office 365 by using their AD credentials.
Join an Amazon EC2 for Windows Server instance to the AWS Microsoft AD domain you use as your ADSync server. We will show you how to install Azure AD Connect on this instance later.
Using Active Directory Users and Computers on your Management instance, create a standard user named ADFSSVC in your AWS Microsoft AD directory. AD FS uses this user account later.
Note: You must use RDP and sign in with the AWS Microsoft AD admin account using the password you specified when you created your AWS Microsoft AD directory when performing Steps 3 and 6 in this “Prerequisites” section.
The following diagram illustrates the environment you must have in place to implement the solution in this blog post (the numbers in the diagram correspond to Steps 1–8 earlier in this section). We build on this configuration to install and configure Azure AD Connect and AD FS with Azure AD and Office 365.
Note: In this blog post, we use separate Microsoft Windows Server instances on which to run AD FS and Azure AD Connect. You can choose to combine these on a single server, as long as you use Windows Server 2016. Though it is technically possible to use an on-premises server as the AD FS and Azure AD host, such a configuration is counter to the idea of a Windows environment completely in the cloud. Also, this requires configuration of firewall ports and AWS security groups, which is beyond the scope of this blog.
Configuration background
When you create an AWS Microsoft AD directory, AWS exclusively retains the enterprise administrator account of the forest and domain administrator account for the root domain to deliver the directory as a managed service. When you set up your directory, AWS creates an organizational unit (OU) in the directory and delegates administrative privileges for the OU to your admin account. Within this OU, you administer users, groups, computers, Group Policy objects, other devices, and additional OUs as needed. You perform these actions using standard AD administration tools from a computer that is joined to an AWS Microsoft AD domain. Typically, the administration computer is an EC2 instance that you access using RDP, by logging in with your admin account credentials. From your admin account, you can also delegate permissions to other users or groups you create within your OU.
To use Office 365 with AD identities, you use Azure AD Connect to synchronize the AD identities into Azure AD. There are two commonly supported ways to use Azure AD Connect to support Office 365 use. In one model, you synchronize user names only, and you use AD FS to federate authentication from Office 365 to your AD. In the second model, you synchronize user names and passwords from your AD directory to Azure AD, and you do not have to use AD FS. The model supported by AWS Microsoft AD is the first model: synchronize user names only and use AD FS to authenticate from Office 365 to your AWS Microsoft AD. The AD FS model also enables authentication with SaaS applications that support federated authentication (this topic is beyond the scope of this blog post).
Note: Azure AD Connect now has a pass-through model of authentication. Because this was in a preview status at the time of writing this blog post, this authentication model is beyond the scope of this blog post.
In a default AD FS installation, AD FS uses two containers that require special AD permissions that your AWS Microsoft AD administrative account does not have. To address this, you will create two nested containers in your OU for AD FS to use. When you install AD FS, you tell AD FS where to find the containers through a Windows PowerShell parameter.
As described previously, we will now show you how to use Azure AD Connect and AD FS with AWS Microsoft AD with Azure AD and Office 365 in five steps, as illustrated in the following diagram.
Add two containers to AWS Microsoft AD for use by AD FS.
Install AD FS.
Integrate AD FS with Azure AD.
Synchronize users from AWS Microsoft AD to Azure AD with Azure AD Connect.
Sign in to Office 365 by using your Microsoft AD identities.
Step 1: Add two containers to AWS Microsoft AD for use by AD FS
The following steps show how to create the AD containers required by AD FS in your AWS Microsoft AD directory.
From the Management instance:
Generate a random global unique identifier (GUID) using the following Windows PowerShell command.
(New-Guid).Guid
Make a note of the GUID output because it will be required later on. In this case, the GUID is 67734c62-0805-4274-b72b-f7171110cd56.
Create a container named ADFS in your OU. The OU is located in the domain root and it has the same name as the NetBIOS name you specified when you created your AWS Microsoft AD directory. In this example, our OU name is AWS, and our domain is DC=awsexample,DC=com. You create the container by running the following Windows PowerShell command. You must replace the names that are in bold text with the names from your AWS Microsoft AD directory.
Create another AD container in your new ADFS container, and use the previously generated GUID as the name. Do this by running the following Windows PowerShell command. Be sure to replace the names in bold text with the names from your AWS Microsoft AD directory and your GUID. In this example, we replace GUID with 67734c62-0805-4274-b72b-f7171110cd56. The other bold items shown match the names in our example AWS Microsoft AD directory.
To verify that you successfully created the ADFS and GUID containers, open Active Directory Users and Computers and navigate to the containers you created. Your root domain, OU name, and GUID name should match your AWS Microsoft AD configuration.
Note: If you do not see the ADFS and GUID containers, turn on Advanced Features by choosing View in the Active Directory Users and Computers tool, and then choosing Advanced Features.
Step 2: Install AD FS
In this section, we show how to install AD FS by using Windows PowerShell commands. First, though, select a federation service name for your AD FS server. You can create your federation service name by adding a short name (for example, sts) followed by your domain name (for example, awsexample.com). In this example, we use sts.awsexample.com as the federation service name.
Using your AWS Microsoft AD admin account, open an RDP session to your ADFS instance, run Windows PowerShell as a local administrator, and complete the following steps:
Install the Windows feature, AD FS, by running the following Windows PowerShell command. This command only adds the components needed to install your ADFS server later.
Install-WindowsFeature ADFS-Federation
Now that you have installed AD FS, you must obtain a certificate for use when you configure your ADFS server. The AD FS certificate plays an important role to secure communication between the ADFS server and clients, and to ensure tokens issued by the ADFS server are secured. AWS recommends that you use a certificate from a trusted Certificate Authority (CA).
In our example, we use the SSL certificate, sts.awsexample.com. It is important to note that the common name and subject alternative name (SAN) must include the federation service name we plan to use for the AD FS server. In our example, the name is sts.awsexample.com.
Choose File, choose Add/Remove snap-in, and choose Add.
For Add StandaloneSnap-in, choose Certificates and then choose Add.
For the Certificates snap-in, choose Computer account and then choose Next.
Choose Finish, and then choose OK to load the Certificates snap In.
Expand Certificates (Local Computer).
Right-click Personal, choose All Tasks, and then choose Import.
On the Certificate Import Wizard, choose Next.
Choose Browse to locate and select your certificate that has been given by your CA. Choose Next.
Ensure Certificate store is set to Personal, and choose Next.
Choose Finish and OK to complete the installation of the certificate on the AD FS server.
Next you need to retrieve the Thumbprint value of the newly installed certificate and save it for use when you configure your ADFS server. Follow the remaining steps:
In the Certificates console window, expand Personal, and choose Certificates.
Right-click the certificate, and then choose Open.
Choose the Details tab to locate the Thumbprint
Note: In this case, we will copy our certificate Thumbprint, d096652327cfa18487723ff61040c85c7f57f701, and save it in Windows Notepad.
Open an RDP session to your ADFS server by using the admin account for your AWS Microsoft AD directory. Install AD FS by running the following Windows PowerShell command. You must replace the bold strings in the command with the GUID you created in Step 1 and the names from your AWS Microsoft AD directory.
Enter the AD FS standard user account credentials for the ADFSSVC user and save it in the script variable, $svcCred, by running the following Windows PowerShell command.
$svcCred = (get-credential)
Type the Microsoft AD administrator credentials of the Admin user and save it in the script variable, $localAdminCred, by running the following Windows PowerShell command.
$localAdminCred = (get-credential)
Install the AD FS server by running the following Windows PowerShell command. You must replace the bold items with the Thumbprint ID from your certificate, and replace the federation service name with the federation service name you chose earlier. For our example, the federation service name is awsexample.com and we copy our certificate Thumbprint, d096652327cfa18487723ff61040c85c7f57f701, from where we saved it in Windows Notepad.
Note: Be sure to remove any empty spaces in the certificate Thumbprint value.
Create a DNS A record for use with AD FS. This record resolves the federation service name to the public IP address you assign to your ADFS instance. You must create the DNS A record at the DNS hosting provider that hosts your domain. In the following example, sts.awsexample.com is the federation service name and 54.x.x.x is the public IP address of our AD FS instance.
Hostname: awsexample.com
Record Type:A
IP Address:x.x.x
Enable the AD FS sign-in page by running the following Windows PowerShell command.
To verify that the AD FS sign-in page works, open a browser on the AD FS instance, and sign in on the AD FS sign-in page (https://<myfederation service name>/AD FS/ls/IdpInitiatedSignOn.aspx) by using your AWS Microsoft AD admin account. In our example, the federation service name (<my federation service name> in the sign-in page URL) is sts.awsexample.com.
Step 3: Integrate AD FS with Azure AD
The following steps show you how to connect AD FS with Office 365 by connecting to Azure AD with Windows PowerShell and federating the custom domain.From the ADFS instance, make sure you run Windows PowerShell as a local administrator and complete the following steps:
Connect to Azure AD using Windows PowerShell. Federate the custom domain you added and verified in Azure AD by running the following two Windows PowerShell commands. You must update the items in bold text with the names from your AWS Microsoft AD directory. For our example, our AD FS instance’s Fully Qualified Domain Name (FQDN) is adfsserver.awsexample.com, and our domain name is awsexample.com.
Step 4: Synchronize users from AWS Microsoft AD to Azure AD with Azure AD Connect
The following steps show you how to install and customize Azure AD Connect to synchronize your AWS Microsoft AD identities to Azure AD for use with Office 365.Open an RDP session to your ADSync instance by using your AWS Microsoft AD admin user account:
On the Welcome page of the Azure AD Connect Wizard, accept the license terms and privacy notice, and then choose Continue.
On the Express Settings page, choose Customize.
On the Install required components page, choose Install.
On the User sign-in page, choose Do not configure and then choose Next.
On the Connect to Azure AD page, enter your Office 365 global administrator account credentials and then choose Next.
On the Connect your directories page, choose Active Directory as the Directory Type, and then choose your Microsoft AD Forest as your Forest. Choose Add Directory.
At the prompt, enter your AWS Microsoft AD admin account credentials, and then choose OK.
Now that you have added the AWS Microsoft AD directory, choose Next.
On the Azure AD sign-in configuration page, choose Next.
Note: AWS recommends the userPrincipalName (UPN) attribute for use by AWS Microsoft AD users when they sign in to Azure AD and Office 365. The UPN attribute format combines the user’s login name and the UPN-suffix of an AWS Microsoft AD user. The UPN suffix is the domain name of your AWS Microsoft AD domain and the same domain name you added and verified with Azure AD.
In the following example from the Active Directory Users and Computers tool, the user’s UPN is [email protected], which is a combination of the user’s login name, awsuser, with the UPN-suffix, @awsexample.com.
On the Domain and OU filtering page, choose Sync selected domains and OUs, choose the Users OU under your NetBIOS OU, and then choose Next.
On the Uniquely identifying your users page, choose Next.
On the Filter users and devices page, choose Next.
On the Optional features page, choose Next.
On the Ready to configure page, choose Start the synchronization process when configuration completes, and then choose Install.
The Azure AD Connect installation has now completed. Choose Exit.
Note: By default, the Azure AD Connect sync scheduler runs every 30 minutes to synchronize your AWS Microsoft AD identities to Azure AD. You can tune the scheduler by opening a Windows PowerShell session as an administrator and running the appropriate Windows PowerShell commands. For more information, go to Azure AD Connect Sync Scheduler.
Tip: Do you need to synchronize a change immediately? You can manually start a sync cycle outside the scheduled sync cycle from the Azure AD Connect sync instance. Open a Windows PowerShell session as an administrator and run the following Windows PowerShell commands.
Step 5: Sign in to Office 365 by using your AWS Microsoft AD identities
The following steps show you how to sign in to Office 365 using AD FS as the authentication method with your AWS Microsoft AD user account. In this example, we assign a license to the AWS Microsoft AD user account, [email protected], in the Office 365 admin center. We then sign in to Office 365 by using the AWS Microsoft AD user account UPN, [email protected].
Using a computer on the internet, open a browser and complete the following steps:
Sign in with the AWS Microsoft AD user account at https://portal.office.com. When entering the UPN of the AWS Microsoft AD user account, you will be redirected to your ADFS server sign-in page to complete user authentication.
On the AD FS sign-in page, enter your UPN and the password of the AWS Microsoft AD user account.
You have successfully signed in to Office 365 using your AWS Microsoft AD user account!
Summary
In this blog post, we showed how to use Azure AD Connect and AD FS with AWS Microsoft AD so that your employees can access Office 365 using their AD credentials. Now that you have Azure AD Connect and AD FS in place, you also might want to explore how to build upon this infrastructure to add sign-in for other Software as a Service (SaaS) applications that are compatible with AD FS. For example, this blog post explains how you can provide your users single sign-on access to Amazon AppStream by using AD FS.
Want to provide users with single sign-on access to AppStream 2.0 using existing enterprise credentials? Active Directory Federation Services (AD FS) 3.0 can be used to provide single sign-on for Amazon AppStream 2.0 using SAML 2.0.
You can use your existing Active Directory or any SAML 2.0–compliant identity service to set up single sign-on access of AppStream 2.0 applications for your users. Identity federation using SAML 2.0 is currently available in all AppStream 2.0 regions.
This post explains how to configure federated identities for AppStream 2.0 using AD FS 3.0.
Walkthrough
After setting up SAML 2.0 federation for AppStream 2.0, users can browse to a specially crafted (AD FS RelayState) URL and be taken directly to their AppStream 2.0 applications.
When users sign in with this URL, they are authenticated against Active Directory. After they are authenticated, the browser receives a SAML assertion as an authentication response from AD FS, which is then posted by the browser to the AWS sign-in SAML endpoint. Temporary security credentials are issued after the assertion and the embedded attributes are validated. The temporary credentials are then used to create the sign-in URL. The user is redirected to the AppStream 2.0 streaming session. The following diagram shows the process.
The user browses to https://applications.exampleco.com. The sign-on page requests authentication for the user.
The federation service requests authentication from the organization’s identity store.
The identity store authenticates the user and returns the authentication response to the federation service.
On successful authentication, the federation service posts the SAML assertion to the user’s browser.
The user’s browser posts the SAML assertion to the AWS Sign-In SAML endpoint (https://signin.aws.amazon.com/saml). AWS Sign-In receives the SAML request, processes the request, authenticates the user, and forwards the authentication token to the AppStream 2.0 service.
Using the authentication token from AWS, AppStream 2.0 authorizes the user and presents applications to the browser.
In this post, use domain.local as the name of the Active Directory domain. Here are the steps in this walkthrough:
Configure AppStream 2.0 identity federation.
Configure the relying trust.
Create claim rules.
Enable RelayState and forms authentication.
Create the AppStream 2.0 RelayState URL and access the stack.
Test the configuration.
Prerequisites
This walkthrough assumes that you have the following prerequisites:
An instance joined to a domain with the “Active Directory Federation Services” role installed and post-deployment configuration completed
Familiarity with AppStream 2.0 resources
Configure AppStream 2.0 identity federation
First, create an AppStream 2.0 stack, as you reference the stack in upcoming steps. Name the stack ExampleStack. For this walkthrough, it doesn’t matter which underlying fleet you associate with the stack. You can create a fleet using one of the example Amazon-AppStream2-Sample-Image images available, or associate an existing fleet to the stack.
Get the AD FS metadata file
The first thing you need is the metadata file from your AD FS server. The metadata file is a signed document that is used later in this guide to establish the relying party trust. Don’t edit or reformat this file.
To download and save this file, navigate to the following location, replacing <FQDN_ADFS_SERVER> with your AD FS s fully qualified server name.
In the IAM console, choose Identity providers, Create provider.
On the Configure Provider page, for Provider Type, choose SAML. For Provider Name, type ADFS01 or similar name. Choose Choose File to upload the metadata document previously downloaded. Choose Next Step.
Verify the provider information and choose Create.
You need the Amazon Resource Name (ARN) of the identity provider (IdP) to configure claims rules later in this walkthrough. To get this, select the IdP that you just created. On the summary page, copy the value for Provider ARN. The ARN is in the following format:
Next, configure a policy with permissions to the AppStream 2.0 stack. This is the level of permissions that federated users have within AWS.
In the IAM console, choose Policies, Create Policy, Create Your Own Policy.
For Policy Name, enter a descriptive name. For Description, enter the level of permissions. For Policy Document, you customize the Region-Code, AccountID (without hyphens), and case-sensitive Stack-Name values.
For Region Codes, use one of the following values based on the region you are using AppStream 2.0 (the available regions for AppStream 2.0):
us-east-1
us-west-2
eu-west-1
ap-northeast-1
Choose Create Policy and you should see the following notification:
Create an IAM role
Here, you create a role that relates to an Active Directory group assigned to your AppStream 2.0 federated users. For this configuration, Active Directory groups and AWS roles are case-sensitive. Here you create an IAM Role named “ExampleStack” and an Active Directory group named in the format AWS-AccountNumber-RoleName, for example AWS-012345678910-ExampleStack.
In the IAM console, choose Roles, Create new role.
On the Select Role type page, choose Role for identity provider access. Choose Select next to Grant Web Single Sign-On (WebSSO) access to SAML providers.
On the Establish Trust page, make sure that the SAML provider that you just created (such as ADFS01) is selected. For Attribute and Value, keep the default values.
On the Verify Role Trust page, the Federated value matches the ARN noted previously for the principal IdP created earlier. The SAML: aud value equals https://signin.aws.amazon.com/saml, as shown below. This is prepopulated and does not require any change. Choose Next Step.
On the Attach policy page, attach the policy that you created earlier granting federated users access only to the AppStream 2.0 stack. In this walkthrough, the policy was named AppStream2_ExampleStack.
After selecting the correct policy, choose Next Step.
On the Set role name and review page, name the role ExampleStack. You can customize this naming convention, as I explain later when I create the claims rules.
You can describe the role as desired. Ensure that the trusted entities match the AD FS IdP ARN, and that the policy attached is the policy created earlier granting access only to this stack.
Choose Create Role.
Important: If you grant more than the stack permissions to federated users, you can give them access to other areas of the console as well. AWS strongly recommends that you attach policies to a role that grants access only to the resources to be shared with federated users.
For example, if you attach the AdministratorAccess policy instead of AppStream2_ExampleStack, any AppStream 2.0 federated user in the ExampleStack Active Directory group has AdministratorAccess in your AWS account. Even though AD FS routes users to the stack, users can still navigate to other areas of the console, using deep links that go directly to specific console locations.
Next, create the Active Directory group in the format AWS-AccountNumber-RoleName using the “ExampleStack” role name that you just created. You reference this Active Directory group in the AD FS claim rules later using regex. For Group scope, choose Global. For Group type, choose Security
Note: To follow this walkthrough exactly, name your Active Directory group in the format “AWS-AccountNumber-ExampleStack” replacing AccountNumber with your AWS AccountID (without hyphens). For example:
AWS-012345678910-ExampleStack
Configure the relying party trust
In this section, you configure AD FS 3.0 to communicate with the configurations made in AWS.
Open the AD FS console on your AD FS 3.0 server.
Open the context (right-click) menu for AD FS and choose Add Relying Party Trust…
On the Welcome page, choose Start. On the Select Data Source page, keep Import data about the relying party published online or on a local network checked. For Federation metadata address (host name or URL), type the following link to the SAML metadata to describe AWS as a relying party and then choose Next.
On the Specify Display Name page, for Display name, type “AppStream 2.0 – ExampleStack” or similar value. For Notes, provide a description. Choose Next.
On the Configure Multi-factor Authentication Now? page, choose I do not want to configure multi-factor authentication settings for this relying party trust at this time. Choose Next.
Because you are controlling access to the stack using an Active Directory group, and IAM role with an attached policy, on the Choose Issuance Authorization Rules page, check Permit all users to access this relying party. Choose Next.
On the Ready to Add Trust page, there shouldn’t be any changes needed to be made. Choose Next.
On the Finish page, clear Open the edit Claim Rules dialog for this relying party trust when the wizard closes. You open this later.
Next, you add the https://signin.aws.amazon.com/saml URL is listed on the Identifiers tab within the properties of the trust. To do this, open the context (right-click) menu for the relying party trust that you just created and choose Properties.
On the Monitoring tab and clear Monitor relying party. Choose Apply. On the Identifiers tab, for Relying party identifier, add https://signin.aws.amazon.com/saml and choose OK.
Create claim rules
In this section, you create four AD FS claim rules, which identify accounts, set LDAP attributes, get the Active Directory groups, and match them to the role created earlier.
In the AD FS console, expand Trust Relationships, choose Relying Party Trusts, and then select the relying party trust that you just created (in this case, the display name is AppStream 2.0 – ExampleStack). Open the context (right-click) menu for the relying party trust and choose Edit Claim Rules. Choose Add Rule.
Rule 1: Name ID
This claim rule tells AD FS the type of expected incoming claim and how to send the claim to AWS. AD FS receives the UPN and tags it as the Name ID when it’s forwarded to AWS. This rule interacts with the third rule, which fetches the user groups.
Claim rule template: Transform an Incoming Claim
Configure Claim Rule values:
Claim Rule Name: Name ID
Incoming Claim Type: UPN
Outgoing Claim Type: Name ID
Outgoing name ID format: Persistent Identifier
Pass through all claim values: selected
Rule 2: RoleSessionName
This rule sets a unique identifier for the user. In this case, use the E-Mail-Addresses values.
Claim rule template: Send LDAP Attributes as Claims
This rule converts the value of the Active Directory group starting with AWS-AccountNumber prefix to the roles known by AWS. For this rule, you need the AWS IdP ARN that you noted earlier. If your IdP in AWS was named ADFS01 and the AccountID was 012345678910, the ARN would look like the following:
arn:aws:iam::012345678910:saml-provider/ADFS01
Claim rule template: Send Claims Using a Custom Rule
Configure Claim Rule values:
Claim Rule Name: Roles
Custom Rule:
c:[Type == "http://temp/variable", Value =~ "(?i)^AWS-"]
=> issue(Type = "https://aws.amazon.com/SAML/Attributes/Role", Value = RegExReplace(c.Value, "AWS-012345678910-", "arn:aws:iam::012345678910:saml-provider/ADFS01,arn:aws:iam::019517892450:role/"));
Change arn:aws:iam::012345678910:saml-provider/ADFS01 to the ARN of your AWS IdP
Change 012345678910 to the ID (without hyphens) of the AWS account.
In this walkthrough, “AWS-” returns the Active Directory groups that start with the AWS- prefix, then removes AWS-012345678910- leaving ExampleStack left on the Active Directory Group name to match the ExampleStack IAM role. To customize the role naming convention, for example to name the IAM Role ADFS-ExampleStack, add “ADFS-” to the end of the role ARN at the end of the rule: arn:aws:iam::012345678910:role/ADFS-.
You should now have four claims rules created:
NameID
RoleSessionName
Get Active Directory Groups
Role
Enable RelayState and forms authentication
By default, AD FS 3.0 doesn’t have RelayState enabled. AppStream 2.0 uses RelayState to direct users to your AppStream 2.0 stack.
On your AD FS server, open the following with elevated (administrator) permissions:
In the Microsoft.IdentityServer.Servicehost.exe.config file, find the section <microsoft.identityServer.web>. Within this section, add the following line:
In the AD FS console, verify that forms authentication is enabled. Choose Authentication Policies. Under Primary Authentication, for Global Settings, choose Edit.
For Extranet, choose Forms Authentication. For Intranet, do the same and choose OK.
On the AD FS server, from an elevated (administrator) command prompt, run the following commands sequentially to stop, then start the AD FS service to register the changes:
net stop adfssrv
net start adfssrv
Create the AppStream 2.0 RelayState URL and access the stack
Now that RelayState is enabled, you can generate the URL.
I have created an Excel spreadsheet for RelayState URL generation, available as RelayGenerator.xlsx. This spreadsheet only requires the fully qualified domain name for your AD FS server, account ID (without hyphens), stack name (case-sensitive), and the AppStream 2.0 region. After all the inputs are entered, the spreadsheet generates a URL in the blue box, as shown in the screenshot below. Copy the entire contents of the blue box to retrieve the generated RelayState URL for AD FS.
Alternatively, if you do not have Excel, there are third-party tools for RelayState URL generation. However, they do require some customization to work with AppStream 2.0. Example customization steps for one such tool are provided below.
CodePlex has an AD FS RelayState generator, which downloads an HTML file locally that you can use to create the RelayState URL. The generator says it’s for AD FS 2.0; however, it also works for AD FS 3.0. You can generate the RelayState URL manually but if the syntax or case sensitivity is incorrect even slightly, it won’t work. I recommend using the tool to ensure a valid URL.
When you open the URL generator, clear out the default text fields. You see a tool that looks like the following:
To generate the values, you need three pieces of information:
IDP URL String
Relying Party Identifier
Relay State / Target App
IDP URL String
The IDP URL string is the URL you use to hit your AD FS sign-on page. For example:
Ultimately, the URL looks like the following example, which is for us-east-1, with a stack name of ExampleStack, and an account ID of 012345678910. The stack name is case-sensitive.
The generated RelayState URL can now be saved and used by users to log in directly from anywhere that can reach the AD FS server, using their existing domain credentials. After they are authenticated, users are directed seamlessly to the AppStream 2.0 stack.
Test the configuration
Create a new AD user in Domain.local named Test User, with a username TUser and an email address. An email address is required based on the claim rules.
Next, add TUser to the AD group you created for the AWS-012345678910-ExampleStack stack.
Next, navigate to the RelayState URL and log in with domain\TUser.
After you log in, you are directed to the streaming session for the ExampleStack stack. As an administrator, you can disassociate and associate different fleets of applications to this stack, without impacting federation, and deliver different applications to this group of federated users.
Because the policy attached to the role only allows access to this AppStream 2.0 stack, if a federated user were to try to access another section of the console, such as Amazon EC2, they would discover that they are not authorized to see (describe) any resources or perform any actions, as shown in the screenshot below. This is why it’s important to grant access only to the AppStream 2.0 stack.
Configurations for AD FS 4.0
If you are using AD FS 4.0, there are a few differences from the procedures discussed earlier.
Do not customize the following file as described in the Enable RelayState and forms authentication of the AD FS 3.0 guide:
Enable the IdP-initiated sign-on page that is used when generating the RelayState URL. To do this, open an elevated PowerShell terminal and run the following command:
To register these changes with AD FS, restart the AD FS service from an elevated PowerShell terminal (or command prompt):
net stop adfssrv
net start adfssrv
After these changes are made, AD FS 4.0 should now work for AppStream 2.0 identity federation.
Troubleshooting
If you are still encountering errors with your setup, below are common error messages you may see, and configuration areas that I recommend that you check.
Invalid policy
Unable to authorize the session. (Error Code: INVALID_AUTH_POLICY);Status Code:401
This error message can occur when the IAM policy does not permit access to the AppStream 2.0 stack. However, it can also occur when the stack name is not entered into the policy or RelayState URL using case-sensitive characters. For example, if your stack name is “ExampleStack” in AppStream 2.0 and the policy has “examplestack” or if the Relay State URL has “examplestack” or any capitalization pattern other than the exact stack name, you see this error message.
Invalid relay state
Error: Bad Request.(Error Code: INVALID_RELAY_STATE);Status Code:400
If you are receiving this error message, there is likely to be another issue in the Relay State URL. It could be related to case sensitivity (other than the stack name). For example, https://relay-state-region-endoint?stack=stackname&accountId=aws-account-id-without-hyphens.
Unable to authorize the session. Cross account access is not allowed. (Error Code: CROSS_ACCOUNT_ACCESS_NOT_ALLOWED);Status Code:401
If you see this error message, check to make sure that the AccountId number is correct in the Relay State URL.
Summary
In this post, you walked through enabling AD FS 3.0 for AppStream 2.0 identity federation. You should now be able to configure AD FS 3.0 or 4.0 for AppStream 2.0 identity federation. If you have questions or suggestions, please comment below.
To govern federated access to your AWS resources, it’s a common practice to use Microsoft Active Directory (AD) groups. When using AD groups, establishing federation requires the number of AD groups to be equal to the number of your AWS accounts multiplied by the number of roles in each of your AWS accounts. As you can imagine, this can result in the creation of a very large number of AD groups to manage federated access.
However, some organizations have limits on how many AD groups they can create. For example, an organization might need to keep its AD group hierarchy reasonably flat and avoid a deep nesting of groups. Such a situation needs a solution that doesn’t require you to create exponentially more AD groups while still allowing you to use access control and automated user integration.
In this blog post, I provide step-by-step instructions for integrating AWS Identity and Access Management (IAM) with Microsoft Active Directory Federation Services (AD FS) by using AD user attributes, allowing you to establish federated access without expanding your total number of AD groups. Your organization’s enterprise administrator probably has existing processes in place for managing AD group memberships and provisioning, and you can extend these processes to the management of AD user attributes and the reduction of your organization’s dependency on AD groups.
You have created an identity provider (IdP) in your AWS account using your XML file (https://<your-server-name-here>/FederationMetadata/2007-06/FederationMetadata.xml) from your AD FS server. Remember the name of your IdP because you will use it later in this solution.
You have created the appropriate IAM roles in your AWS account, which will be used for federated access.
After you satisfy these prerequisites, you can proceed to the next section of this post to configure your AD users and AD FS server.
Solution overview
To benefit fully from the solution in this post, your AD and AD FS environment should look similar to what is shown in the following diagram. I focus this post on AD users and claim rules in an AD FS server. AD FS claim rules provide the logic to identify who has been correctly set up in AD with the appropriate user attributes to sign in via AD FS to the AWS Management Console.
In the preceding diagram:
An AD user (let’s call him Bob) browses to the AD FS sample site (https://Fully.Qualified.Domain.Name.Here/adfs/ls/IdpInitiatedSignOn.aspx) inside this domain.
The sign-in page authenticates Bob against AD. If Bob is already authenticated or using a domain joined workstation, he also might be prompted for his AD user name and password.
Bob’s browser receives a SAML assertion in the form of an authentication response from AD FS. Bob’s access is authorized based on his AD group membership or on AD user attributes configured on his account.
Bob’s browser automatically posts the SAML assertion to the AWS sign-in endpoint for SAML (https://signin.aws.amazon.com/saml). The endpoint uses the AssumeRoleWithSAML API to request temporary security credentials and then constructs a sign-in URL for the AWS Management Console using those credentials.
Bob’s browser receives the sign-in URL and redirects to the AWS Management Console.
Deploy the solution
A. Configure an AD user’s account
Because the AD user attributes hold all the associated AWS account and role information when using this solution, you will start by configuring an AD user’s accounts.
To edit the user attributes in an AD user’s account:
On your AD server, in the Active Directory Users and Computers console, go to View > Advanced Features in Active Directory Users and Computers to see the Attribute editor tab.
For AD user Bob, edit one attribute using the built-in AD attribute editor. The attribute I am using is url, which is a multi-valued string. If you use another AD user attribute, consider how you will need to modify your AD FS claim rules later because different attributes may return the values differently back to the AD FS server. The name of the AD user attribute will be used in the AD FS claim rules later in this post.
Bob has two AWS accounts: 111122223333 and 444455556666. Each of Bob’s AWS accounts has two roles: AWS-Dev and AWS-ReadOnly. I have configured Bob’s url attribute with the corresponding values associated with his AWS accounts and roles. As part of the attribute entries, I prefixed each entry with AWS- to have a unique identifier. As shown in the following screenshot, I added the entries one at a time so that each value can be returned back to my AD FS server:
AWS-111122223333-Dev
AWS-111122223333-ReadOnly
AWS-444455556666-Dev
AWS-444455556666-ReadOnly
Bob also requires an email address because that information will be used in the role session name when Bob signs in to the AWS Management Console via his chosen AWS account and associated role. We use Bob’s email address only because it’s a common user attribute most users have and is also unique across users. The unique identifier is then forwarded by AD FS to be used by AWS as a unique value for users. If you have enabled AWS CloudTrail, the role session name is captured in CloudTrail and allows for ease of identification of who assumed the role and subsequent API calls the user or role might have executed on the platform (for example, ec2:terminateinstance).
Now that you have configured Bob’s account, you will configure the AD FS server claim rules.
B. Configure the AD FS server claim rules
Because this blog post assumes your environment is already up and running and to ensure that you can follow along, I am providing example Windows PowerShell code that you can run on your AD FS server. This code allows you to choose a conventional approach by using AD groups in AD FS claim rules, or for the purposes of this post, to use AD FS claim rules with AD user attributes. If you use the AD group approach on your AD FS server with the example code, your AD group naming convention must be: AWS-YourAccountNumber–YourRoleName. If you have already created claim rules for AWS on your AD FS server, I encourage you to run this code against a different AD FS server that has no existing AWS rules.
To configure the AD FS claim rules:
Open the AD FS console. You can find it by searching for ad, as shown in the following screenshot.
Expand Trust Relationships and choose Relying Party Trusts.
Run the example Windows PowerShell code from the command prompt in the same directory where you extracted the .zip file. The following screenshot shows a list of the example files from the .zip file.
Run the 01-Configure-ADFS-AD-User-URL-mapping.ps1 Windows PowerShell script to set up the AD FS claim rules. Note: Run this script with Administrative permissions. A log file is generated to which you can refer, as shown in the following screenshot.
After you run the Windows PowerShell script, you will see the new relying party trust that has been created in your AD FS configuration for Amazon Web Services, as shown in the following screenshot.
Right-click Amazon Web Services & AD User URL and choose Edit Claim Rules.
The following screenshot shows what your AD FS server claim rules should look like now.
About these four claim rules:
Claim rule 1 captures the Windows account name of the current user whose attributes will then be queried further with claim rule 3.
Claim rule 2 captures Bob’s email address for use in the role session name.
Claim rule 3 queries the current user’s URL attributes to identify which account and role the user is authorized to assume access to. These URL attribute values are then stored in a variable (http://temp/variable) for use in claim rule 4.
Claim rule 4 works by matching the first pattern match, ([^d]{12}), to $1 and the second pattern match, (\w*), to $2 for each entry in http://temp/variable. With this final rule, you define the resulting value for the AWS role attribute in a dynamic way, which allows the configuration to scale to support virtually any number of AWS accounts and IAM roles without further configuration within AD FS. By using these claim rules, you query, store, and then convert the values in the URL attributes to the IAM role attributes that AWS expects.
At the beginning of this post, I mentioned that you need to remember the name of the IdP you created in your AWS account, and now is when you will use your IdP’s name. Replace myADFS, highlighted in the following code, with the name of your IdP. (When modifying the rules, be careful not to insert any additional spaces because they can cause claim rules to not work as designed.)
Go to the AD FS sign-in page (https://Fully.Qualified.Domain.Name.Here/adfs/ls/IdpInitiatedSignOn.aspx) to test Bob’s federated access. Note that you might see a certificate warning if the server uses a locally self-signed certificate from Internet Information Services.
To test Bob’s federated access:
Choose Sign in to one of the following sites, choose Amazon Web Services& AD User URL from the list, and then choose Continue to Sign In.
If prompted, type Bob’s user name and password. You will be redirected to sign in to the Amazon Web Services AD FS page previously defined when you set up the AD FS relying party trusts.
After you authenticate to the server as Bob, your browser is redirected to https://signin.aws.amazon.com/saml, and you can choose which of Bob’s accounts and roles to use from. Choose a role and then choose Sign In.
You have signed in as Bob, and his email address now appears as part of the role session name, as shown in the following screenshot.
You can now see Bob’s email address used in the role session name. If you have enabled CloudTrail, the role session name is captured in CloudTrail and allows you to easily identify who assumed the role. If Bob wants to switch to a different account or role, he can return to his AD FS sign-in page (https://Fully.Qualified.Domain.Name.Here/adfs/ls/IdpInitiatedSignOn.aspx) and choose an alternative account or role.
Summary
In this blog post, I demonstrated how to use dynamic resolution of federated access using AD user attributes to scale your configuration and support a large number of AWS accounts and associated IAM roles. This is a powerful technique for managing a large number of AWS accounts and the federated access of associated AD users. Even though I demonstrate the integration of IAM with AD FS and AD, you can replicate this solution across your choice of SAML federated access technology, such as Shibboleth or OpenLDAP.
If you have comments about this blog post, submit them in the “Comments” section below. If you have implementation or troubleshooting questions, start a new thread on the IAM forum.
Contributors: Richard Threlkeld, Gene Ting, Stefano Buliani
The full code for both scenarios—including SAM templates—can be found at the samljs-serverless-sample GitHub repository. We highly recommend you use the SAM templates in the GitHub repository to create the resources, opitonally you can manually create them.
This is the second part of a two part series for using SAML providers in your application and receiving short-term credentials to access AWS Services. These credentials can be limited with IAM roles so the users of the applications can perform actions like fetching data from databases or uploading files based on their level of authorization. For example, you may want to build a JavaScript application that allows a user to authenticate against Active Directory Federation Services (ADFS). The user can be granted scoped AWS credentials to invoke an API to display information in the application or write to an Amazon DynamoDB table.
The scenario in the last blog post may be sufficient for many organizations but, due to size restrictions, some browsers may drop part or all of a query string when sending a large number of claims in the SAMLResponse. Additionally, for auditing and logging reasons, you may wish to relay SAML assertions via POST only and perform parsing in the backend before sending credentials to the client. This scenario allows you to perform custom business logic and validation as well as putting tracking controls in place.
In this post, we want to show you how these requirements can be achieved in a Serverless application. We also show how different challenges (like XML parsing and JWT exchange) can be done in a Serverless application design. Feel free to mix and match, or swap pieces around to suit your needs.
This scenario uses the following services and features:
Cognito for unique ID generation and default role mapping
S3 for static website hosting
API Gateway for receiving the SAMLResponse POST from ADFS
Lambda for processing the SAML assertion using a native XML parser
DynamoDB conditional writes for session tracking exceptions
STS for credentials via Lambda
KMS for signing JWT tokens
API Gateway custom authorizers for controlling per-session access to credentials, using JWT tokens that were signed with KMS keys
JavaScript-generated SDK from API Gateway using a service proxy to DynamoDB
RelayState in the SAMLRequest to ADFS to transmit the CognitoID and a short code from the client to your AWS backend
At a high level, this solution is similar to that of Scenario 1; however, most of the work is done in the infrastructure rather than on the client.
ADFS still uses a POST binding to redirect the SAMLResponse to API Gateway; however, the Lambda function does not immediately redirect.
The Lambda function decodes and uses an XML parser to read the properties of the SAML assertion.
If the user’s assertion shows that they belong to a certain group matching a specified string (“Prod” in the sample), then you assign a role that they can assume (“ADFS-Production”).
Lambda then gets the credentials on behalf of the user and stores them in DynamoDB as well as logging an audit record in a separate table.
Lambda then returns a short-lived, signed JSON Web Token (JWT) to the JavaScript application.
The application uses the JWT to get their stored credentials from DynamoDB through an API Gateway custom authorizer.
The architecture you build in this tutorial is outlined in the following diagram.
First, a user visits your static website hosted on S3. They generate an ephemeral random code that is transmitted during redirection to ADFS, where they are prompted for their Active Directory credentials.
Upon successful authentication, the ADFS server redirects the SAMLResponse assertion, along with the code (as the RelayState) via POST to API Gateway.
The Lambda function parses the SAMLResponse. If the user is part of the appropriate Active Directory group (AWS-Production in this tutorial), it retrieves credentials from STS on behalf of the user.
The credentials are stored in a DynamoDB table called SAMLSessions, along with the short code. The user login is stored in a tracking table called SAMLUsers.
The Lambda function generates a JWT token, with a 30-second expiration time signed with KMS, then redirects the client back to the static website along with this token.
The client then makes a call to an API Gateway resource acting as a DynamoDB service proxy that retrieves the credentials via a DeleteItem call. To make this call, the client passes the JWT in the authorization header.
A custom authorizer runs to validate the token using the KMS key again as well as the original random code.
Now that the client has credentials, it can use these to access AWS resources.
Tutorial: Backend processing and audit tracking
Before you walk through this tutorial you will need the source code from the samljs-serverless-sample Github Repository. You should use the SAM template provided in order to streamline the process but we’ll outline how you you would manually create resources too. There is a readme in the repository with instructions for using the SAM template. Either way you will still perform the manual steps of KMS key configuration, ADFS enablement of RelayState, and Amazon Cognito Identity Pool creation. The template will automate the process in creating the S3 website, Lambda functions, API Gateway resources and DynamoDB tables.
We walk through the details of all the steps and configuration below for illustrative purposes in this tutorial calling out the sections that can be omitted if you used the SAM template.
KMS key configuration
To sign JWT tokens, you need an encrypted plaintext key, to be stored in KMS. You will need to complete this step even if you use the SAM template.
In the IAM console, choose Encryption Keys, Create Key.
For Alias, type sessionMaster.
For Advanced Options, choose KMS, Next Step.
For Key Administrative Permissions, select your administrative role or user account.
For Key Usage Permissions, you can leave this blank as the IAM Role (next section) will have individual key actions configured. This allows you to perform administrative actions on the set of keys while the Lambda functions have rights to just create data keys for encryption/decryption and use them to sign JWTs.
Take note of the Key ID, which is needed for the Lambda functions.
IAM role configuration
You will need an IAM role for executing your Lambda functions. If you are using the SAM template this can be skipped. The sample code in the GitHub repository under Scenario2 creates separate roles for each function, with limited permissions on individual resources when you use the SAM template. We recommend separate roles scoped to individual resources for production deployments. Your Lambda functions need the following permissions:
If you are not using the SAM template, create the following three Lambda functions from the GitHub repository in /Scenario2/lambda using the following names and environment variables. The Lambda functions are written in Node.js.
GenerateKey_awslabs_samldemo
ProcessSAML_awslabs_samldemo
SAMLCustomAuth_awslabs_samldemo
The functions above are built, packaged, and uploaded to Lambda. For two of the functions, this can be done from your workstation (the sample commands for each function assume OSX or Linux). The third will need to be built on an AWS EC2 instance running the current Lambda AMI.
GenerateKey_awslabs_samldemo
This function is only used one time to create keys in KMS for signing JWT tokens. The function calls GenerateDataKey and stores the encrypted CipherText blob as Base64 in DynamoDB. This is used by the other two functions for getting the PlainTextKey for signing with a Decrypt operation.
This function only requires a single file. It has the following environment variables:
KMS_KEY_ID: Unique identifier from KMS for your sessionMaster Key
SESSION_DDB_TABLE: SAMLSessions
ENC_CONTEXT: ADFS (or something unique to your organization)
This is an API Gateway custom authorizer called after the client has been redirected to the website as part of the login workflow. This function calls a GET against the service proxy to DynamoDB, retrieving credentials. The function uses the KMS key signing validation of the JWT created in the ProcessSAML_awslabs_samldemo function and also validates the random code that was generated at the beginning of the login workflow.
You must install the dependencies before zipping this function up. It has the following environment variables:
SESSION_DDB_TABLE: SAMLSessions
ENC_CONTEXT: ADFS (or whatever was used in GenerateKey_awslabs_samldemo)
This function is called when ADFS sends the SAMLResponse to API Gateway. The function parses the SAML assertion to select a role (based on a simple string search) and extract user information. It then uses this data to get short-term credentials from STS via AssumeRoleWithSAML and stores this information in a SAMLSessions table and tracks the user login via a SAMLUsers table. Both of these are DynamoDB tables but you could also store the user information in another AWS database type, as this is for auditing purposes. Finally, this function creates a JWT (signed with the KMS key) which is only valid for 30 seconds and is returned to the client as part of a 302 redirect from API Gateway.
This function needs to be built on an EC2 server running Amazon Linux. This function leverages two main external libraries:
nJwt: Used for secure JWT creation for individual client sessions to get access to their records
libxmljs: Used for XML XPath queries of the decoded SAMLResponse from AD FS
Libxmljs uses native build tools and you should run this on EC2 running the same AMI as Lambda and with Node.js v4.3.2; otherwise, you might see errors. For more information about current Lambda AMI information, see Lambda Execution Environment and Available Libraries.
After you have the correct AMI launched in EC2 and have SSH open to that host, install Node.js. Ensure that the Node.js version on EC2 is 4.3.2, to match Lambda. If your version is off, you can roll back with NVM.
After you have set up Node.js, run the following command:
yum install -y make gcc*
Now, create a /saml folder on your EC2 server and copy up ProcessSAML.js and package.json from /Scenario2/lambda/ProcessSAML to the EC2 server. Here is a sample SCP command:
cd ProcessSAML/
ls
package.json ProcessSAML.js
scp -i ~/path/yourpemfile.pem ./* [email protected]:/home/ec2-user/saml/
Then you can SSH to your server, cd into the /saml directory, and run:
npm install
A successful build should look similar to the following:
Finally, zip up the package and create the function using the following AWS CLI command and these environment variables. Configure the CLI with your credentials as needed.
SESSION_DDB_TABLE: SAMLSessions
ENC_CONTEXT: ADFS (or whatever was used in GenerateKeyawslabssamldemo)
PRINCIPAL_ARN: Full ARN of the AD FS IdP created in the IAM console
USER_DDB_TABLE: SAMLUsers
REDIRECT_URL: Endpoint URL of your static S3 website (or CloudFront distribution domain name if you did that optional step)
zip –r saml.zip .
aws lambda create-function – function-name ProcessSAML_awslabs_samldemo – runtime nodejs4.3 – role LAMBDA_ROLE_ARN – handler ProcessSAML.handler – timeout 10 – memory-size 512 – zip-file fileb://saml.zip –environment Variables={USER_DDB_TABLE=SAMLUsers,SESSION_DDB_TABLE= SAMLSessions,REDIRECT_URL=<your S3 bucket and test page path>,ID_HASH=us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX,ENC_CONTEXT=ADFS,PRINCIPAL_ARN=<your ADFS IdP ARN>}
If you built the first two functions on your workstation and created the ProcessSAML_awslabs_samldemo function separately in the Lambda console before building on EC2, you can update the code after building on with the following command:
This scenario uses STS directly to assume a role. You will need to complete this step even if you use the SAM template. Modify the trust policy, as you did before when Amazon Cognito was assuming the role. In the GitHub repository sample code, ProcessSAML.js is preconfigured to filter and select a role with “Prod” in the name via the selectedRole variable.
This is an example of business logic you can alter in your organization later, such as a callout to an external mapping database for other rules matching. In this tutorial, it corresponds to the ADFS-Production role that was created.
In the IAM console, choose Roles and open the ADFS-Production Role.
Edit the Trust Permissions field and replace the content with the following:
If you end up using another role (or add more complex filtering/selection logic), ensure that those roles have similar trust policy configurations. Also note that the sample policy above purposely uses an array for the federated provider matching the IdP ARN that you added. If your environment has multiple SAML providers, you could list them here and modify the code in ProcessSAML.js to process requests from different IdPs and grant or revoke credentials accordingly.
DynamoDB table creation
If you are not using the SAM template, create two DynamoDB tables:
SAMLSessions: Temporarily stores credentials from STS. Credentials are removed by an API Gateway Service Proxy to the DynamoDB DeleteItem call that simultaneously returns the credentials to the client.
SAMLUsers: This table is for tracking user information and the last time they authenticated in the system via ADFS.
The following AWS CLI commands creates the tables (indexed only with a primary key hash, called identityHash and CognitoID respectively):
After the tables are created, you should be able to run the GenerateKey_awslabs_samldemo Lambda function and see a CipherText key stored in SAMLSessions. This is only for convenience of this post, to demonstrate that you should persist CipherText keys in a data store and never persist plaintext keys that have been decrypted. You should also never log plaintext keys in your code.
API Gateway configuration
If you are not using the SAM template, you will need to create API Gateway resources. If you have created resources for Scenario 1 in Part I, then the naming of these resources may be similar. If that is the case, then simply create an API with a different name (SAMLAuth2 or similar) and follow these steps accordingly.
In the API Gateway console for your API, choose Authorizers, CustomAuthorizer.
Select your region and enter SAMLCustomAuth_awslabs_samldemo for the Lambda function. Choose a friendly name like JWTParser and ensure that Identity token source is method.request.header.Authorization. This tells the custom authorizer to look for the JWT in the Authorization header of the HTTP request, which is specified in the JavaScript code on your S3 webpage. Save the changes.
Now it’s time to wire up the Lambda functions to API Gateway.
In the API Gateway console, choose Resources, select your API, and then create a Child Resource called SAML. This includes a POST and a GET method. The POST method uses the ProcessSAML_awslabs_samldemo Lambda function and a 302 redirect, while the GET method uses the JWTParser custom authorizer with a service proxy to DynamoDB to retrieve credentials upon successful authorization.
Create a POST method. For Integration Type, choose Lambda and add the ProcessSAML_awslabs_samldemo Lambda function. For Method Request, add headers called RelayState and SAMLResponse.
Delete the Method Response code for 200 and add a 302. Create a response header called Location. In the Response Models section, for Content-Type, choose application/json and for Models, choose Empty.
Delete the Integration Response section for 200 and add one for 302 that has a Method response status of 302. Edit the response header for Location to add a Mapping value of integration.response.body.location.
Finally, in order for Lambda to capture the SAMLResponse and RelayState values, choose Integration Request.
In the Body Mapping Template section, for Content-Type, enter application/x-www-form-urlencoded and add the following template:
Create a GET method with an Integration Type of Service Proxy. Select the region and DynamoDB as the AWS Service. Use POST for the HTTP method and DeleteItem for the Action. This is important as you leverage a DynamoDB feature to return the current records when you perform deletion. This simultaneously allows credentials in this system to not be stored long term and also allows clients to retrieve them. For Execution role, use the Lambda role from earlier or a new role that only has IAM scoped permissions for DeleteItem on the SAMLSessions table.
Save this and open Method Request.
For Authorization, select your custom authorizer JWTParser. Add in a header called COGNITO_ID and save the changes.
In the Integration Request, add in a header name of Content-Type and a value for Mapped of ‘application/x-amzn-json-1.0‘ (you need the single quotes surrounding the entry).
Next, in the Body Mapping Template section, for Content-Type, enter application/json and add the following template:
Inspect this closely for a moment. When your client passes the JWT in an Authorization Header to this GET method, the JWTParser Custom Authorizer grants/denies executing a DeleteItem call on the SAMLSessions table.
ADF
If it is granted, then there needs to be an item to delete the reference as a primary key to the table. The client JavaScript (seen in a moment) passes its CognitoID through as a header called COGNITO_ID that is mapped above. DeleteItem executes to remove the credentials that were placed there via a call to STS by the ProcessSAML_awslabs_samldemo Lambda function. Because the above action specifies ALL_OLD under the ReturnValues mapping, DynamoDB returns these credentials at the same time.
Save the changes and open your /saml resource root.
Choose Actions, Enable CORS.
In the Access-Control-Allow-Headers section, add COGNITO_ID into the end (inside the quotes and separated from other headers by a comma), then choose Enable CORS and replace existing CORS headers.
When completed, choose Actions, Deploy API. Use the Prod stage or another stage.
In the Stage Editor, choose SDK Generation. For Platform, choose JavaScript and then choose Generate SDK. Save the folder someplace close. Take note of the Invoke URL value at the top, as you need this for ADFS configuration later.
Website configuration
If you are not using the SAM template, create an S3 bucket and configure it as a static website in the same way that you did for Part I.
If you are using the SAM template this will automatically be created for you however the steps below will still need to be completed:
In the source code repository, edit /Scenario2/website/configs.js.
Ensure that the identityPool value matches your Amazon Cognito Pool ID and the region is correct.
Leave adfsUrl the same if you’re testing on your lab server; otherwise, update with the AD FS DNS entries as appropriate.
Update the relayingPartyId value as well if you used something different from the prerequisite blog post.
Next, download the minified version of the AWS SDK for JavaScript in the Browser (aws-sdk.min.js) and place it along with the other files in /Scenario2/website into the S3 bucket.
Copy the files from the API Gateway Generated SDK in the last section to this bucket so that the apigClient.js is in the root directory and lib folder is as well. The imports for these scripts (which do things like sign API requests and configure headers for the JWT in the Authorization header) are already included in the index.html file. Consult the latest API Gateway documentation if the SDK generation process updates in the future
ADFS configuration
Now that the AWS setup is complete, modify your ADFS setup to capture RelayState information about the client and to send the POST response to API Gateway for processing. You will need to complete this step even if you use the SAM template.
If you’re using Windows Server 2008 with ADFS 2.0, ensure that Update Rollup 2 is installed before enabling RelayState. Please see official Microsoft documentation for specific download information.
After Update Rollup 2 is installed, modify %systemroot%\inetpub\adfs\ls\web.config. If you’re on a newer version of Windows Server running AD FS 3.0, modify %systemroot%\ADFS\Microsoft.IdentityServer.Servicehost.exe.config.
Find the section in the XML marked <Microsoft.identityServer.web> and add an entry for <useRelayStateForIdpInitiatedSignOn enabled="true">. If you have the proper ADFS rollup or version installed, this should allow the RelayState parameter to be accepted by the service provider.
In the ADFS console, open Relaying Party Trusts for Amazon Web Services and choose Endpoints.
For Binding, choose POST and for Invoke URL,enter the URL to your API Gateway from the stage that you noted earlier.
At this point, you are ready to test out your webpage. Navigate to the S3 static website Endpoint URL and it should redirect you to the ADFS login screen. If the user login has been recent enough to have a valid SAML cookie, then you should see the login pass-through; otherwise, a login prompt appears. After the authentication has taken place, you should quickly end up back at your original webpage. Using the browser debugging tools, you see “Successful DDB call” followed by the results of a call to STS that were stored in DynamoDB.
As in Scenario 1, the sample code under /scenario2/website/index.html has a button that allows you to “ping” an endpoint to test if the federated credentials are working. If you have used the SAM template this should already be working and you can test it out (it will fail at first – keep reading to find out how to set the IAM permissions!). If not go to API Gateway and create a new Resource called /users at the same level of /saml in your API with a GET method.
For Integration type, choose Mock.
In the Method Request, for Authorization, choose AWS_IAM. In the Integration Response, in the Body Mapping Template section, for Content-Type, choose application/json and add the following JSON:
Before using this new Mock API as a test, configure CORS and re-generate the JavaScript SDK so that the browser knows about the new methods.
On the /saml resource root and choose Actions,Enable CORS.
In the Access-Control-Allow-Headers section, add COGNITO_ID into the endpoint and then choose Enable CORS and replace existing CORS headers.
Choose Actions, Deploy API. Use the stage that you configured earlier.
In the Stage Editor, choose SDK Generation and select JavaScript as your platform. Choose Generate SDK.
Upload the new apigClient.js and lib directory to the S3 bucket of your static website.
One last thing must be completed before testing (You will need to complete this step even if you use the SAM template) if the credentials can invoke this mock endpoint with AWS_IAM credentials. The ADFS-Production Role needs execute-api:Invoke permissions for this API Gateway resource.
In the IAM console, choose Roles, and open the ADFS-Production Role.
For testing, you can attach the AmazonAPIGatewayInvokeFullAccess policy; however, for production, you should scope this down to the resource as documented in Control Access to API Gateway with IAM Permissions.
After you have attached a policy with invocation rights and authenticated with AD FS to finish the redirect process, choose PING.
If everything has been set up successfully you should see an alert with information about the user agent.
Final Thoughts
We hope these scenarios and sample code help you to not only begin to build comprehensive enterprise applications on AWS but also to enhance your understanding of different AuthN and AuthZ mechanisms. Consider some ways that you might be able to evolve this solution to meet the needs of your own customers and innovate in this space. For example:
Completing the CloudFront configuration and leveraging SSL termination for site identification. See if this can be incorporated into the Lambda processing pipeline.
Attaching a scope-down IAM policy if the business rules are matched. For example, the default role could be more permissive for a group but if the user is a contractor (username with –C appended) they get extra restrictions applied when assumeRoleWithSaml is called in the ProcessSAML_awslabs_samldemo Lambda function.
Changing the time duration before credentials expire on a per-role basis. Perhaps if the SAMLResponse parsing determines the user is an Administrator, they get a longer duration.
Passing through additional user claims in SAMLResponse for further logical decisions or auditing by adding more claim rules in the ADFS console. This could also be a mechanism to synchronize some Active Directory schema attributes with AWS services.
Granting different sets of credentials if a user has accounts with multiple SAML providers. While this tutorial was made with ADFS, you could also leverage it with other solutions such as Shibboleth and modify the ProcessSAML_awslabs_samldemo Lambda function to be aware of the different IdP ARN values. Perhaps your solution grants different IAM roles for the same user depending on if they initiated a login from Shibboleth rather than ADFS?
The Lambda functions can be altered to take advantage of these options which you can read more about here. For more information about ADFS claim rule language manipulation, see The Role of the Claim Rule Language on Microsoft TechNet.
We would love to hear feedback from our customers on these designs and see different secure application designs that you’re implementing on the AWS platform.
Contributors: Richard Threlkeld, Gene Ting, Stefano Buliani
The full code for this blog, including SAM templates—can be found at the samljs-serverless-sample GitHub repository. We highly recommend you use the SAM templates in the github repository to create the resources, opitonally you can manually create them.
Want to enable SAML federated authentication? You can use the AWS platform to exchange SAML assertions for short-term, temporary AWS credentials.
When you build enterprise web applications, it is imperative to ensure that authentication and authorization (AuthN and AuthZ) is done consistently and follows industry best practices. At AWS, we have built a service called Amazon Cognito that allows you to create unique Identities for users and grants them short-term credentials for interacting with AWS services. These credentials are tied to roles based on IAM policies so that you can grant or deny access to different resources.
In this post, we walk you through different strategies for federating SAML providers with Amazon Cognito. Additionally, you can federate with different types of identity providers (IdP). These IdPs could be third-party social media services like Facebook, Twitter, and others. You can also federate with the User Pools service of Amazon Cognito and create your own managed user directory (including registration, sign-In, MFA, and other workflows).
For example, you may want to build a JavaScript application that allows a user to authenticate against Active Directory Federation Services (ADFS). The user can be granted scoped AWS credentials to invoke an API to display information in the application or write to an Amazon DynamoDB table. In the Announcing SAML Support for Amazon Cognito AWS Mobile blog post, we introduced the new SAML functionality with some sample code in Java as well as Android and iOS snippets. This post goes deeper into customizing the ADFS flow and JavaScript samples.
Scenarios
In this post, we cover the scenario of “client-side” flow, where SAML assertions are passed through Amazon API Gateway and the browser code retrieves credentials directly from Amazon Cognito Identity. In the next, related post, we’ll cover “backend request logic”, where the SAML assertions and credentials selection take place in AWS Lambda functions allowing for customized business logic and audit tracking.
The full code for this scenario, including SAM templates—can be found at the samljs-serverless-sample GitHub repository. We highly recommend you use the SAM templates in the github repository to create the resources, opitonally you can manually create them.
Although this is a Serverless system, you can substitute certain components for traditional compute types, like EC2 instances, to integrate with ADFS. For terms and definitions used in this post, see Claims-based identity term definitions.
Prerequisites
For this blog post, you need ADFS running in your environment. Use the following references:
Verify that you can authenticate with user example\bob for both the ADFS-Dev and ADFS-Production groups via the sign-in page (https://localhost/adfs/IdpInitiatedSignOn.aspx).
Before you start the tutorials, review a few AWS and SAML details, starting with the IAM roles that were created in the prerequisites. You may create a new IAM role and AD group for your application. For this post, we use the ADFS-Dev and ADFS-Production from the previous Enabling Federation to AWS Using Windows Active Directory, ADFS, and SAML 2.0 post as a learning exercise.
In the IAM console, choose Roles, select ADFS-Dev, and choose Trust Relationships tab to see the following code:
This policy allows a user authenticated with the SAML IdP called “ADFS” to assume the role. It also includes a condition where the audience restriction (contained in the SAML assertion) has an AudienceRestriction of https://signin.aws.amazon.com/saml. The SAML assertion is sent to AWS with a header called SAMLResponse from ADFS via an HTTP POST. If you have followed the federation post listed in the Prerequisites section, this would have been configured in the ADFS console when you specified the AWS metadata URL as the relaying party. For more information about this process, see Configuring SAML Assertions for the Authentication Response.
After authentication, ADFS automatically redirects to the Relaying Party Application realm.
In the above screenshot, we used Chrome to view the SAMLResponse value after authenticating. You can do this in other browsers, as documented in How to View a SAML Response in Your Browser for Troubleshooting. There are “SAML Decoders” available on the Internet that allow you to view values such as Audience, Roles, and Destination if you paste in SAMLResponse. In Part II of this blog series we will walk through how this can be done programmatically.
Redirect from ADFS to a Serverless website followed by Amazon Cognito federation
The scenario in this first blog is less complex; for many organizational requirements, it might be the best route. Users authenticate against ADFS and receive AWS credentials from Amazon Cognito so that they can perform actions in your app. This sample application:
Exposes a login mechanism to authenticate against ADFS and captures the SAMLResponse header. This is automatically kicked off when the user visits the website hosted on S3.
Changes the ADFS-Dev role trust policy to allow users that are in the AWS-gDev Active Directory group to receive temporary AWS credentials from Amazon Cognito.
Adds a mechanism in the code to select the application role for the user. In this post, the chosen role is ADFS-Dev.
Note that #3 is happening in the federated AWS console example when the user clicks the radio button after the redirect from the IdpInitiatedSignOn.aspx webpage that ADFS provides. For more information, see the Enabling Federation to AWS Using Windows Active Directory, ADFS, and SAML 2.0 post on the AWS Security blog. If users are only in a single Active Directory group, then #3 can be omitted, as the SAMLResponse will never contain multiple roles in the ADFS claims. Amazon Cognito can automatically assume the single role.
The architecture you build is outlined in the following diagram.
Tutorial: Redirect from ADFS to a Serverless website followed by Amazon Cognito federation
First, set up a Serverless website and initiate a login workflow to get credentials. Use S3 for hosting the single page web app.
S3 bucket creation
In the S3 console, choose Create bucket and enter a unique bucket name. The following example bucket is called “serverlessweb” but yours can be something different.
After the bucket is created, on the details page, choose Properties,Edit bucket policy.
Add the following policy, replacing YOURBUCKETNAMEGOESHERE. This policy allows anyone to issue GET requests on any of the objects that it contains, such as HTML or JavaScript files. Web browsers issue GET requests when they try to access websites and this policy allows users to load the resources.
Choose Static Website Hosting, Enable website hosting. Type in ‘index.html’ and ‘error.html’ in the appropriate forms.
At this point, add a simple HTML file to your bucket and browse to https://YOURBUCKETNAME.s3-website-REGION.amazonaws.com and see the page (replace YOURBUCKETNAME and REGION as appropriate). As a starting point, you can use the following template. First, download the AWS JavaScript SDK and also place it in the bucket.
After downloading the minified version of the JavaScript SDK (aws-sdk.min.js) and placing it in the bucket along with the above HTML file, verify that your page loads without any errors.
(Optional) CloudFront distribution set up
Before going further, you should set up one more thing: a CloudFront distribution. The S3 static web hosting is HTTP, and CloudFront or another CDN provider of your choice provides SSL.
While this isn’t mandatory to get these examples functional (you can do redirects from API Gateway to HTTP sites), you should have end-to-end HTTPS for your site and an AuthN/AuthZ system. Setting this up is minimal work and should be done.
In the CloudFront console, create a new distribution of type Web.
For Viewer Protocol Policy, choose HTTPS Only.
For Origin Domain Name, select your S3 bucket.
As a best practice, choose Restrict Bucket Access so that the bucket is protected from direct browsing. Then you can access the site via the listed Domain Name for the CloudFront distribution.
Login mechanism
Next, build a login mechanism. Your website can either prompt the user to log in with a button or automatically check to see if credentials are valid and redirect them with a login workflow.
This example takes the second approach, using JavaScript to check the status immediately when the user visits the page and redirect them if it’s an initial visit to get their credentials. Because users also get redirected to the page during the login process from API Gateway, the workflow needs to redirect users to the ADFS login as well as capture incoming SAMLResponse data based on some capture progress state. An example flow might look like the following:
function loginWorkflow(){
var activelogin = sessionStorage.getItem('activelogin');
if (activelogin=='inProgress'){ //ADFS login redirect from API Gateway
var samlResponse = getParameterByName('SAMLResponse');
sessionStorage.removeItem(‘activelogin’);
if (samlResponse != null){
getSamlCredentials(samlResponse.replace(/\s/g, ''));
}
}
else if (activelogin === null) { //First page visit. Redirect to ADFS login.
var RPID = encodeURIComponent('urn:amazon:webservices');
var result = 'https://localhost/adfs/ls/IdpInitiatedSignOn.aspx' + "?loginToRp=" + RPID;
sessionStorage.setItem('activelogin', 'inProgress');
window.location = result;
}
else {//Credentials exist, page refresh, etc.
console.log('activelogin already exists in session and the value is ' + activelogin);
}
}
The flow above sets a session variable to initiate a call to the ADFS IdP and return to the site to call a getSamlCredentials() routine after with SAMLResponse (more on this and getParameterByName() in a moment).
The SAMLResponse value from ADFS that AWS requires is only supported in the POST binding. However, S3 static websites can only receive GET requests. For this reason, use API Gateway to capture the SAMLResponse from ADFS for the JavaScript application. Use Lambda as a “proxy” and redirect the user back to the static website along with SAMLResponse, which is encapsulated in a query string.
Lambda function configuration
In the Lambda console, create a function named samlRedirect using /Scenario1/lambda/redirect/index.js from the GitHub repository with Node.js 4.3 as the runtime. The execution role only needs permission to right to CloudWatch Logs for logging.
If you don’t have a basic execution role handy, you can ask Lambda to create a new one when you create the function.
Create environment variables named LOG_LEVEL and REDIRECT_URL. Set LOG_LEVEL to info and REDIRECT_URL to your S3 static website URL (either the endpoint URL displayed on the properties of the bucket when you enabled static hosting or—if you completed the optional step earlier of setting up a CloudFront distribution— the domain name listing).
API Gateway configuration
In the API Gateway console, create an API called SAMLAuth or something similar.
Choose Resources and create a child resource called SAML.
Create a POST method. For Integration Type, choose Lambda. Select the samlRedirect function. For Method Request Header, enter SAMLResponse.
When you created the samlRedirect function earlier, that function set the location property to contain your static website URL along with SAMLResponse appended as a query string. To finish the redirect, configure API Gateway to respond with a 302 status code.
Delete the Method Response code for 200 and add a 302. Create a Response Header called Location and use an Empty Response Model of Content-Type application/json.
Delete the Integration Response for 200 and add one for 302 that has a Method response status of 302. Edit the Response header for Location with a Mapping value of integration.response.body.location.
To have the Lambda function capture SAMLResponse and RelayState, edit the Integration Request and add a Body Mapping Template of Content-Type application/x-www-form-urlencoded with the following template:
On your /saml resource root, choose Actions, Enable CORS,Enable CORS and replace existing CORS headers.
Choose Actions, Deploy API. Use a stage of Prod or something similar. In Stage Editor, choose SDK Generation. For Platform, choose JavaScript and then choose Generate SDK. Save the folder someplace close. Take note of the Invoke URL at the top as you need this for ADFS next.
ADFS redirect configuration
In the ADFS console, edit the properties under Relaying Party Trusts for Amazon Web Services. Disable (clear) the Automatically update relaying party field.
Choose Endpoints. For Binding, choose POST; For URL, enter the InvokeURL from API Gateway when you deployed the API. Make sure to add /saml onto the end of the InvokeURL value.
To recap what you’ve built:
A webpage that redirects users to the ADFS login page if they don’t have credentials.
Upon successful authentication, ADFS sends the user back to the webpage (via API Gateway) along with the SAMLResponse.
The SAMLResponse is passed back to the original website as part of the query string.
To get credentials from Amazon Cognito, grab this query string in your JavaScript code and send it as part of a logins map value for the getCredentialsForIdentity call.
In the Amazon Cognito Federated Identities console, locate the identity pool that you set up in the prerequisites. Find the identity pool ID and put it in the top of the following JavaScript code as well as the appropriate AWS region.
This code is the entry point for your application by first ensuring that a unique user ID is generated with Amazon Cognito. It then initiates the loginWorkflow() code from earlier to return the SAMLResponse value to the browser in a query string.
The following is a sample utility function from a Stack Overflow query, which allows you to grab this value from the query string. Put this code after the above sample.
function getParameterByName(name, url) {
if (!url) {
url = window.location.href;
}
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
Now that your webpage has the SAMLResponse base64-encoded value from ADFS, this can be passed to Amazon Cognito in order for the client to get AWS credentials. The getSamlCredentials() routine called by loginWorkflow() looks something like the following:
function getSamlCredentials(samlResponse) {
var role = 'arn:aws:iam::ACCOUNTNUMBER:role/ADFS-Dev';
var params = {
IdentityId: identityId,
CustomRoleArn: role,
Logins: {
'arn:aws:iam:: ACCOUNTNUMBER:saml-provider/ADFS' : samlResponse,
}
};
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
if (err) console.log(err, err.stack);
else {
console.log('Credentials from Cognito: ');
console.log(data.Credentials);
}
});
}
Notice that ACCOUNTNUMBER for the ARN must be updated in both role variables, which in this case are hardcoded to show the selection process. If you’re not returning multiple roles in your SAML claim, then this parameter isn’t required. If you do, then you might want some logic for selecting the role for the client to assume. Part II of this blog series will cover how you can do this on the backend rather than the client.
Also, take note that the key in the logins map matching up to the samlResponse value is the ARN of the IdP that you created in the IAM console with your ADFS federation metadata document. Update this as well with your account number. This information is what allows Amazon Cognito to do validation for the SAMLResponse value against the ADFS trust.
If you try this code now, it won’t work. First, enable the SAML IdP as an authentication provider in your Amazon Cognito identity pool.
In the Amazon Cognito Federated Identities console, select the pool and scroll to Authentication Providers. Choose SAML. Select the checkbox next to your IdP for ADFS
Choose Save.
Next, modify the trust policy to allow Amazon Cognito to assume the role on behalf of the user when the service receives a valid SAMLResponse assertion. Amazon Cognito does this by calling the STSAssumeRoleWithWebIdentity API action.
In the IAM console, edit the trust policy for the ADFS-Dev role with the following policy (insert the Amazon Cognito pool ID where appropriate, as you did in the JavaScript code earlier):
Now that your Amazon Cognito trusts have been set up, you should be able to test your webpage. The credentials returned to console logging in the “data” object takes the form of a triple (AccessKey, SecretKey, Token), which can be used to sign requests to AWS services. A common scenario for applications is to do this via API Gateway by setting AWS_IAM authorization on a method. If you do this, then you can pass this credentials object through to a SDK request. If the role that you specified above has invoke rights to that API, then they’ll successfully call the method.
For example, if you create an API with API Gateway, you can enable AWS_IAM on those methods. For the role specified above (passed into the logins map), ensure that it has rights to invoke the method. For more details, see Control Access to API Gateway with IAM Permissions. Then, when you deploy the API, you can use the Generate SDK tab on the stage to generate and download a JavaScript SDK of your methods. You then include this in your webpage to call these methods. For more information, see Use a JavaScript SDK Generated by API Gateway. At the bottom of that topic, it shows how you can pass in ACCESSKEY and SECRETKEY to the apigClientFactory.newClient constructor.
Because you are using Amazon Cognito Identity with short-lived credentials (expiring in an hour), you can pass the temporary accessKey, secretKey and sessionToken into the apigClientFactory.newClient constructor:
A working version of the webpage code demonstrating this functionality is in the GitHub repo under /scenario1/website/index.html. Update the configs.js file in the same directory with your appropriate region, Cognito Identity Pool, SAML IdP ARN, and the ADFS-Dev Role ARN. The SAM template also creates a MOCK endpoint in API Gateway with AWS_IAM Authorization, along with a button on the webpage to “ping” as a test to see if the federated credentials are working.
Final Thoughts
Hopefully this walk through tutorial has helped you understand how SAML authentication and AWS authorization with Amazon Cognito Identity works at a deeper level. If you haven’t done so already please do take a few moments to test the full working code located at the samljs-serverless-sample GitHub repository to see this in action and let us know your thoughts.
This scenario may be enough to get you started however some organizations might be looking to do a bit more. For instance you might want to move the role selection away from the client and to a backend process or implement a custom IAM scoping scheme based on business logic. In Part II of this series we’ll walk through how you can accomplish this.
The collective thoughts of the interwebz
By continuing to use the site, you agree to the use of cookies. more information
The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.