Charting our identity journey in AWS — Part 2

Louay Shaat
My Local Farmer Engineering
9 min readNov 2, 2021

Parts of this blog were contributed to by Aidan Keane

Our identity model

TL;DR This blog is part 2 of our identity journey, in this part the blog will focus on the challenges we had with AWS SSO to build our enterprise identity solution.

Check out Part 1 as to why we decided to proceed with AWS SSO for our Identity solution in AWS.

Now that we decided that AWS SSO is our service of choice, let’s run through our setup, challenges and how we managed to get AWS SSO to serve our purposes.

The focus of our identity strategy is simplicity, as you know we don’t have a dedicated Security/Identity role, so I wanted to make our implementation intuitive and dynamic. This is why we went with a combined Role Based Access Control “RBAC” and Attribute based access control “ABAC” model. Additionally we built a custom solution to help get our synchronization working properly between AzureAD and AWS SSO. Thanks solely to Aidan Keane’s efforts as he’s our Microsoft whiz.

Disclaimer
I Love My Local Farmer is a fictional company inspired by customer interactions with AWS Solutions Architects. Any stories told in this blog are not related to a specific customer. Similarities with any real companies, people, or situations are purely coincidental. Stories in this blog represent the views of the authors and are not endorsed by AWS.

Our implementation

AWS SSO implementation with AzureAD is straight forward, as we mentioned in the previous blog, we selected “External Identity provider“ and we built the integration based on the AWS SSO Gallery Application in Azure AD. Once we built the trust between AWS SSO and the gallery app, we added the users/groups we wanted synchronized to AWS SSO.

To enable auto-sync, we enabled SCIMv2 provisioning in AWS SSO and used the tokens created in the AzureAD app.

SCIM in AWS SSO

Note: here you can find a step-by-step guide on how to build the integration between AWS SSO and AzureAD.

Note: Depending on your setup, if you are only an Office365 or full AzureAD user, you might have to modify the attributes in your Gallery app. More info here

The sync issue

Sync times between providers

Once we had SCIM enabled, the assumption is that we will have a JIT (Just in time) implementation. But we were faced with a hard fact that Auto Sync from AzureAD is done on a 40 mins interval.

Adding on top of that, the 30 mins sync between our on-prem AD and Azure AD. We only modify, add and delete users from our on-prem AD today.
Our setup is explained below

~70 mins sync doesn’t work for us

We rely on consistency and the 70 mins sync will now work for us. Since I’m not a Microsoft wizard, I got in touch with our resident Microsoft Guru Aidan Keane. Looking at our options and what AWS detailed in this blog post we wanted a better more robust solution. Aidan Keane built this excellent automated solution using Azure Vault and Azure functions.

This section is written by Aidan Keane

The solution

AzureAD to AWS SSO Sync solution

We’re going to dive into two solutions for solving the sync delay between on-premises Active Directory and Azure Active Directory to AWS SSO. This can be configured to perform a delta sync on a schedule e.g. every 5 minutes which brings the total time to sync on-premises to AWS SSO to 8 minutes which is a dramatic improvement over the default 70 minutes. We can go through the setup of the sync for Active Directory to Azure AD here and the setup for the Azure functions will be on the repo with the code.

Active Directory Sync to Azure AD:

To force an Active Directory sync with PowerShell requires the following steps:

  1. Install Azure Active Directory Connect which can be download from the Azure Portal or directly from Microsoft.
  2. Import the ADSync PowerShell module
  3. Run the Start-AdSyncSchedule cmdlet which syncs with Azure AD.

Import the AD Sync PowerShell module

  • Import-Module –Name "C:\Program Files\Microsoft Azure AD Sync\Bin\ADSync" -Verbose

To verify that the module has been imported, use Get-Module -Name adsync

Create a PowerShell file and enter the following line of code and save it to a location e.g. C:\ILMLF\ADConnectSync.ps1
This one liner will trigger a Delta sync of Active Directory to Azure AD.
Start-ADSyncSyncCycle -PolicyType Delta

On the Server with AD Connect installed, bring up Task Scheduler and Create a Basic Task

  • For Start a Program, type powershell Start-ADSyncSyncCycle -PolicyType Delta
  • After we click save, bring up the task again to change the frequency to 5 minutes
  • Click on the triggers tab and then Check off the Repeat Task every 5 minutes.

To verify that this is now running on a schedule — let’s bring up the AD Connect Synchronization Service Manager.

On the Server that has AD Connect Installed — and go to the following directory :

  1. C:\Program Files\Microsoft Azure AD Sync\UIShell

Double Click on the miisclient to see the current job runs

Now our sync from on-prem AD to Azure AD is optimized.

Azure Active Directory Sync by Job ID

AzureAD to AWS SSO Function setup

we have evolved the Azure AD Sync solution that was originally posted in Part 1 into a managed solution using Azure Key Vault and two Azure Functions. The Incremental function performs a delta sync between Azure AD and AWS SSO on a timed interval. This will send over all Users and Groups who have been assigned to the Enterprise Application within Azure AD.

The second function does a complete reset and re-sync of all Users and Groups on a schedule. The Reset Sync Function resets the ‘watermark’ on all Users and Groups to enable a full sync to run between Azure AD and AWS SSO. This is important as users or groups can be deleted from AWS SSO by accident. However, the Users and Groups are still stored in Azure AD as that is the primary Identity Provider (IdP). On the next sync, there is no guarantee that those “deleted” Users and Groups will show up in AWS SSO so we solve this by running the Reset function.

The schedule is configured using a cron job and the Incremental Delta Function currently has a default of 3 minutes while the Reset function runs at midnight UTC. This function uses the SCIM Job id to perform the sync. By using the Job id, we can trigger multiple SCIM endpoints e.g. Azure AD, Google or GitHub etc. The function can be copied and a few values replaced and this can be contained within the same Azure function or deployed to a separate Resource Group due to change control policies within your company. Finally, Log Analytics is deployed as part of this solution so you can query and alert on the status if this is needed.

Note: This repo has all the instructions to build this synchronization model AWS SSO Sync Solution

Now that sync is sorted, lets walk through our RBAC and ABAC model

Our Authorization model

Authorization model

Now that synchronization blues are a thing of the past, we focused on building our authorization model. We wanted a model where we have the ability to dynamically assign access based on metrics we control and leverage.
As part of our tagging strategy in AzureAD, we have a few tags that we control and update based on user changes including:

  • Department
  • Team

On the resource side, we ensured that there tags are present to identify owners and to track for billing, we additionally added these tags for our automation

  • Environment: Dev/Test/UAT/Prod
  • Deployment: IaC/Manual

Can we leverage these attributes to build a dynamic access model?

Attribute based Access Control (ABAC)

ABAC model

Attribute Based Access Control is a model where we can leverage the attributes from our IdP and provide access when the resources have the same tag.

Below is a sample policy that incorporates both an ABAC and RBAC components.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RBAC",
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:InvokeFunction",
"lambda:PublishLayerVersion",
"lambda:InvokeAsync",
"lambda:PublishVersion",
"lambda:CreateAlias"
],
"Resource": [
"arn:aws:lambda:*:417640402475:layer:*",
"arn:aws:lambda:*:417640402475:function:*"
]
},
{
"Sid": "ABAC",
"Effect": "Allow",
"Action": [
"rds:AddTagsToResource",
"rds:CreateEventSubscription",
"rds:CreateDBClusterEndpoint",
"rds:CreateDBParameterGroup",
"rds:CreateDBSubnetGroup",
"rds:CreateDBProxyEndpoint",
"rds:CreateDBSecurityGroup",
"rds:CreateDBSnapshot",
"rds:CreateDBCluster",
"rds:CreateDBInstance",
"rds:CreateDBProxy",
"rds:CreateDBClusterSnapshot",
"rds:CreateDBClusterParameterGroup",
"rds:CreateDBInstanceReadReplica"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Department": "aws:PrincipalTag/Department"
}
}
}
]
}

As you can see above, with Lambda (doesn’t support ABAC) we specified the arns for the functions that we want to provide access to, while for RDS we are relying on a matching condition

"aws:ResourceTag/Department": "aws:PrincipalTag/Department"

If the resource and the user have the same value for the attribute Department, then the user will be able to perform the actions in the policy

Important note: ABAC isn’t supported in all services today. This link shows all services that accept Authorization based on tags. If the service is listed as No, then you have to use an RBAC policy

Now are are able to make our policies more dynamic where possible

Controlling Tags

To be able to ensure tags aren’t modified to grant access, we applied 2 control

  • Only untag resources that belong to your team using this policy
Effect": "Allow",
"Action": [
"secretsmanager:UntagResource" ],
"Resource": "*",
"Condition": {
"StringEquals": {
"secretsmanager:ResourceTag/project": "${aws:PrincipalTag/project}" },
"ForAllValues:StringEquals": {
"aws:TagKeys": [
"application" ] } } } ] }

The example above is based on Secrets Manager

  • We also implemented a tagging policy in SCP to control ensure the Department tag is present
{
"tags": {
"department": {
"tag_key": {
"@@assign": "Department"
},
"tag_value": {
"@@assign": [
"100",
"200"
]
},
"enforced_for": {
"@@assign": [
"secretsmanager:*"
]
}
}
}
}

Example above enforces Department tag for the Secrets Manager service only

Delegation Model

Now that we managed to reduce the sync time from AzureAD to AWS SSO, my next mission was to delegate access to the development teams so they can provision their own access with the proper guardrails.

We wanted a simple delegation model for our development teams to manage all permission sets for a set of accounts they control.

Implementing this was straight forward, below is a sample PermissionSet that allows me to assign to an Azure AD Group so they can manage their own access

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DelegatedPermissionsAdmin",
"Effect": "Allow",
"Action": [
"sso:AssociateProfile",
"sso:CreateAccountAssignment",
"sso:CreateInstanceAccessControlAttributeConfiguration",
"sso:CreateManagedApplicationInstance",
"sso:CreateProfile",
"sso:DeleteAccountAssignment",
"sso:DeleteInlinePolicyFromPermissionSet",
"sso:DeleteInstanceAccessControlAttributeConfiguration",
"sso:DeletePermissionSet",
"sso:ProvisionPermissionSet",
"sso:PutInlinePolicyToPermissionSet",
"sso:AttachManagedPolicyToPermissionSet",
"sso:DeletePermissionsPolicy",
"sso:DetachManagedPolicyFromPermissionSet",
"sso:PutPermissionsPolicy",
"sso:UpdatePermissionSet"
],
"Resource": [
"arn:aws:sso:::account/123456789101",
"arn:aws:sso:::account/123456789101",
"arn:aws:sso:::account/123456789101"
]
},
{
"Sid": "Permissions",
"Effect": "Allow",
"Action": [
"sso:DescribeAccountAssignmentCreationStatus",
"sso:DescribeAccountAssignmentDeletionStatus",
"sso:DescribeInstanceAccessControlAttributeConfiguration",
"sso:DescribePermissionSet",
"sso:DescribePermissionSetProvisioningStatus",
"sso:DescribePermissionsPolicies",
"sso:DescribeRegisteredRegions",
"sso:GetInlinePolicyForPermissionSet",
"sso:GetPermissionSet",
"sso:GetPermissionsPolicy",
"sso:GetSharedSsoConfiguration",
"sso:GetSsoConfiguration",
"sso:ListProfileAssociations",
"sso:SearchGroups",
"sso:SearchUsers",
"sso:ListAccountAssignmentCreationStatus",
"sso:ListAccountAssignmentDeletionStatus",
"sso:ListAccountAssignments",
"sso:ListAccountsForProvisionedPermissionSet",
"sso:ListPermissionSets",
"sso:ListPermissionSetsProvisionedToAccount",
"sso:ListProfiles",
"sso:ListDirectoryAssociations",
"sso-directory:*",
"sso:Get*",
"sso:List*",
"sso:Describe*",
"sso:Search*",
"organizations:*"
],
"Resource": "*"
}
]
}

What’s next?

We hope to have shed some light on some of the foundational work we did from decision making to actual implementation of our identity model. This is still early days, we are planning to extend our AWS SSO as a single SAML endpoint for our applications, as highlighted in Setting up VPN with AWS and extending that to all our internal/external applications to have a consistent authentication/authorization model.

--

--