{"id":68479,"date":"2024-02-12T23:16:32","date_gmt":"2024-02-13T07:16:32","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/devops\/?p=68479"},"modified":"2024-02-12T23:17:33","modified_gmt":"2024-02-13T07:17:33","slug":"workload-identity-federation-for-azure-deployments-is-now-generally-available","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/workload-identity-federation-for-azure-deployments-is-now-generally-available\/","title":{"rendered":"Workload identity federation for Azure deployments is now generally available"},"content":{"rendered":"<p>In September, we <a href=\"https:\/\/devblogs.microsoft.com\/devops\/public-preview-of-workload-identity-federation-for-azure-pipelines\/\">announced<\/a> the ability to configure Azure service connections that do not need a secret. Azure service connections that use workload identity federation are easier to manage and more secure. Many customers have adopted this feature and we&#8217;re excited to announce it is now generally available!<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/oidc-collaboration-4.png\" alt=\"Image oidc collaboration\" width=\"1250\" height=\"543\" class=\"aligncenter size-full wp-image-67562\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/oidc-collaboration-4.png 2500w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/oidc-collaboration-4-300x130.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/oidc-collaboration-4-1024x445.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/oidc-collaboration-4-768x334.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/oidc-collaboration-4-1536x668.png 1536w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/oidc-collaboration-4-2048x890.png 2048w\" sizes=\"(max-width: 1250px) 100vw, 1250px\" \/><\/p>\n<h3>Improved security<\/h3>\n<p>Workload identity federation enforces how an identity can be used. The federation subject (<code>sc:\/\/&lt;org&gt;\/&lt;project&gt;\/&lt;service connection name&gt;<\/code>) configured on the App Registration or Managed Identity can only be used in Azure DevOps, by the service connection the federation is configured for. This provides a stricter constraint than a secret, which could unintentionally be leaked and used for other purposes or from other locations.<\/p>\n<h3>No more worries about expiring secrets<\/h3>\n<p>Configuration of an Azure service connection with workload identity federation is a one-time setup. You don&#8217;t have to worry about expiring secrets that have to be rotated in order for the service connection to stay operational.<\/p>\n<h3>Getting started<\/h3>\n<p>If you haven&#8217;t used Workload identity federation yet, you can take advantage of worry-free Azure service connections in the following ways:<\/p>\n<p>To create a new Azure service connection using workload identity federation, select Workload identity federation (automatic) in the Azure service connection creation experience:<\/p>\n<p><center>\n  <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/create-service-connection2-1.png\" width=\"457\" \/>\n<\/center><\/p>\n<p>To convert a previously created Azure service connection created with a secret, select the &#8220;Convert&#8221; action after selecting the connection:<\/p>\n<p><center>\n  <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2023\/09\/convert-service-connection.png\" width=\"870\" \/>\n<\/center><\/p>\n<p>To convert multiple service connections that use a secret to use workload identity federation instead, you can use the below script as a basis:<\/p>\n<pre><code class=\"powershell\">#!\/usr\/bin\/env pwsh\n&lt;# \n.SYNOPSIS \n    Convert multiple Azure Resource Manager service connection(s) to use Workload identity federation\n\n.LINK\n    https:\/\/aka.ms\/azdo-rm-workload-identity-conversion\n\n.EXAMPLE\n    &lt;script&gt; -Project &lt;project&gt; -OrganizationUrl https:\/\/dev.azure.com\/&lt;organization&gt;\n#&gt; \n#Requires -Version 7.3\n\nparam ( \n    [parameter(Mandatory=$true,HelpMessage=\"Name of the Azure DevOps Project\")]\n    [string]\n    [ValidateNotNullOrEmpty()]\n    $Project,\n\n    [parameter(Mandatory=$true,HelpMessage=\"Url of the Azure DevOps Organization\")]\n    [uri]\n    [ValidateNotNullOrEmpty()]\n    $OrganizationUrl\n) \n$apiVersion = \"7.1\"\n\n#-----------------------------------------------------------\n# Log in to Azure\naz account show -o json 2&gt;$null | ConvertFrom-Json | Set-Variable account\nif (!$account) {\n    az login --allow-no-subscriptions -o json | ConvertFrom-Json | Set-Variable account\n}\n$OrganizationUrl = $OrganizationUrl.ToString().Trim('\/')\n\n#-----------------------------------------------------------\n# Retrieve the service connection\n$getApiUrl = \"${OrganizationUrl}\/${Project}\/_apis\/serviceendpoint\/endpoints?authSchemes=ServicePrincipal&type=azurerm&includeFailed=false&includeDetails=true&api-version=${apiVersion}\"\naz rest -u $getApiUrl -m GET --resource 499b84ac-1321-427f-aa17-267ca6975798 --query \"sort_by(value[?authorization.scheme=='ServicePrincipal' && data.creationMode=='Automatic' && !(isShared && serviceEndpointProjectReferences[0].projectReference.name!='${Project}')],&name)\" -o json `\n        | Tee-Object -Variable rawResponse | ConvertFrom-Json | Tee-Object -Variable serviceEndpoints | Format-List | Out-String | Write-Debug\nif (!$serviceEndpoints -or ($serviceEndpoints.count-eq 0)) {\n    Write-Warning \"No convertible service connections found\"\n    exit 1\n}\n\nforeach ($serviceEndpoint in $serviceEndpoints) {\n    # Prompt user to confirm conversion\n    $choices = @(\n        [System.Management.Automation.Host.ChoiceDescription]::new(\"&Convert\", \"Converting service connection '$($serviceEndpoint.name)'...\")\n        [System.Management.Automation.Host.ChoiceDescription]::new(\"&Skip\", \"Skipping service connection '$($serviceEndpoint.name)'...\")\n        [System.Management.Automation.Host.ChoiceDescription]::new(\"&Exit\", \"Exit script\")\n    )\n    $prompt = $serviceEndpoint.isShared ? \"Convert shared service connection '$($serviceEndpoint.name)'?\" : \"Convert service connection '$($serviceEndpoint.name)'?\"\n    $decision = $Host.UI.PromptForChoice([string]::Empty, $prompt, $choices, $serviceEndpoint.isShared ? 1 : 0)\n\n    if ($decision -eq 0) {\n        Write-Host \"$($choices[$decision].HelpMessage)\"\n    } elseif ($decision -eq 1) {\n        Write-Host \"$($PSStyle.Formatting.Warning)$($choices[$decision].HelpMessage)$($PSStyle.Reset)\"\n        continue \n    } elseif ($decision -ge 2) {\n        Write-Host \"$($PSStyle.Formatting.Warning)$($choices[$decision].HelpMessage)$($PSStyle.Reset)\"\n        exit \n    }\n\n    # Prepare request body\n    $serviceEndpoint.authorization.scheme = \"WorkloadIdentityFederation\"\n    $serviceEndpoint.data.PSObject.Properties.Remove('revertSchemeDeadline')\n    $serviceEndpoint | ConvertTo-Json -Depth 4 -Compress | Set-Variable serviceEndpointRequest\n    $putApiUrl = \"${OrganizationUrl}\/${Project}\/_apis\/serviceendpoint\/endpoints\/$($serviceEndpoint.id)?operation=ConvertAuthenticationScheme&api-version=${apiVersion}\"\n\n    # Convert service connection\n    az rest -u $putApiUrl -m PUT -b $serviceEndpointRequest --headers content-type=application\/json --resource 499b84ac-1321-427f-aa17-267ca6975798 -o json `\n            | ConvertFrom-Json | Set-Variable updatedServiceEndpoint\n\n    $updatedServiceEndpoint | ConvertTo-Json -Depth 4 | Write-Debug\n    if (!$updatedServiceEndpoint) {\n        Write-Debug \"Empty response\"\n        Write-Error \"Failed to convert service connection '$($serviceEndpoint.name)'\"\n        exit 1\n    }\n    Write-Host \"Successfully converted service connection '$($serviceEndpoint.name)'\"\n}\n<\/code><\/pre>\n<h3>Resources<\/h3>\n<ul>\n<li><a href=\"https:\/\/aka.ms\/azdo-rm-workload-identity\">Creating Azure service connections with Workload identity federation<\/a><\/li>\n<li><a href=\"https:\/\/aka.ms\/azdo-rm-workload-identity-conversion\">Converting Azure service connections<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/devops\/public-preview-of-workload-identity-federation-for-azure-pipelines\">Public preview of Workload identity federation for Azure Pipelines<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In September, we announced the ability to configure Azure service connections that do not need a secret. Azure service connections that use workload identity federation are easier to manage and more secure. Many customers have adopted this feature and we&#8217;re excited to announce it is now generally available! Improved security Workload identity federation enforces how [&hellip;]<\/p>\n","protected":false},"author":26231,"featured_media":67562,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[224,226],"tags":[],"class_list":["post-68479","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-ci"],"acf":[],"blog_post_summary":"<p>In September, we announced the ability to configure Azure service connections that do not need a secret. Azure service connections that use workload identity federation are easier to manage and more secure. Many customers have adopted this feature and we&#8217;re excited to announce it is now generally available! Improved security Workload identity federation enforces how [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/68479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/26231"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=68479"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/68479\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/67562"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=68479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=68479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=68479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}