This article shows how to import AzureAD app role assignments into the Terraform state. With app role assignments, AzureAD users, groups, or service principals are assigned a role in an application. Source.
In the use case I'm writing about, AzureAD groups are assigned a role "User" in the AzureAD enterprise application for Snowflake, allowing members of those AzureAD groups to single sign-on to Snowflake.
In short
- The problem
- Get Microsoft Graph API token
- List existing app role assignments using the Graph API
- Import existing app role assignments into the Terraform state
- Conclusion
Context
Creating and managing a data platform involves managing its infrastructure and user access among other things. In the data platform my team is managing, we use Snowflake for analytical data warehousing and user access is managed from AzureAD (Microsoft Entra).
This setup allows us to use existing AzureAD users and groups and grant them access to roles inside of Snowflake. In short, adding a group named "ECOM_SALES" will allow any member of that group to log in to Snowflake and use a functional role named ECOM_SALES
.
Below is a screenshot of the Snowflake enterprise application showing multiple groups assigned the role "User":
Being strong believers in infrastructure-as-code, my team manages the entire platform with Terraform. However, during the very early days, some changes were done manually, such as adding AzureAD groups to the enterprise application for Snowflake single sign-on.
Access management is an important part of the overall platform security and as such should be managed through code. Manual configuration can be overlooked during migrations, it does not follow the four-eyes principle which can cause outages and does not provide a stable foundation for a data platform.
The problem
With the understanding of why we want to manage all AzureAD app role assignments with Terraform, let's see how those added manually can be imported and managed with Terraform.
The docs state that app role assignments are imported with:
terraform import \
azuread_app_role_assignment.example \
00000000-0000-0000-0000-000000000000/appRoleAssignment/aaBBcDDeFG6h5JKLMN2PQrrssTTUUvWWxxxxxyyyzzz
where:
-
00000000-0000-0000-0000-000000000000
is the object ID of the service principal object associated with your AzureAD enterprise application for Snowflake. -
aaBBcDDeFG6h5JKLMN2PQrrssTTUUvWWxxxxxyyyzzz
is the app role assignment ID.
I had absolutely no idea where to find the real value of aaBBcDDeFG6h5JKLMN2PQrrssTTUUvWWxxxxxyyyzzz
in the UI.
Since Terraform providers communicate with 3rd party APIs (AWS, AzureAD etc...) I figured I could do the same.
Get Microsoft Graph API token
Microsoft's Graph API allows programmatic access to the Microsoft Cloud service resources.
To use it, you must authenticate and obtain a JWT:
TOKEN=$(curl -d grant_type=client_credentials \
-d client_id=$CLIENT_ID \
-d client_secret=$CLIENT_SECRET \
-d scope=https://graph.microsoft.com/.default \
-d resource=https://graph.microsoft.com \
https://login.microsoftonline.com/$TENANT_ID/oauth2/token |
jq -j .access_token)
Of course, export CLIENT_ID
, CLIENT_SECRET
and TENANT_ID
first.
List existing app role assignments using the Graph API
Having the JWT in the TOKEN
variable, we can list the existing app role assignment for group ECOM_SALES
in the AzureAD enterprise application for Snowflake with ID 1ab2c3de-f456-7890-fghi-j12345k67lm8
:
ASSIGNMENT_ID=$(curl -sX GET \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
https://graph.microsoft.com/v1.0/servicePrincipals/1ab2c3de-f456-7890-fghi-j12345k67lm8/appRoleAssignedTo |
jq '.value[] | select(.principalDisplayName =="ECOM_SALES").id')
The API returns:
{
"@odata.context": "LINK_HERE",
"@odata.nextLink": "LINK_HERE",
"value": [
{
"id": "ZMW3ujNOGUuENMLa2k6-mVWFENfBHbVDlwQJg1ui848",
"deletedDateTime": null,
"appRoleId": "33c0d484-efdc-4e65-b6fc-470f4bcb4f46",
"createdDateTime": "2023-02-17T08:48:17.1803369Z",
"principalDisplayName": "ECOM_SALES",
"principalId": "bab7c564-4e33-4b19-8434-c2dada4ebe99",
"principalType": "Group",
"resourceDisplayName": "Snowflake AAD",
"resourceId": "1ab2c3de-f456-7890-fghi-j12345k67lm8"
}
]
}
and our variable ASSIGNMENT_ID
has the value ZMW3ujNOGUuENMLa2k6-mVWFENfBHbVDlwQJg1ui848
.
With this value we now have all the elements necessary to import this app role assignment into the Terraform state.
Multiple assignments
In a situation where you have multiple AzureAD app role assignments for groups such as ECOM_SALES
, ECOM_FINANCE
and ECOM_LEGAL
, you can use the following jq
expression to list them all:
.value[] | select(.principalDisplayName | startswith("ECOM_"))
Import existing app role assignments into the Terraform state
Having the app role assignment ID in a variable named ASSIGNMENT_ID
and the AzureAD enterprise application for Snowflake having ID 1ab2c3de-f456-7890-fghi-j12345k67lm8
, we can:
terraform import \
azuread_app_role_assignment.example \
1ab2c3de-f456-7890-fghi-j12345k67lm8/appRoleAssignment/$ASSIGNMENT_ID
Conclusion
This article provided a quick solution for importing Azure AD app role assignments into Terraform, addressing the challenge of manual interventions in infrastructure management. Leveraging Microsoft's Graph API and Terraform, we demonstrated a streamlined process to list and import app role assignments.
Top comments (0)