Securing your AWS Accounts with SAML Authentication

Gavin Lewis
Jul 1 · 8 min read

Security of your AWS accounts is important, it doesn’t just protect client data but also can affect the availability of your applications. Especially so when it comes to production workloads where you need to be absolutely sure who has been granted access to an account, what levels of permission they have and be able to manage users at an organizational level instead of in each independent system. No matter how many policies and processes you put into place, someone always ends up sharing an access or secret key when they shouldn’t have! Utilizing a SAML Identity Provider along with Active Directory can help solve these problems!

Although there are now pre-built options such as AWS SSO to act as the SAML provider, they still rely on extending your AD into AWS with the AD Connector as part of AWS Directory Services, this means you need to have a VPN or a Direct Connect implemented, which isn’t always the right approach or possible for everyone! Although we have extended our AD into AWS, AWS SSO didn’t exist at that point so we chose to build our own solution with ADFS instead.

You’ll need access to a few components to build the solution:

  1. Active Directory
  2. ADFS
  3. AWS Account(s)

Theory

I wanted to explain at a high level how the different components work together, as there are a number of moving parts and inter-dependencies involved.

To log in, users access an alternate URL (eg. awsconsole.domain.com) instead of the traditional console URL. This URL will redirect the user to the SAML provider, authenticate them and then allow them to be granted access to specific AWS Accounts.

AWS Account access is determined by a couple of components; the groups the user is assigned to in AD, and an IAM role created in AWS. The group in AD needs to have a name which correlates with an IAM role’s name. The IAM role then needs to have permissions assigned to it specifically to the level of access a user will have once authenticated.

IAM roles are different to users, instead of having a set access and secret key, they generate a set of temporary credentials which can be consumed for a period of time before expiring; after they expire they need to be re-generated. It’s worth having a read about STS (Secure Token Service) to understand how this process works in detail.

This solution works not only for the console, for the CLI too. I’ve used a tool called saml2aws to streamline the authentication process for programmatic access for a number of years now as a replacement for hardcoded IAM details!

Oh, I should also mention, this solution works across multiple accounts!

SAML Concepts

There are some SAML concepts and terminology which are useful to know before doing a deep dive into the configuration process. If you’ve never worked with SAML before, some of these terminologies are important to remember:

  • Identity Provider (IdP): the source of authentication information, eg. the IdP is ADFS in this example.
  • Service Provider (SP): the application which relies on the IdP for authentication. In the case of ADFS, also known as the relying party trust (RPT). The SP is AWS in this example.
  • Claim Rules: A list of information which is sent as part of the assertion, contains information such as username and groups.
  • Assertion: The information sent as a token from the IdP to the SP

It’s important to note, the IdP and SP never communicate directly, all communication occurs via the end user’s browser. The IdP and SP are simply aware of each other, as demonstrated:

Source: https://en.wikipedia.org/wiki/SAML_2.0

Configuring ADFS

The first item we need to set up is a new Relying Party Trust in ADFS. We can do this via the RPT Wizard in ADFS. AWS makes their SAML metadata publically available via an XML file which can be referenced directly into your IdP. After adding the initial information such as the federation metadata and an RPT name, you can click through the rest of the wizard with the default settings.

Federation Metadata Address: 
https://signin.aws.amazon.com/static/saml-metadata.xml

After the wizard is complete, you should see an AWS entry in the list of RPTs on your ADFS server. We now need to configure the Claim Rules in ADFS, these send information about the authenticating user as part of the assertion to AWS. Right click on the AWS RPT and select Edit Claim Rules.

Rule 1

Maps the windows account name to the NameID section of the assertion sent to AWS.

Rule name: NameIdClaim rule template: Transform an incoming claim

Rule 2

Maps the email address of the user to the RoleSessionName attribute of the assertion sent to AWS.

Rule name: RoleSessionNameClaim rule template: Send LDAP Attributes as ClaimsOutgoing Claim Type: 
https://aws.amazon.com/SAML/Attributes/RoleSessionName

Rule 3

