AWS IAM Identity Center Integration with Microsoft Entra SSO (Azure AD) Using Infrastructure as Code (IaC)

thobekani ndlovu
4 min readNov 17, 2023

--

Managing user access to AWS resources can be a challenging task, especially in complex enterprise environments. One effective solution is to integrate Microsoft Entra with AWS Single Sign-On (AWS IAM Identity Center), allowing users to access AWS resources using their Azure AD credentials. In this technical article, we’ll explore how to achieve some parts of this integration using Infrastructure as Code (IaC) principles, specifically with Terraform, and the benefits it brings to the table.

The Power of IaC for Azure AD and AWS SSO Integration

Infrastructure as Code (IaC) is a methodology that allows you to manage and provision infrastructure resources programmatically. By using IaC, you can automate the setup and configuration of complex systems, ensuring consistency, repeatability, and reducing the likelihood of human error.

Setting Up Azure AD Integration

In this section, we’ll delve into the steps required to set up Azure AD integration using Terraform:

Azure AD & AWS SSO Configuration

https://learn.microsoft.com/en-us/entra/identity/saas-apps/aws-single-sign-on-tutorial

You also have the option of utilizing the Terraform Azure AD provider to specify and generate certain components within this configuration.

While AWS SSO instance setup might require manual configuration due to the limited Terraform support, you can still use Terraform data sources to gather details and reference the instance ARN in your code.

Generating Secrets for Automated Provisioning

When creating an AWS SSO instance, you have the option to enable automatic provisioning. This can be configured at any time within the AWS SSO settings, specifically in the “Identity Source” section, where you can manage provisioning settings.

Defining Permission Sets

Permission sets in AWS SSO are akin to roles with specific permissions. Understand how to define these sets to determine what actions users from Azure AD can perform within AWS.

locals {

managed_permissions = {
SomeAccess1 = {
description = ""
session_duration = ""
managed_policy_arn = ""
},
SomeAccess2 = {
description = ""
session_duration = ""
managed_policy_arn = ""
}
}
}

##Create a Permission Set
resource "aws_ssoadmin_permission_set" "ad_perms" {
for_each = local.managed_permissions
name = each.key
description = each.value.description
session_duration = each.value.session_duration
instance_arn = tolist(data.aws_ssoadmin_instances.azure_ad.arns)[0]
tags = merge(
local.tags,
var.custom_tags,
tomap({ "Name" = each.key}),
)
}

##Define Policy For Permission Set
resource "aws_ssoadmin_managed_policy_attachment" "policy_attachment" {
for_each = local.managed_permissions
instance_arn = tolist(data.aws_ssoadmin_instances.azure_ad.arns)[0]
managed_policy_arn = each.value.managed_policy_arn
permission_set_arn = aws_ssoadmin_permission_set.this[each.key].arn
}

Utilize the local map above to specify the permission sets for your organization. These permission sets can be shared among various groups, streamlining the management process irrespective of the number of groups within Azure AD. To retrieve the manually created AWS SSO Instance, you can query AWS using a data source.

data "aws_ssoadmin_instances" "azure_ad" {}

Assigning Permission Sets

Discover how to assign permission sets to groups or users within the context of specific AWS accounts. AWS SSO will automatically provision these permissions and roles for the assigned users or groups.

resource "aws_ssoadmin_account_assignment" "assignment" {
count = length(var.azure_ad_group_accounts)
instance_arn = var.instance_arn
permission_set_arn = var.permission_set_arn
principal_id = var.principal_id
principal_type = var.principal_type
target_id = var.azure_ad_group_accounts[count.index]
target_type = var.target_type
}

In scenarios where you need to allocate permissions to a group across multiple accounts, consider employing the “count” feature. A more effective strategy involves incorporating the aforementioned resource as a local module. This enables the definition of a local map, facilitating diverse group assignments across various accounts. The Ids of the group synced from AD can also be retrieved using data source.

data "aws_identitystore_group" "azure_ad_group" {
for_each = local.azure_ad_groups
identity_store_id = tolist(data.aws_ssoadmin_instances.azure_ad.identity_store_ids)[0]

filter {
attribute_path = "DisplayName"
attribute_value = each.value.ad_group_name
}
}


module "assignment" {
source = "./modules/assignment"

for_each = local.azure_ad_groups

instance_arn = aws_ssoadmin_permission_set.this[each.value.permission_set].instance_arn
permission_set_arn = aws_ssoadmin_permission_set.this[each.value.permission_set].arn
principal_id = data.aws_identitystore_group.azure_ad_group[each.key].group_id
azure_ad_group_accounts = each.value.aws_accounts

}

locals{

azure_ad_groups = {
ad_group1= {
aws_accounts = ["1111111111","222222222"]
description = "SomeAccess1 users account access",
ad_group_name = "ad_group1"
permission_set = "SomeAccess1"
},
ad_group2 = {
aws_accounts = ["222222222","3333333333"]
description = "SomeAccess2 users account access",
ad_group_name = "ad_group2"
permission_set = "SomeAccess2"
}

}

Custom Inline Policies

Opting for inline policies instead of custom policies offers enhanced flexibility and control in access management. These inline policies can be deployed from your AWS SSO account and synchronized across all accounts where the permission set is applied. Inline policies are particularly useful when you need to supplement permissions beyond those provided by an AWS Managed Policy in specific scenarios.

resource "aws_ssoadmin_customer_managed_policy_attachment" "custom_Access" {
instance_arn = aws_ssoadmin_permission_set.this["SomeAccess1"].instance_arn
permission_set_arn = aws_ssoadmin_permission_set.this["SomeAccess1"].arn
customer_managed_policy_reference {
name = aws_iam_policy.custom_access_role_policy.name
path = "/"
}
}

resource "aws_iam_policy" "custom_access_role_policy" {
policy = data.template_file.custom_access_role_policy.rendered
name = "${local.name_prefix}-custom-policy"
}

data "template_file" "custom_access_role_policy" {
template = file("${path.module}/policies/custom_access_role_policy.json")
}

Benefits of Using IaC for Azure AD Integration with AWS SSO

- Efficiency: Automating the integration reduces manual work and speeds up the process.

- Consistency: IaC ensures that the setup is uniform and repeatable across environments.

- Scalability: As your organization grows, IaC can easily accommodate changes and additions.

- Maintenance: Updating configurations is simplified, reducing the risk of errors.

Conclusion

Integrating Microsoft Entra SSO with AWS SSO (IAM Identity Center) using Infrastructure as Code is a powerful approach to streamline access management. With Terraform, you can automate the setup, manage configurations efficiently, and enhance security by maintaining consistency. This integration not only simplifies user access but also contributes to a more robust and manageable IAM strategy in your organization.

--

--

thobekani ndlovu

Public cloud infrastructure architecture and engineering. Specializing in Cloud platform engineering & API Design.