It’s a pretty common design request these days to have a single authentication source. I mean, do you really want to have to manage a bunch of different logins instead of having to remember one? Also, five different accounts give attackers five different avenues to try to exploit. So many times we use our existing Active Directory infrastructure as our single source of authentication. Amazon Web Services (AWS) needs a way for people to login and will allow you to use your own Active Directory credentials through Security Assertion Markup Language (SAML). This post will walk you through the setup of Active Directory Federation Services (ADFS) on Windows Server 2016 and configuring it to be your credentials for AWS.

For this post we’ll take a few AD security groups with a prefix of “theITHollow-” and allow the users within it to authenticate with AWS Roles similarly named.

Here are the AD Groups I’ll be working with for this post:

And here are the associate AWS Roles that will map to them:

How Does SAML Work?

To use the process explained in this blog post several things will happen. The user who logs in will navigate to the ADFS Portal which will authenticate agains local Active Directory. The Authentication will be sent back to the user’s browser which will then POST the token to the AWS portal and then the browser will be redirected to the AWS Console if authenticated correctly. The diagram below shows how the process would work.

Install ADFS

The first thing we need to do is install Active Directory Federation Services on your Windows Server 2016 server. This procedure requires an SSL Certificate for you to upload to the server during the configuration so you may want to have one of these ready. I purchased a certificate from a public CA prior to these steps.

To install ADFS open the Server Manager and Add a new server role. Select the Active Directory Federation Service Role.

No other features need to be added through this process so you can mosey on through the wizard until you get to the end of the installation.

Basic ADFS Configuration Steps

Now that ADFS has been installed we’re prompted to complete the configuration through the wizard. Select the option to “Create the first federation server in a federation server farm” option. Of course this assumes that you don’t already have ADFS running already in your environment. Click next.

Select an account to use to connect to your Active Directory Domain Services. Typically you’d want to use a service account to bind with AD. Click next again.

On the Service Properties tab, you’ll need to import your ADFS Certificate. This is the SSL Certificate I alluded to earlier in this post. Then give the federation service a display name. This name will show up on your ADFS Login portal.

You’ll need to then specify another service account that will run the ADFS services on your server. Click Next.

Then you’ll need to create a database for storing configuration data. You can create a new on using the Windows Internal Database or specify your own SQL server. I went the easy route mainly so I could snapshot my ADFS server and be sure that the configuration information comes along with the snapshot.

Review the configuration options and click next to start Pre-requisite checks.

If all of the prerequisite checks complete successfully, click the configure button to begin the configuration.

Once the configuration is done, you’ll notice some results. The main one is that you need to restart the server, but you may also find that the port is using 49443 if you didn’t add the certauth.servername Subject Alternate Name (SAN) as part of your certificate. Thats perfectly fine, it just means that a standard SSL Port of 443 won’t be used. Click Close and be sure to restart your ADFS server.

Setup AWS for SAML Authentication

While we’re waiting for that server to reboot, we want to go to our AWS portal with some local login credentials. (I know, local credentials are so lame but we need them for now until we get our SAML authentication working. Just be patient.) Go to the IAM Service and click on the “Identify Providers” link. There you’ll have the opportunity to add a new SAML provider by clicking the “Create Provider” button. Click that and on the first screen select the provider type of SAML. Give the provider a name and then you’ll need to upload your MetaData Document. This is a document on your ADFS server which explains how the federation should work. You can get this by going to https://[your-server-name-here/FederationMetadata/2007-06/FderationMetadata.xml in a web browser. In my example I went to: https://adfs.theithollow.com/FederationMetadata/2007-06/FederationMetadata.xml.

Note: If you added an SSL Certificate with a public DNS Entry in it but not a local DNS name this might fail. To get around that ensure that you’ve got Split-DNS working so that you can reach the ADFS server with it’s public name from within the local area network.

Choose your metadata file and complete the setup.

Now you should have an identity provider listed in your AWS IAM console.

Create AWS Roles

