Configure federated identity between GitHub and Azure with PowerShell
Tags: azure, powershell, github, devops
Published: 2024-04-04 23:13:27

Usually, when you want to connect a GitHub workflow to Azure, in order to manage resources, you use an Entra ID application (Azure AD). The main problem with using an App is that you need to manage a secret or a certificate. Most of the time people use a secret, it needs to be stored as a secret in GitHub, and it transits through the Internet when connecting to Azure.
But if instead of using a secret you can use a federated identity credential. It is a trust relationship between two entities, one entity can request a token and use this token to authenticate to Azure. In this case, no secret is exchanged. 
Federated identity works with an Entra ID app or a user-managed identity (but not with a system-managed identity). In the following example, I will use a user-managed identity.

The first step is to create a user-managed identity in a resource group

```powershell
$managedIdentity = New-AzUserAssignedIdentity -Name mi-test -ResourceGroupName managed-identity -Location northeurope 
```

This instruction creates the identity name mi-test in the North Europe Azure region in the resource group name managed-identity.
Now we can create the federated credential to be used in GitHub. 
You will need several pieces of information:
-	The organization, your account name for individual users, or your GitHub organization name.
-	The repository name.
-	Which entity to use, GitHub you can use:
 - The environment is an entity in GitHub where you can store secrets, environment variables, and other configuration settings.
 - Branch, the identity will be used when a workflow runs on this branch.
 - Pull Request, the identity will be used with each pull request.
 - Tag, the identity will be used when the tag is used.

For this example, I will use environment, as is simpler to understand. 
In a GitHub repo, go to settings and then environment. Create a new environment, for this example, I will use devTo-test.
To create the federated credential for the newly managed identity we need, at least, two things, an issuer (who requests the identity), for GitHub it is https://token.actions.githubusercontent.com, and a subject. The subject is a URI starting with “repo” and with all the information needed, organization, repository name, ... everything separated by a :

```powershell
$repoName = "devtoDemo"
$githubOrga = "myOraName"
$environmentName = "devTo-test"

$subjectUri =  "repo:$($githubOrga)/$($repoName):environment:$($environmentName)"
```
Now we can create the federated credential. 

```powershell
New-AzFederatedIdentityCredentials -ResourceGroupName managed-identity -IdentityName mi-test -Name $managedIdentity.name -Issuer "https://token.actions.githubusercontent.com" -Subject $subjectUri
```
Now we can configure a workflow in the GitHub repository. To allow a workflow to connect to Azure with the federated identity you need to configure a workflow. In the YAMl file defining the workflow, you need to indicate which environment you use.
You can do it when you configure a job.

```yaml
jobs:

  test-identity:
    name: run azure workflow
    runs-on: ubuntu-latest
    environment: devTo-test
```
Then when you need to log in to Azure you just need to use the azure/login step without needing to add a secret or anything else. You just need to indicate the tenant ID and the client-id of the managed identity (you can get it with $managedIdentity.PrincipalId. 

```yaml
      - name: Login to Azure
        uses: azure/login@v1
        with:
          client-id: principal ID
          tenant-id: Tenant ID
          subscription-id:  Target Subscription ID 
          enable-AzPSSession: true
```
Nothing else is needed, no secret or certificate. The best practice is to get the client ID, Tenant ID, and Subscription ID as a secret from the environment.

```yaml
      - name: Login to Azure
        uses: azure/login@v1
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id:  ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          enable-AzPSSession: true
```

When you do not need the federate credential, you can run 

```powershell
remove-AzFederatedIdentityCredentials -ResourceGroupName managed-identity -IdentityName mi-test -Name fic-test
```