Gets a list of AD groups the user is associated with. AD groups form a list of AWS accounts a user is able to assume once authenticated.

Rule name: Get AD GroupsClaim rule template: Send claims using a custom ruleCustom rule:
c:[Type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == “AD AUTHORITY”]
=> add(store = “Active Directory”, types = (“http://temp/variable"), query = “;tokenGroups;{0}”, param = c.Value);

Rule 4

Transforms the list of groups from AD to be in a format which matches the IAM roles created in AWS.

Rule name: Group TransformerClaim rule template: Send claims using a custom ruleCustom rule:
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/ADFS,arn:aws:iam::$1:role/AWS-"));

Rule 5

Sends through the duration for which the session token should remain valid. We’ve set this to 10 hours (long enough for a standard working day).

Rule name: SessionDurationClaim rule template: Send claims using a custom ruleCustom rule:
=> issue(Type = "https://aws.amazon.com/SAML/Attributes/SessionDuration", Value = "36000");

Configuring AWS

Now ADFS is set up, it’s time to configure our AWS Account(s). For any account you want to be able to utilize SAML to authenticate into, this process will need to be followed (or performed as part of an automated process across your accounts).

Setup the Identity Provider

Navigate to IAM > Identity Providers and create a new provider. Populate AWS with the following information:

  • Provider Type: SAML
  • Provider Name: ADFS
  • Metadata Document: Upload the one available from https://fs.yourdomain.com/FederationMetadata/2007–06/FederationMetadata.xml

Create an IAM Role

Now create a new IAM Role. This role will be assumed by users when logging into the AWS Account. Navigate to IAM > Roles and create a new role.

We then need to assign permissions to the role, which will allow the users who assume that role to perform various actions. I’m going to grant this role ReadOnlyAccess.

On the last screen, I’m going to name the role AWS-GavinSandbox-ROA. It's important to include AWS in the name of the role as this was included in our group transformation information.

Setup User Groups

In Active Directory, we now need to create a User Group which matches the role information created in the AWS Account. The format of the group name needs to be AWS-<ACCOUNTID>-<ROLENAME>, replacing the Account ID and IAM role name with your own.

After creating the group we need to assign some users to it — just myself for now:

Create an S3 Website Bucket

This isn’t a critical piece to the puzzle, but it does make access to your AWS Accounts via SAML simpler. Doing this allows users to access the AWS Console by going to a URL such as awsconsole.domain.com instead of manually navigating to your IdP and selecting the SP.

In one of your AWS Accounts (eg. in an account specific to core infrastructure within your organization with specific SCP policies) create an S3 Website Bucket and give it the name awsconsole.domain.com (replacing domain.com with your own). Configure the bucket for static website hosting, and selecting the option to perform redirects:

Target: fs.domain.com/adfs/ls/idpinitiatedsignon.aspx?logintorp=urn:amazon:webservicesProtocol: https

Once created, in DNS create an entry to point awsconsole.domain.com to the S3 bucket.

Test Run

We’re ready to give this a test run! To get started, type in the URL awsconsole.domain.com into the browser. You should first see the browser window redirect to your IdP and either authenticate you automatically or ask you to log in (depending on the configuration).

You’ll then be presented with a list of accounts you have access to, select one of the roles and click Sign In.

Assuming all has gone well, you should be logged in to your account with the specific role you selected!

Summary

To increase security even further with this solution, you may want to consider implementing MFA, which lowers the risk of someone’s AD account being compromised and an attacker gaining access to multiple systems.

These steps may seem like a lot to get going, and it is a fair amount of work to get set up initially. On an on-going basis, you do only need to add additional AD Groups and configure the AWS Accounts. We ended up automating the process after I threw together a rough and ready serverless account factory, I am aware there are other tools available in AWS now to do this.

The Startup

Medium's largest active publication, followed by +540K people. Follow to join our community.

Gavin Lewis

Written by

Passionate about building and delivering solutions in the Cloud! Senior Cloud Architect @ Rapid Circle. Views are my own.

The Startup

Medium's largest active publication, followed by +540K people. Follow to join our community.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade