Azure AD no SSO - Currently Not working

AWS

Overview

There was an API change for Azure and we are working to come up with a new version of the code to handle this change. We have decided to leave this lab up for reference, just in case you want to try and tackle the change to the code yourself.

In this lab we will walk through how to integrate Azure AD with Control Tower. We will be leveraging a public blog post and an Azure AD Lambda function for most of the work, with a modification to take advantage of StackSets and the account structure already provided by AWS Control Tower.

TIP: It is a best practice to keep AWS SSO configured to be used in a break glass scenario when using a third party Identity provider.

Prerequisites

  1. This lab requires an account with Administrator privileges and Control Tower.
  2. We will be utilizing an Azure free account to create our Azure AD and test users for this lab. Follow the steps from Microsoft to create a free account and free access to Azure AD Premium trial https://azure.microsoft.com/en-us/trial/get-started-active-directory/.

As of the writing of this lab, the control tower deployed the AWSControlTowerAdmin in master account and AWSControlTowerExecution in all the accounts. If this changes, you can just deploy it using the template provided as part of the AWS CloudFormation StackSets prerequisites.

Use the master account number for the AdministratorAccountId parameter.

Step 1: Configure Microsoft Azure Active Directory

TIP: If the Azure portal becomes unresponsive, or does not display some parts of the console, try with a differennt browser.

1.1) Copy your Azure AD domain (AKA Tenant ID)


Note: if a custom domain wasnot created with the account, or if you deleted it, you can create a new one y following these steps: https://docs.microsoft.com/en-us/azure/active-directory-domain-services/create-instance

1.2) Create a new User
Got to Active Directory/Users/All Users/New User

1.3) Login to the Azure portal with the new user and change its password
Since the user you created has a OTP (One Timme Password) you need to login, change the password, and copy the new password to Notepad for later.

1.4) Add a New Enterprise Application
Login with the Account Owner again and go to Active Directory/Enterprise applications/Application
Filter on AWS and select Amazon Web Services
Customize the Name and Add the Application

1.5) Open the Amazon Web Services Application, and click Edit
Note: Depending on the portal behavior this step may not be necessary because you may already be in the application summary

1.6) Enable SAML

1.7) Update the Identifier (Entity ID) field with the default value
WARNING: Do NOT rely on the default value (it doesn’t work and the error message will be unhelpful. Copy the default https://signin.aws.amazon.com/saml and remember to Save
You can use the default https://signin.aws.amazon.com/saml value. Just be aware the Identifier must be unique within your Azure account.

1.8) Configure the User Attributes
You need to tell Azure AD what SAML attributes and values are expected and accepted on the AWS side. AWS requires two mandatory attributes in any incoming SAML assertion.
A) Go and edit User Attributes & Claims

B) Add the RoleSessionName | https://aws.amazon.com/SAML/Attributes | user.userprincipalname claim


C) Add the Role | https://aws.amazon.com/SAML/Attributes | user.assignedroles claim


D) [OPTIONAL] Add the SessionDuration | https://aws.amazon.com/SAML/Attributes | 43200 claim

Your claim list should now be similar to this one

Summary of User Attributes

Name (case-sensitive) Value Namespace (case-sensitive) Required or optional?
RoleSessionName user.userprincipalname (this will show logged in user ID in AWS portal, if you want user name, replace it with user.displayName) https://aws.amazon.com/SAML/Attributes Required
Role user.assignedroles https://aws.amazon.com/SAML/Attributes Required
SessionDuration An integer between 900 seconds (15 minutes) and 43200 seconds (12 hours). https://aws.amazon.com/SAML/Attributes Required

Note: This lab assumes users are directly created within your Azure AD tenant. If you’re using an external user such as a Hotmail, Live, or Gmail account for proof-of-concept purposes, RoleSessionName should be set to user.mail instead.

1.9) Copy the Federation Metadata XML URI
Copy the URI to the Application Metadata XML file and save it in Notepad

1.10 Copy the Manifest Object ID. Open Azure Portal / Azure Active Directory / App Registrations / your application name (for example, “Amazon Web Services (AWS)”) / Manifest / Download
TIP: If you don’t see your application in the list on the App Registrations page, select All apps from the drop-down list on top of that page and search for it.

Info: All Azure AD applications are described as a JavaScript Object Notification (JSON) document called manifest. For AWS, this manifest defines all AWS to Azure AD role mappings. Later, we’ll be using automation to generate updates to this file.

Steps:
A) Go into the Amazon Web Services (AWS) application

B) Copy the Object ID. then select the application Manifest

1.11) Set the user you created as the Application Owner
Go to the Settings pane of your registered application


Set the owner of the application

1.12) Copy the Login URL
Go back to Sigle Sign-on: Azure Active Directory / Enterprise applications / Amazon Web Services (AWS) / Single sign-on. Scroll down to section 4 and copy the Login URL

At this point, we’re done with the initial configuration of Azure AD.
You should have the following:

Information Sample Content
Azure Tenant ID myazaccount.onmicrosoft.com
Azure User Name emma@myazaccount.onmicrosoft.com
Azure User password Password you have set after login in with that user
The Federation Metadata URL https://login.microsoftonline.com/b4f8e8b2-ABCD-XYZ-9399-097dd6669707/federationmetadata/2007-06/federationmetadata.xml?appid=ed1b3a1f-470c-4717-aadd-36bf7a9487ac
Login URL https://login.microsoftonline.com/b4f8e8b2-ABCD-XYZ-9399-097dd6669707/saml2
Application Object ID ed1b3a1f-460c-4717-aadd-36bf7a9487ac

At this point, we’re done with the initial configuration of Azure AD. All remaining steps will be performed in your AWS accounts.

Step 2: Configure AWS IAM Identity Providers and Roles

This customization has the roles and a SAML Identity Provider Role lambda function in a CloudFormation template that we will use StackSets to deploy to all of the accounts in our Organization.

2.01) Create a AWSControlTowerExecution role in the Master account

OPTIONAL(?) - Verify if you have a AWSControlTowerExecution role in the master account. If you don’t, you will have to create one

  1. Go into the Identity and Access Management Console (IAM), and create a Role named AWSControlTowerExecution
  2. For the Trust Entity, select Another AWS account and use your Master Account Number
  3. For permission policies, attach the AdministratorAccess policy
  4. Name the role AWSControlTowerExecution and complete creation
  5. Search the role, go back in Edit mode, and click on the Trust relashionship tab
  6. Edit the trust relationship and paste the one below but REPLACE THE ACCOUNT NUMBER WITH YOUR MASTER ACCOUNT NUMBER
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::012345678912:role/service-role/AWSControlTowerStackSetRole"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}

2.1) Download and Unzip the CloudFormation aws-landing-zone-default-azure-roles.template for this lab
aws-landing-zone-default-azure-roles.template
OPTIONAL - If you are using a shared account:

  1. Modify the Mappings:AzureADMapping:IDPName:Name to aliasAzureAD to avoid collisions in the shared account.
  2. Modify the Mappings:AzureADMapping:RoleName:Name to alias-AzureAD-Idp-cross-account-role.
    This has only been tested with 8 characters, so use more at your own risk. Azure AD cannot handle long role names.

2.2) Launch the aws-landing-zone-default-azure-roles.template as a CloudFormation StackSet to create roles

  1. Navigate to the StackSet console under CloudFormation in the master account and click “Create StackSet”

  2. Select “Upload a template to Amazon S3” and select the aws-landing-zone-default-azure-roles.template

  3. Give the StackSet a good name like AzureADIntegration. If you are using a shared account, then use aliasAzureADIntegration and enter the AzureADMetadataUrl you copied from your Azure AD application configuration above.

  4. Specify Accounts or OUs and 1 region, click Next-Next and Create. Deploy only into Accounts or OUs you want Azure AD to authorize.

  5. Remember to select the checkbox 'I acknowledge that AWS CloudFormation might create IAM resources with custom names.'
  6. Use Control Tower roles: AWSControlTowerStackSetRole and AWSControlTowerExecution.

  7. If you have deployed any of the other labs, make sure that you enter unique role names for the three role name parameters and shorten them, eg. aliasAzureADAdmin, aliasAzureADPower, aliasAzureADRead etc.

Step 3: Synchronizing AWS Roles to AzureAD

