Skip to content
adatum
  • Home
  •  About adatum
  •  Learn Azure Bicep
  •  SCOM Web API
Azure Active Directory

GitHub actions federated identity with Azure AD

  • 24/08/202224/08/2022
  • by Martin Ehrnst

A long-awaited feature for many is the ability to authenticate with Azure in a GitHub workflow. For a long time, this has been an integrated feature in Azure DevOps, and for some time GitHub actions have had the ability to authenticate using Azure Application registrations and secrets. But now, we can use federated credentials which utilize OIDC- This will completely remove the cumbersome task of rotating app secrets.

Configure an Azure Application with federated identity

At my company, I have decided we should look into moving pipelines from Azure DevOps to GitHub. Federated identity is now Generally Available (GA) which means we are allowed to work with a production solution in mind. So how do you set it up? my suggestion is to follow the official guide. Below is a script that will configure an Azure AD application with GitHub authentication enabled. The script assumes you use a branching strategy. However, you can change this to be any of the other entity types, altering the federationSubcject variable.

# creates an appregistration in Azure AD and connects it with a github repo
# use as an example only
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]
$gitHubRepoName,
[Parameter(Mandatory)]
[string]
$teamName,
[Parameter(Mandatory)]
[string]
$branchName = "main"
)
$organization = "myorgltd"
$appRegistrationName = "gh-$teamName-action-sp"
$appRegistrationDescription = "Used by $teamName for enabeling GitHub actions with Azure AD OIDC authentication"
$audience = "api://AzureADTokenExchange"
$ghIssuer = "https://token.actions.githubusercontent.com/"
$federationName = "action-$gitHubRepoName"
$federationSubject = "repo:$($organization)/$($gitHubRepoName):ref:refs/heads/$($branchName)"
# check if app exists
$GhAdApp = $null
$GhAdApp = Get-AzADApplication –DisplayName $appRegistrationName
if ($GhAdApp) {
Write-Output "App registration already exist. Adding new credential for specified repo $gitHubRepoName"
$federatedCred = New-AzADAppFederatedCredential –ApplicationObjectId $GhAdApp.Id `
–Audience $audience –Issuer $ghIssuer –Subject $federationSubject `
–Name $federationName –Description "Used to authenticate pipeline in $gitHubRepoName"
}
# if app does not eist
else {
Write-Output "adding new app registration for $teamName with credentials for $gitHubRepoName"
$GhAdApp = New-AzADApplication –DisplayName $appRegistrationName –Description $appRegistrationDescription
$federatedCred = New-AzADAppFederatedCredential –ApplicationObjectId $GhAdApp.Id `
–Audience $audience –Issuer $ghIssuer –Subject $federationSubject `
–Name $federationName –Description "Used to authenticate pipeline in $gitHubRepoName"
}
$credentialObject = [PSCustomObject]@{
ApplicationName = "$($GhAdApp.DisplayName)"
ApplicationObjectId = "$($GhAdApp.Id)"
}
Write-Output $credentialObject | ConvertTo-Json
view raw create-adappgithub.ps1 hosted with ❤ by GitHub

Configure repository secrets in GitHub using PowerShell

As you probably understand, I need to automate this entire process. If our developers are moving from DevOps to Github workflows, it has to be as easy as it can be. No one will move unless they see some benefits, and onboarding is just as easy as the current DevOps setup. I am pretty familiar with Azure as an identity platform, especially with app registrations and enterprise apps. So the above script was done quickly. On the other hand, I am not that familiar with GitHub APIs. I know there’s a CLI, but for various reasons, I need to look into the API, more specifically the repository secrets API. What you can see from the first part of the documentation is that you need to encrypt the secret before you make the put request.

Creates or updates an organization secret with an encrypted value. Encrypt your secret using LibSodium. 

GitHub api docs

Now I was in trouble. Should I write everything in .NET, or is it possible to solve this using PowerShell? For sure I would be better off using PowerShell, at least in the PoC phase. First I tried to load the .NET sodium DLLs in my script, but it did not work, and the approach is not that delightful. Luckily with some search engine work, I found a module that wraps Sodium, created specifically for creating secrets in GitHub. Thanks, Tyler! See my example script below.