Next, we’re going to setup a few roles in AWS. The roles here are the same listed at the beginning of this post that match up with our Active Directory Security Groups. Note that you can use IAM Users or IAM Groups to set this stuff up, but an AWS role is an object with authorization to do stuff without credentials. This makes it very secure since something else must assume a role, like a user or even an EC2 instance. To create a role we’ll go into the IAM console and under the roles heading click “Create new role”. Under the role type, select the “Role for identity provider access” option and then click the “select” button next to “Grant Web Single Sign-On (WebSSO) access to SAML providers” option.

Under the Establish trust step, select the SAML provider we created previously and click “Next Step”

Then verify the Role that’s listed and click “Next Step”.

Now we need to attach a policy. The policy will depend on what permissions you want the role to have. One of my roles has administrator access so I’ve selected that policy for this role. Click “Next Step”.

Next, give the role a name. The name will be important later. I’m matching up my AWS role names with my AD Group names. This means they must match or the claim rules created later won’t work correctly so the name can be important for this post. If you follow the post exactly you’ll understand what I mean and can modify it accordingly later on.

Now, I’ve repeated this last section for a general users account so I can show both Admins and Users. Feel free to use one or multiple AD Groups and roles as you see fit.

Adding a Relying Party Trust

Now we must go back to ADFS again. If you open up the ADFS management console, you’ll likely notice a link stating that you need to add a relying party trust. Click the link to open the wizard or go to the “Relying Party Trust folder and right click it to add one. We want to select a “Claims aware” trust for our wizard. A claim is used to pass attributes about the object authenticating over to the relying trust for authorization purposes. We’ll want that cause one of our claims will be a security group membership.

On the data source step, we want to select the “Import data about the relying party published online or on a local network. Remember that metadata file we uploaded to AWS earlier? Now we want to do the reverse with ADFS but this metadata file is publicly accessible so we can enter in the URL https://signin.aws.amazon.com/static/saml-metadata.xml.

Specify a Display Name. This name will show up in the ADFS web portal as the resource you’re authenticating into so make it descriptive.

Next you can select who will have access to login to the ADFS portal for authentication to take place. You can select “Permit everyone” if you’d like which will allow anybody to login. I’ve selected “Permit Specific Group” and selected an AD Security Group as the members. Be aware though if you use this option. Even if your users are in an AD group that matches our AWS Roles, they’ll get a permissions error if they’re not in a security group with permissions to attempt to login through the ADFS portal. Permitting everyone is the easiest way to prevent this but specifying other options allows for more security.

On the Ready to Add Trust step you can review the settings before clicking next.

Select the checkbox to configure claims issuance policy to open our claims rules when finished.

Adding Claims

After a user authenticated to the Identity Provider (ADFS in this case) we must send the authentication response to the AWS SAML endpoint. This is basically an authentication token and a POST REST call. AWS Requires certain things to be added to that POST call which you can find at: http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml_assertions.html The rest of this section shows how we modify the information in that POST call so that we have the proper attributes passed to the AWS SAML endpoint.

If you didn’t check the box in the last step you can always go to the “Relying Party Trusts” folder and click “Edit Claim Issuance Policy…” by right clicking on the trust.

Click Add Rule to add a new claim. The first claim we should do is the NameId. Select the “Transform an Incoming Claim” from the dropdown and click Next.

Give the rule a name of “NameId”, select “Windows account name” from the claim type drop down and then select “Name ID” in the “outgoing claim type” dropdown. The “Outgoing name ID format” should be a “Persistent Identifier and we’ll select the “Pass through all claim values” radio button.

Click Finish

We must add a couple of other claims to ensure all of the required information is passed. Add another claim and select the “Send LDAP Attributes as Claims” this time.

This new Rule should be named “RoleSessionName” and the Attribute store value will be “Active Directory”. Under the attributes select E-Mail-Addresses and the Outgoing Claim Type must be: “https://aws.amazon.com/SAML/Attributes/RoleSessionName” exactly.

Note: We used E-Mail-Addresses as the RoleSession Attribute. This means that you want to have the email address attribute populated in Active Directory as well. It will be used in the AWS Console for identification.

Now comes the magic part. We want to take the Group Membership of the person who has authenticated and match it to a role in AWS. Example the AD Group named “theITHollow-Admins” will map to the AWS role “theITHollowAdmins”. We can do this by using two additional claim rules. An explanation of this process is much better explained here: http://molikop.com/2014/04/adfs-claim-rules-filtering-groups/