In this step, we configure the Azure AD Role Sync Lambda code to synchronize our AWS roles with Azure AD.

Run these steps on the Master account.

3.1 Create IAM Roles and the Lambda function to Sync them to Azure

  1. Download, Unzip, and run the Cloudformation template from azure-ec2.template.zip in the Master account
    Give the stack a unique name like alias-azure-ec2, and create the stack with default values.
    Note: If you are using a SHARED account: First edit the template, search for 'CT-Lab07' and add your user prefix (aliasCT-Lab07) to make it easier to locdate your instrance
  2. Wait for the stack to be fully deployed
  3. Connect to the instance from thhe AWS Console with an AWS System Manager (SSM) session
    1. Go to the AWS System Manager service
    2. Click on Session Manager
    3. Click Start Session, and select the CT-Lab07 instance
      NOTE: Alternatively you can do this directly from a terminal session on your laptop. This required the the AWS CLI and the Session Manager Plugin to be installed. For details see the References section st the end of the lab
      To connect to the instance with the CLI:
      1. Connect with SSO to the Master account but instead of accessing the console, copy credetials from the CLI access link
      2. Paste these credention in your terminal and use aws ssm start-session --region *REGION* --target *INSTANCEDID*
  4. On the SSM Session Terminal execute the following line by line (not as a block)
screen
cd ~
curl -O http://controltower.aws-management.tools/optional/sso/azure/Aad-iam-sync-lambda.zip
unzip -q Aad-iam-sync-lambda.zip
cd Aad-iam-sync-lambda/deploy
chmod +x *.sh
################################################
##### ---- IF USING A SHARED ACCOUNT ----- #####
################################################
# Open code/lib/AWSService.js in a text editor like Vim or Nano
# Modify line ~75 to include your alias
# Example: return role.idp && role.idp.includes('saml-provider/aliasAzureAD ');
# Important: Use the same Alias you used for deploying Roles and the Identity Provider
### ---- End of: IF USING A SHARED ACCOUNT -----
################################################

# follow steps and COPY the output bucket name
./create-bucket.sh
### ---- generated output -----
### this will generate output from the S3 bucket creation and configuration
### do a 'cat create-bucket.sh' if you are curious of details
### REMEMBER to take note of your deployment bucket name. It is part of the script output
###
# follow steps and COPY the KMS key output
./configure.sh
### ---- simulated output -----
Please enter Azure AD Custom Domain:
eggxxxxxxxxx.onmicrosoft.com
{
    "Version": 2
}
Please enter AzureAD Application Object ID:
eacd31c1-9ead-ABCD-1234-8dda0f74d8f4
{
    "Version": 2
}
Please enter an AzureAD User - Username:
bob@eggxxxxxxxxx.onmicrosoft.com
{
    "Version": 2
}
Please enter an AzureAD User - Password:
{
    "Version": 2
}

Parameter creation complete.  KMS Key ARN is:
arn:aws:kms:us-east-2:012345678912:key/4c73b7bc-xyzz-xyzz-9c54-d6fadab22d6e
### ---- end of simulated output -----
cd ../
aws cloudformation package --region **YOUR-REGION** --template-file deploy/lambdafunction.yml --s3-bucket **YOUR-BUCKET** --output-template-file build/lambdafunction-packaged.yml

aws cloudformation deploy --region **YOUR-REGION** --template-file build/lambdafunction-packaged.yml --stack-name aad-sync-function --capabilities CAPABILITY_IAM --parameter-overrides "KMSKeyARN=**YOUR-KMS-KEY**"

3.2) Navigate to the AWS Lambda function in the console and verify that it executes successfully
The function will be named with this prefix: aad-sync-function-AzureADSyncFunc-…
INFO: the function is invoked on a schedule every 15 minutes by Amazon CloudWatch Event so you will have to wait until the next invokation.

Troubleshooting tips:
  • Look at details of the Lambda execution in CloudWatch Logs. This is available from the Monitoring pane in Lambda
  • If 0 roles are found, you either did not deplor roles or you are using a shared account and forgot to add your prefix to roles or the AWSService.js file. Roles are discovered because they use the same saml-provider: AzureAD or aliasAzureAD
  • If you have Sync errors with the Azure account you may have entered incorect values when executing configure.sh. You can look up these values in the System Manager Parameter Store. You can re-execute configure.sh but you will also have to rebuild and redeploy the package because the lambda function is CACHING values.