# add secrets to repo
import-module PSSodium
$ghToken = "ghp_"
$headers = @{Authorization = "token " + $ghToken}
$secret = "fb4ca569-c690-4391-96d9-928e7a8fd7ff"
$repoName = "myrepo"
$organization = "myorgltd"
Invoke-RestMethod –Method get –Uri "https://api.github.com/repos/$($organization)/$($repoName)/actions/secrets" –Headers $headers
$publicKey = (Invoke-RestMethod –Method get –Uri "https://api.github.com/repos/$($organization)/$($repoName)/actions/secrets/public-key" –Headers $headers)
$encryptedSecret = ConvertTo-SodiumEncryptedString –Text $secret –PublicKey $($publicKey.key)
$secretBody = @"
{
"encrypted_value": "$encryptedSecret",
"key_id": "$($publicKey.key_id)"
}
"@
Invoke-RestMethod –Method Put –Uri "https://api.github.com/repos/$($organization)/$($repoName)/actions/secrets/AZURE_TENANT_ID" –Headers $headers –body $secretBody
view raw create-ghsecret.ps1 hosted with ❤ by GitHub

What about the pipeline?

Next, you need a working pipeline. Lucky for you the documentation is way better when I first looked at this (before GA), so the example works just fine as it is. Anyway, there are a couple of things to point out. Namely the permissions and the setting for login without a subscription ID.

View this gist on GitHub

Summary

I hope this short post on how to configure Azure and GitHub with federated identity helps you, and that it provided some more information than the official documentation does. If anything please reach out. I now have my scripts in place, and can start the full automation and migration from Azure DevOps pipelines.

Share this:

  • LinkedIn
  • Twitter
  • Reddit
Azure

How to move Azure blobs up the path

  • 25/01/202225/01/2022
  • by Martin Ehrnst

This is the short, but for me, pretty intense story from when I uploaded 900 blobs of one Gb each to the wrong path in a storage container. Eventually I was able to move these files using azcopy and PowerShell

Thanos persistent Prometheus metrics

In our Azure Kubernetes environment (AKS) we use Prometheus and Thanos for application metrics. Thanos allow us to use Azure Storage for long term retention and high availability Prometheus setup. The other day I was challenged with deleting a series of metrics causing high cardinality. Meaning that a lot of new series of data was written due to a parameter being inserted during scraping.

The way Thanos works is that it takes raw prometheus data, downsamples it and upload it to Azure Storage for long term retention. Each time this process runs, it will create a new blob. In our production environment we had around 900 blobs and 900gb of data.

Thanos has a built in tool to rewrite these blobs and remove the metric we wanted, which seemed easy enough to do, but we had no idea when the problem first started, so I had to analyze, rewrite and upload all the data. It all seemed to work fine, util I discovered no metrics where available. It turned out that the tool I used inherited my local path and uploaded all the modified data to <guid>/chunks/c:/users/appdata/local/[...]/00001.blob

So no matter how satisfied I was, all the data was useless as thanos expected the files to be under <guid>/chunks/00001. On the bright side, all data was there, so the challenge was to move the files from <guid>/chunks/c:/users/appdata/local/[...] to <guid>/chunks/. From the two pictures below you can see the folder structure. Going trough a download and upload approach was the last thing I wanted to do.

Azure storage explorer

AzCopy and PowerShell to the rescue

I already knew my way around azcopy. But I did not know the process actually run on the Azure backbone if you copy within or between storage accounts. Luckily my dear Twitter friends was there to help where I failed to read the documentation.

To perform the copy operation I used a combination of Azure Powershell and AzCopy.

  • Connect
  • Get all current blobs
  • Filter them
  • Actually copy
  • Second loop to delete

Below is my complete script. This could be way smarter but I quickly put it together to get the job done.

## connect to storage using SAS
$storageName = ""
$sasToken = ""
$container = ""
$ctx = New-AzureStorageContext –StorageAccountName $storageName –SasToken $sasToken
# get all the blobs
$blobs = Get-AzureStorageBlob –Container $container –Context $ctx
# a date to filter on
$date = (get-date –Date 20.01.2022 –AsUTC)
# filter the blobs for date and where name has /c:/..
$blobsToModify = $blobs | where { ($_.LastModified.DateTime -ge $date) -and ($_.LastModified.DateTime -le $date.AddHours(24)) -and ($_.Name -like "*/chunks/C:/Users/*") }
# loop through the blobs
# get the original folder name and the blob name with some splitting
foreach ($blob in $blobsToModify) {
$blobtoMove = $blob.name
$original = $blob.Name.split("/",2)[0] # trim to original name
$newBlob = $blob.Name.split("/")[-1] # trim to original chunk name
# actually copy
./azcopy.exe copy "https://$storageName.blob.core.windows.net/thanos/$blobToMove$sasToken" "https://$storageName.blob.core.windows.net/thanos/$original/chunks/$newBlob$sasToken" —overwrite=prompt —s2s–preserve–access–tier=false —include–directory–stub=false —recursive —log–level=INFO;
}
# antother loop to delete the whole c:/ folder after the chunks of data is moved
# i have a separate loop as there might be multiple chunks in the folder.
foreach ($blob in $blobsToModify) {
$original = $blob.Name.split("/",2)[0] # trim to original name
./azcopy.exe remove "https://$storageName.blob.core.windows.net/thanos/$original/chunks/C%3A/$sasToken" —from–to=BlobTrash —recursive —log–level=INFO;
}
view raw azcopy-move.ps1 hosted with ❤ by GitHub