So, Let’s add another claim rule to grab the group membership of the person who authenticated. Add a new claim rule using the custom rule template.

Name the rule something and then add the following code using the claim rule language.

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"] => add(store = "Active Directory", types = ("http://theITHollow/groups"), query = ";tokenGroups;{0}", param = c.Value); 1 2 c : [ Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname" , Issuer == "AD AUTHORITY" ] = > add ( store = "Active Directory" , types = ( "http://theITHollow/groups" ) , query = ";tokenGroups;{0}" , param = c . Value ) ;

Now add a second claim rule using the custom rule language again. This time we’ll use the claim rule language and retrieve the variables placed in the prior claim rule, we’ll filter it based on our group names (Looking for groups named like theITHollow) and then we’ll transform them into an IAM role name.

c:[Type == "http://theITHollow/groups", Value =~ "(?i)^theITHollow-"] => issue(Type = "https://aws.amazon.com/SAML/Attributes/Role", Value = RegExReplace(c.Value, "theITHollow-", "arn:aws:iam::YOURARNNUMBERGOESHERE:saml-provider/adfs,arn:aws:iam::YOURARNNUMBERGOESHERE:role/theITHollow")); 1 2 c : [ Type == "http://theITHollow/groups" , Value = ~ "(?i)^theITHollow-" ] = > issue ( Type = "https://aws.amazon.com/SAML/Attributes/Role" , Value = RegExReplace ( c . Value , "theITHollow-" , "arn:aws:iam::YOURARNNUMBERGOESHERE:saml-provider/adfs,arn:aws:iam::YOURARNNUMBERGOESHERE:role/theITHollow" ) ) ;

NOTE: In your code, you must replace the group prefixes with your own group names and the second piece of the RegExReplace command must be the arn of your SAML Provider/Group Role arn with prefix.

For example I’ve used the following because my AWS roles begin with theITHollow.

"arn:aws:iam::YOURARNNUMBERGOESHERE:saml-provider/adfs,arn:aws:iam::YOURARNNUMBERGOESHERE:role/theITHollow" 1 "arn:aws:iam::YOURARNNUMBERGOESHERE:saml-provider/adfs,arn:aws:iam::YOURARNNUMBERGOESHERE:role/theITHollow"

When you’re all done you’ll have a claim list like the one below from my lab.

Customizing your ADFS Portal

You can skip this section if you’d like, but I wanted to customize my ADFS login portal just a bit to make it look fancy. You can do this by opening up a PowerShell console on your ADFS server and using the set-adfswebtheme cmdlets. Here is an example where I changed the illustration.

Set-AdfsWebTheme -TargetName default -Illustration @{path="C:\path\adfslogo.jpg"} 1 Set -AdfsWebTheme -TargetName default -Illustration @ { path = "C:\path\adfslogo.jpg" }

Authenticate

I found that I needed to make one more PowerShell request before I could login to the portal. On the ADFS server you may need to run the command:

Set-AdfsProperties -EnableIdPInitiatedSignonPage $true 1 Set - AdfsProperties - EnableIdPInitiatedSignonPage $ true

This enables the login page and by default wasn’t set to true.

Once you’ve run that you can go to your ADFS portal and try to login. Go to https://[YOURADFSSERVERNAME.DOMAIN.NAME]/adfs/ls/IdpInitiatedSignOn.aspx

Here you’ll hopefully see your branded page, and on the right side of the screen the opportunity to login to your relying trust. Select the trust and click the “Sign in” button.

Enter your Active Directory Credentials and see if it worked. In my case I logged in and was redirected to my AWS portal and assigned the appropriate role based on my Active Directory Group membership. Remember that this login user must be in your AWS Groups, in my case named “theITHollow-Admin”.

You can see from my login attempt that my account was logged in through federation and that my login is based on my email address.

Summary

Now we can login to our AWS console using locally authenticated credentials and pass a SAML token to AWS for authorization. Roles are used in AWS to provide our authorizations so we can have all of our credentials stored in our protected Active Directory environment and never have to store them in two places making the solution more secure and easier to manage. Good luck on your tests, I hope this post will be useful while you’re setting up AWS Federation.