Checking out Azure AD cross tenant access policies

So, as one does, I was checking out the different Microsoft Graph AppRoles, which are the application scopes available. And then I found this:

Now, I now cross tenant access is something Microsoft has been working on for a while, and I have seen some preview stuff presented, but I have no access to any preview at all at this point. However, let’s see what we can find!

Disclaimer: Do not use this in production, as it is only a private preview feature I discovered.

Continue reading “Checking out Azure AD cross tenant access policies”

Another deep dive into Azure AD Workload Identity Federation using GitHub actions

I just had a previous blogpost about Workload Identity Federation, where I went into the details of how authentication works. This time, I want to use GitHub actions, which is the currently supported method. There are some limitations to the documentation today, but hopefully we will be able to do things like accessing KeyVaults and other services, not only using Azure CLI.

Continue reading “Another deep dive into Azure AD Workload Identity Federation using GitHub actions”

A deep dive into Azure AD Workload identity federation

Workload Identity Federation is a rather new concept in Azure AD, where service principals do not have keys in a directory, but in stead is federated to an external OpenID Connect (OIDC) provider, such as Okta, Ping, Github, GCP, AWS and – well – Azure AD.

A part of an earlier blogpost used a JWT in a client credential grant, signed by a KeyVault based certificate, to authenticate as an application. This time, this JWT will not be signed by a certificate, but instead by an OIDC provider.

Continue reading “A deep dive into Azure AD Workload identity federation”

Script to create named locations for Azure regions

Just built a quick little script that creates named locations for conditional access based on the IP addresses provided and updated by Microsoft, through a json file.

By using this script to manage named locations, you can, through the workload identities conditional access policies currently in preview, limit where your service principals can be used from. You can say things like “These service principals can only be used from Azure region West Europe”.

Find it here in my GitHub!

Assigning PIM Azure RBAC permissions using Terraform and ARM template

Currently, Terraform does not support eligible assignments of permissions in Azure RBAC, and only active assignments using the azurerm_role_assignment resource. Continue reading if you want to be able to assign your eligible assignments using ARM or Terraform (Terraform willl use the ARM template).

Continue reading “Assigning PIM Azure RBAC permissions using Terraform and ARM template”

Getting the Azure AD Connect version using API

Finally the Azure AD Connect version is available through the Azure Portal:

But I am more interested in getting this using an API, as I am checking things towards customer tenants. Looking at the API calls behind the Azure Portal, we can find that it is using some endpoints from management.azure.com:

Step 1 – Getting the required access token

You can use the well known 1950a258-227b-4e31-a9cf-717495945fc2 app id with ROPC to get an access token as follows, only username and password required:

$secrets = @{
    username = "abc@demo.com"
    password = "MyPassword"
}

# Create uri and body - AAD graph (deprecated)
$uri = "https://login.microsoftonline.com/{0}/oauth2/token" -f $secrets.tenant
$body = "resource=https://management.azure.com/&client_id=1950a258-227b-4e31-a9cf-717495945fc2&grant_type=password&username={1}&password={0}" -f [System.Net.WebUtility]::UrlEncode($secrets.password), $secrets.username

# Get access token and build header
$token = $null
try {
    $token = Invoke-RestMethod $uri -Body $body -ContentType "application/x-www-form-urlencoded" -ErrorAction SilentlyContinue
} catch {
    Write-Error "Exception when getting AAD access token" -Exception $_
}

if($token.access_token) {
    $Global:HeadersForAzure = @{Authorization = "Bearer $($token.access_token)"}
} else {
    Write-Error "Unable to retrieve access token for https://management.azure.com"
}

Step 2 – Getting the latest actual version from Github

This step is not really crucial, but you can easily fetch the latest version from the Azure AD Connect version history, in order to compare to your tenant:

# Get latest version from Github
$VersionHistory = Invoke-RestMethod "https://raw.githubusercontent.com/MicrosoftDocs/azure-docs/master/articles/active-directory/hybrid/reference-connect-version-history.md"
$_LatestVersion = $VersionHistory -split "`n" | 
    Where-Object {$_ -match "^## [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"} |
    ForEach-Object {$_ -replace "## "} |
    Sort-Object | 
    Select-Object -Last 1

if($_LatestVersion -notmatch "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") {
    New-PolicyResult -Policy $Policy -Status "Failed" -StatusDetail "Unable to determine latest version of Azure AD Connect"
}

$LatestVersion = [Version] $_LatestVersion

Step 3 – Working with the API

Now we are ready to work with the API. Remember, this is an undocumented API, and it is prone to change without notification from Microsoft:

# Get AAD Connect Health service
$PremiumCheck = Invoke-RestMethod -Uri 'https://management.azure.com/providers/Microsoft.ADHybridHealthService/services/GetServices/PremiumCheck?serviceType=AadSyncService&skipCount=0&takeCount=50&api-version=2014-01-01' -Headers $Global:HeadersForAzure

if(!$PremiumCheck.Value) {
    throw "Unable to get Azure AD Connect configuration from management.azure.com"
}

# Check Azure AD Connect status being healthy
if($PremiumCheck.value[0].health -ne "Healthy") {
    throw "Azure AD Connect service not healthy"
}

# Get all servers providing the Azure AD Connect service
$ServiceMembers = Invoke-RestMethod -Uri "https://management.azure.com/providers/Microsoft.ADHybridHealthService/services/$($PremiumCheck.value[0].serviceName)/servicemembers?api-version=2014-01-01" -Headers $Global:HeadersForAzure

# Process servers, checking version, health and version
$ServiceMembers.value | ForEach-Object {
    if(([Version] $_.osVersion) -lt ([Version] "10.0.14393.0")) {
        throw "Server $($_.machineName) running too old operating system Windows build $($_.osVersion)"
    }

    if($_.Status -ne "Healthy") {
        throw "Server $($_.machineName) is not healthy, according to Azure AD Connect Health"
    }

    $ServiceConfiguration = Invoke-RestMethod -Uri "https://management.azure.com/providers/Microsoft.ADHybridHealthService/services/$($PremiumCheck.value[0].serviceName)/servicemembers/$($_.serviceMemberId)/serviceconfiguration?api-version=2014-01-01" -Headers $Global:HeadersForAzure

    if(([Version] $ServiceConfiguration.version) -lt $LatestVersion) {
        throw "Server $($_.machineName) is running version $($ServiceConfiguration.version) of Azure AD Connect, which is not the latest ($LatestVersion)"
    }
}

This API might be different in a few weeks, which means the example will stop working, but that’s life 🙂

Automating certificate rollover for Azure AD applications using Azure Functions and KeyVault

There are several documentation pages on docs.microsoft.com on managing application registration certificate rollover, including several github repos from Microsoft, all of which are either using a silly approach with high privileged user account (Global Admin, Application Admin, etc) or does not delve into details on how to solve the issue with least privilege and in a proper automated fashion when using KeyVault.

In this post I will try to document a few of the things I have experienced while implementing this using the addKey Graph endpoint.

Continue reading “Automating certificate rollover for Azure AD applications using Azure Functions and KeyVault”