Summary

I hope this helps someone else who accidentaly upload a lot of data to the wrong place. If you by any chance are using Thanos. I filed this as a bug.

Share this:

  • LinkedIn
  • Twitter
  • Reddit
Azure Active Directory

Azure token from a custom app registration

  • 20/01/202214/11/2022
  • by Martin Ehrnst

There’s no secret you can get an Azure AD token and access API resources like Microsoft Graph, Azure Resource Manager (ARM), etc. It’s also pretty straightforward to authenticate a custom API using client credentials. In fact, I have written about how to do that previously where we accessed a custom API built on Azure Functions. Authentication-wise, I also wrote a post on how to access the Azure Monitor REST APIs using client credentials (app registration).

Get an Azure token with delegated user credentials from a custom API

The above examples are fine. But they both use a separate app registration for authenticating against our custom API, the Azure Function, and against ARM to access Azure Monitor. But what if I want to use my own, personal credentials instead of client credentials. For ARM resources, like Azure Monitor, Resource Graph, etc. You can do that already using Azure CLI, or the PowerShell example below.

Connect-AzAccount
Get-AzAccessToken -ResourceUrl "https://management.azure.com"

Wheater you use Az CLI or PowerShell, the output is similar to the above. you can decipher the token using jwt.io. And get a human-readable output.

Always be careful when using services like JWT.io Your token is after all your credentials and can give access to resources.


App registration expose an API

Instead of specifying ARM as we did above, you can also generate a token against your custom app registration using delegated permissions from Azure CLI or PowerShell. The secret lies in the “expose and API”, or more specifically, “Authorized client applications”.

To allow delegated access and the ability to receive a token from your custom app registration do the following

  • Make sure your user is allowed to access the app, you can add that in the enterprise app blade.
  • Create a scope under “expose an API”
  • Add client application(s) to the scope
    • Azure CLI well-known client application ID: 04b07795-8ddb-461a-bbee-02f9e1bf7b46
    • Azure PowerShell well-known client application ID: 1950a258-227b-4e31-a9cf-717495945fc2

Get access token from custom API using Azure CLI or PowerShell

Pull out your favorite shell and change you’re ResourceUrl from management.azure.com to your app id or URI. In my case, this is api://adatum-auth-test-app

After getting the token you can again use JWT.io and see the details. Pay attention to the appId and aud. AppId in this case is Azure PowerShell.

Final words

This post has been laying around in my draft for more than a year. But yesterday I got a question from a colleague about this and figured it was time to release it to the masses.

The reason I had it laying in drafts is that I am unsure of the supportability from Microsoft and the potential security vulnerability it may add to your services. However, keep that in mind and use the feature when needed.
If you want to learn more about application registrations, enterprise apps, and managed identities in general. Please read my other post about the topic.

Share this:

  • LinkedIn
  • Twitter
  • Reddit

Posts navigation

1 2 3 … 10

Popular blog posts

  • Azure Application registrations, Enterprise Apps, and managed identities
  • SCOM 1801 REST API Interfaces
  • Creating Azure AD Application using Powershell
  • Automate Azure DevOps like a boss
  • Access to Blob storage using Managed Identity in Logic Apps - by Nadeem Ahamed

Categories

Automation Azure Azure Active Directory Azure Bicep Azure DevOps Azure Functions Azure Lighthouse Azure Logic Apps Azure Monitor Azure Policy Community Conferences CSP Monitoring DevOps Guest blogs Infrastructure As Code Microsoft CSP MPAuthoring OMS Operations Manager Podcast Powershell Uncategorised Windows Admin Center Windows Server

Follow Martin Ehrnst

  • Twitter
  • LinkedIn

RSS feed RSS - Posts

RSS feed RSS - Comments

Microsoft Azure MVP

Martin Ehrnst Microsoft Azure MVP
Adatum.no use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it. Cookie Policy
Theme by Colorlib Powered by WordPress