Public/Discovery/Get-FederatedIdentityCredential.ps1
|
function Get-FederatedIdentityCredential { [cmdletbinding()] param ( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias('identity-name', 'user-assigned-identity')] [string]$Name, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias('resource-id', 'Id')] [string]$ResourceId, [Parameter(Mandatory = $false)] [ValidateSet("Object", "JSON", "CSV", "Table")] [Alias("output", "o")] [string]$OutputFormat = "Table" ) begin { Write-Verbose "Starting function $($MyInvocation.MyCommand.Name)" $MyInvocation.MyCommand.Name | Invoke-BlackCat } process { try { $results = @() $managedIdentities = @() # Determine which managed identities to query if ($ResourceId) { Write-Host "Using provided Resource ID..." -ForegroundColor Cyan $managedIdentities += [PSCustomObject]@{ id = $ResourceId name = ($ResourceId -split '/')[-1] } } elseif ($Name) { Write-Host "Looking up Managed Identity: $Name..." -ForegroundColor Cyan $uami = Get-ManagedIdentity -Name $Name -OutputFormat Object if ($uami) { $managedIdentities += $uami Write-Host " Found managed identity" -ForegroundColor Green } else { Write-Host " Managed identity not found: $Name" -ForegroundColor Red return } } else { Write-Host " Retrieving all User Assigned Managed Identities..." -ForegroundColor Cyan $managedIdentities = Get-ManagedIdentity -OutputFormat Object Write-Host " Found $($managedIdentities.Count) managed identities" -ForegroundColor Green } $totalFics = 0 foreach ($uami in $managedIdentities) { Write-Verbose "Querying federated credentials for: $($uami.name)" $ficUrl = "https://management.azure.com$($uami.id)/federatedIdentityCredentials?api-version=2023-01-31" try { $fics = Invoke-RestMethod -Uri $ficUrl -Headers $script:authHeader -Method GET if ($fics.value -and $fics.value.Count -gt 0) { $totalFics += $fics.value.Count foreach ($fic in $fics.value) { $enhancedFic = [PSCustomObject]@{ 'Name' = $uami.name 'Credential Name' = $fic.name 'Subject' = $fic.properties.subject 'Issuer' = $fic.properties.issuer 'Audiences' = ($fic.properties.audiences -join ', ') 'ResourceGroup' = ($uami.id -split '/')[4] 'ResourceId' = $uami.id } $results += $enhancedFic } } } catch { Write-Verbose "Could not retrieve federated credentials for $($uami.name): $($_.Exception.Message)" } } if ($results.Count -gt 0) { Write-Host "`nFederated Identity Credential Summary:" -ForegroundColor Magenta Write-Host " Managed Identities Scanned: $($managedIdentities.Count)" -ForegroundColor White Write-Host " Total Federated Credentials: $totalFics" -ForegroundColor Yellow # Group by issuer for summary $issuerCounts = $results | Group-Object 'Issuer' | Sort-Object Count -Descending Write-Host " Issuers:" -ForegroundColor Cyan foreach ($group in $issuerCounts) { $issuerName = $group.Name if ($issuerName -eq 'https://token.actions.githubusercontent.com') { $issuerName = "GitHub Actions" } elseif ($issuerName -match 'sts\.windows\.net') { $issuerName = "Azure AD" } elseif ($issuerName -match 'login\.microsoftonline\.com') { $issuerName = "Microsoft Identity Platform" } Write-Host " $($issuerName): $($group.Count)" -ForegroundColor White } # Highlight potential security concerns $githubFics = $results | Where-Object { $_.Issuer -eq 'https://token.actions.githubusercontent.com' } if ($githubFics.Count -gt 0) { Write-Host "`n GitHub Actions Trust Relationships:" -ForegroundColor Yellow foreach ($ghFic in $githubFics) { Write-Host " • $($ghFic.'Identity Name'): $($ghFic.Subject)" -ForegroundColor White } } } else { Write-Host "`nNo federated identity credentials found" -ForegroundColor Red } # Format and return results Format-BlackCatOutput -Data $results -OutputFormat $OutputFormat -FunctionName $MyInvocation.MyCommand.Name } catch { Write-Message -FunctionName $($MyInvocation.MyCommand.Name) -Message "$($_.Exception.Message)" -Severity 'Error' } } <# .SYNOPSIS Retrieves federated identity credentials on managed identities. .DESCRIPTION Retrieves federated identity credentials on managed identities via Azure Resource Manager. These credentials enable workloads running outside Azure to obtain access tokens without storing secrets. Useful for discovering external workload connections and OIDC configurations on managed identities. .PARAMETER Name The name of a specific User Assigned Managed Identity to query. If not specified, all UAMIs in accessible subscriptions are queried. Aliases: identity-name, user-assigned-identity, Name .PARAMETER ResourceId The full Azure Resource ID of the managed identity. Aliases: resource-id, Id .PARAMETER OutputFormat Specifies the output format. Valid values are: Object, JSON, CSV, Table. Default: Table Aliases: output, o .EXAMPLE Get-FederatedIdentityCredential Retrieves all federated identity credentials from all accessible managed identities. .EXAMPLE Get-FederatedIdentityCredential -Name "uami-hr-cicd-automation" Retrieves federated credentials for a specific managed identity by name. .EXAMPLE Get-ManagedIdentity | Get-FederatedIdentityCredential Pipes managed identities to retrieve their federated credentials. .EXAMPLE Get-FederatedIdentityCredential -OutputFormat JSON Returns results in JSON format for further processing or export. .NOTES Author: Rogier Dijkman Security Note: Federated identity credentials can be abused by attackers who have Contributor access to a managed identity. They can add their own GitHub repository as a trusted issuer, then exchange GitHub OIDC tokens for Azure access tokens. .LINK MITRE ATT&CK Tactic: TA0007 - Discovery https://attack.mitre.org/tactics/TA0007/ .LINK MITRE ATT&CK Technique: T1526 - Cloud Service Discovery https://attack.mitre.org/techniques/T1526/ #> } |