Step 4: Entitling Azure AD users to assume AWS Roles

Now we are back to following the blog post, the section titled Entitling Azure AD users to assume AWS Roles.

4.1) Open Azure Portal > Azure Active Directory > Enterprise applications > All applications > (your application name)

4.2) Select Users and groups > Add user, and assign a role to the user

4.3) Navigate to Azure Active Directory > Enterprise Applications > Amazon Web Services (AWS) > Properties and copy the User access URL

Step 5: Login to the Azure MyApps portal

Now we can use the new user and new User access URL to login to the myapps portal and select a role to login to the AWS console.

  • Ideally using a different browser instance, login to the myapps portal using the URL you copied previously.

  • Select the AWS account and AWS role that you want to use to sign in. Or if you only have one account you will be automatically logged into the console for that account.


Exploring the Solution

You deployed 3 templates. One created IAM roles in AWS accounts to handle user authorizations, another deployed an EC2 instance used to build a deploy the third template with the Lambda function used to synchronize IAM roles to Azure AD.

  1. Go into the IAM console in one of these accounts, locate one of the deployed role, and look at the trust policy. Each role trust the same SAML provider named AzureAD or yourAliasAzureAD.
  2. The second template deployed an AWS Lambda function that synchronize some IAM roles with with Azure AD. See you you can locate the Amazon CloudWatch scheduled event that invoques this function.
  3. On the AWS side everything could be deployed with a single template. Some manual steps were kept to allow you to explore other aspects. Look at:
    1. The EC2 instance you deployed.
      1. Try executing: ec2-metadata –all. For details on instance metadata, see References at the end of the lab
      2. It does not have nay PEM key but you still were able to use it through AWS Systems Manager. This EC2 instance does not allow any public traffic and could have been deployed in a private subnet and you still could create a session to it.
      3. The instance is using an IAM Role for EC2. See if you can locate this roole in the EC2 Console.
      4. Instead of starting a session through the Session Manager Console, you can start session from a terminal and the Session Manager Plugin for the AWS CLI
      5. If you configure the service for it, the Session Manager can also Audit and Log Session Activity.
      6. Finally, have you noticed the CloudFormation template used to deploy the instance did not specify an AMI? Instead it used a template paramater to get the latest AMI for the requested architecture. See Query for the latest Amazon Linux AMI IDs using AWS Systems Manager Parameter Store for details

Deleting AWS resources deployed in this lab

In the Master account:

  1. Delete the CloudFormation stack you deployed from the azure-ec2.template
  2. Delete the Stackset ‘aliasAzureADIntegration’ deployed from the aws-landing-zone-default-azure-roles.template
    1. First delete the deployed Stacks of the StackSet
    2. Then delete the Stacksets itself
  3. Delete the ‘aad-sync-function’ stack.
  4. In the System Manager Parameter store you can delete:
  • /azuread-sync/username
  • /azuread-sync/tennant
  • /azuread-sync/password
  • /azuread-sync/objectid
  1. Delete the alias-640271645869-us-east-2-demosync bucket
  2. You can also delete Amazon CloudWatch Log Grooups that were created for AWS Lambda functions and System Manager Sessions
  3. In the Azure Console, delete the AWS application

REFERENCES

  1. Instance metadata: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
  2. EC2 Instance Metadata Query Tool: https://aws.amazon.com/code/ec2-instance-metadata-query-tool/
  3. Installing the AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html
  4. Installing the Session Manager plug-in: https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html
  5. AWS Systems Manager Session Manager: https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html
  6. How to automate SAML federation to multiple AWS accounts from Microsoft Azure Active Directory
  7. SAML Developer Tools
  8. Enabling SAML for Your AWS Resources
  9. Query for the latest Amazon Linux AMI IDs using AWS Systems Manager Parameter Store
  10. Azure AD does not provide an easy way to use the commmand line but there are solutions like aws-azure-login on Github.
  11. How To Use Linux Screen

Copyright 2019, Amazon Web Services, All Rights Reserved.