{"id":2204,"date":"2022-09-20T09:57:27","date_gmt":"2022-09-20T16:57:27","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=2204"},"modified":"2022-09-23T09:10:55","modified_gmt":"2022-09-23T16:10:55","slug":"guidance-for-multi-tenant-applications-using-the-azure-identity-libraries","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/guidance-for-multi-tenant-applications-using-the-azure-identity-libraries\/","title":{"rendered":"Guidance for multi-tenant applications using the Azure Identity libraries"},"content":{"rendered":"<p>The Azure SDK team has become aware of a potential risk for developers using multi-tenant applications to access Azure resources. Most applications using multi-tenant applications are safe; however, multi-tenant applications that take user-provided URIs to Azure resources and authenticate via service-to-service authentication may leave their customers vulnerable to unauthorized access. Multi-tenant applications accepting URIs to user-provided resources must properly validate resource ownership to prevent potential leaks.<\/p>\n<p>Multi-tenant applications need to validate resource ownership as recommended below, and in addition, the Azure SDK team is releasing new versions of the Azure Identity libraries to help multi-tenant applications be secure by default and provide some defense in depth.<\/p>\n<h2>Affected applications<\/h2>\n<p>Multi-tenant applications that accept a user-provided URI to a customer-owned resource need to validate the ownership of that resource. Examples include, but aren&#8217;t limited to:<\/p>\n<ul>\n<li>URIs to Azure data plane services corresponding to customer owned resources<\/li>\n<li>URIs to other customer owned data sources or applications protected by Azure Active Directory<\/li>\n<\/ul>\n<p>Resource URIs could be provided through configuration files, command line interfaces (CLIs), or user interfaces. If ownership of the resource isn&#8217;t properly validated, an attacker may be able to trick your application into accessing resources in tenants to which they don&#8217;t have access.<\/p>\n<h2>Recommended actions<\/h2>\n<p>All multi-tenant applications accessing user-provided resources should consider the following measures to secure customer provided resource access:<\/p>\n<ul>\n<li>When immediate resource access is precipitated by a specific user request, consider using <a href=\"https:\/\/learn.microsoft.com\/azure\/active-directory\/develop\/v2-oauth2-on-behalf-of-flow\">On Behalf Of (OBO) authentication<\/a>. This authentication flow ensures both the user and application have necessary access to the resource.<\/li>\n<li>If users provide resource URIs for setup or configuration, consider limiting the user&#8217;s input to resources in their current tenant or a single registered tenant.<\/li>\n<li>Applications whose customers require access to resources in multiple tenants should strongly consider creating a unique multi-tenant application per customer to prevent cross customer access.<\/li>\n<li>Applications using authentication challenge data (<code>WWW-Authenticate<\/code> headers) returned from requests to customer provided resources should validate the requested authority matches a tenant owned by the same customer.<\/li>\n<\/ul>\n<h3>Additional recommended actions<\/h3>\n<p>For applications using the Azure SDK, we have provided new versions of the Azure Identity library to ensure multi-tenant applications are secure by default. These updated libraries restrict multi-tenant authentication and provide APIs to configure the tenants from which credentials may acquire tokens. You should update your applications to use any of the packages below or newer:<\/p>\n<ul>\n<li>.NET: <a href=\"https:\/\/www.nuget.org\/packages\/Azure.Identity\/1.7.0\">https:\/\/www.nuget.org\/packages\/Azure.Identity\/1.7.0<\/a><\/li>\n<li>Java: <a href=\"https:\/\/search.maven.org\/artifact\/com.azure\/azure-identity\/1.6.0\/jar\">https:\/\/search.maven.org\/artifact\/com.azure\/azure-identity\/1.6.0\/jar<\/a><\/li>\n<li>JavaScript: <a href=\"https:\/\/www.npmjs.com\/package\/@azure\/identity\/v\/3.0.0\">https:\/\/www.npmjs.com\/package\/@azure\/identity\/v\/3.0.0<\/a><\/li>\n<li>Python: <a href=\"https:\/\/pypi.org\/project\/azure-identity\/1.11.0\">https:\/\/pypi.org\/project\/azure-identity\/1.11.0<\/a><\/li>\n<\/ul>\n<p>These SDK updates alone don&#8217;t mitigate the issue, but they do prevent multi-tenant applications from acquiring tokens for arbitrary tenants by default. With these updates applied, applications must configure the tenants from which credentials may acquire tokens. If an SDK client or the application attempts to acquire a token for a tenant not explicitly allowed in the credential configuration, the credential will throw a runtime error.<\/p>\n<p>This new behavior is a runtime breaking change from the previous support for multi-tenant authentication, which provided no such safeguards. The SDK team carefully considered the impact of this breaking change, and determined it was warranted to ensure multi-tenant applications using the Azure Identity library are secure by default. Multi-tenant applications upgrading from earlier versions of the Azure Identity library can consult the following instructions to fix any impacted credentials:<\/p>\n<h4>.NET<\/h4>\n<p>As of <code>Azure.Identity<\/code> 1.7.0, the default behavior of credentials supporting multi-tenant authentication has changed. Each of these credentials will throw an <code>AuthenticationFailedException<\/code> if the requested <code>TenantId<\/code> doesn&#8217;t match the tenant ID originally configured on the credential. Apps must now do one of the following things:<\/p>\n<ul>\n<li>Add all IDs, of tenants from which tokens should be acquired, to the <code>AdditionallyAllowedTenants<\/code> list in the credential options. For example:\n<pre><code class=\"language-C#\">var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions\r\n{\r\n    AdditionallyAllowedTenants = { \"&lt;tenant_id_1&gt;\", \"&lt;tenant_id_2&gt;\" }\r\n});<\/code><\/pre>\n<\/li>\n<li>Add <code>*<\/code> to enable token acquisition from any tenant. This configuration provides behavior compatible with previous multi-tenant support. For example:\n<pre><code class=\"language-C#\">var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions\r\n{\r\n    AdditionallyAllowedTenants = { \"*\" }\r\n});<\/code><\/pre>\n<\/li>\n<\/ul>\n<h4>Java<\/h4>\n<p>As of <code>azure-identity<\/code> 1.6.0, the default behavior of credentials supporting multi-tenant authentication has changed. Each of these credentials will throw an <code>ClientAuthenticationException<\/code> if the requested <code>tenantId<\/code> doesn&#8217;t match the tenant ID originally configured on the credential. Apps must now do one of the following things:<\/p>\n<ul>\n<li>Add all IDs, of tenants from which tokens should be acquired, to the <code>additionallyAllowedTenants<\/code> list on the credential builder. For example:\n<pre><code class=\"language-java\">DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder()\r\n    .additionallyAllowedTenants(\"&lt;tenant_id_1&gt;\", \"tenant_id_2&gt;\")\r\n    .build();<\/code><\/pre>\n<\/li>\n<li>Add <code>*<\/code> to enable token acquisition from any tenant. This is the original behavior and is compatible with versions 1.4.0 through 1.5.5. For example:\n<pre><code class=\"language-java\">DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder()\r\n            .additionallyAllowedTenants(\"*\")\r\n            .build();<\/code><\/pre>\n<\/li>\n<\/ul>\n<h4>JavaScript<\/h4>\n<p>As of <code>@azure\/identity<\/code> 3.0.0, the default behavior of credentials supporting multi-tenant authentication has changed. Each of these credentials will throw an error if the requested <code>tenantId<\/code> doesn&#8217;t match the tenant ID originally configured on the credential. Apps must now do one of the following things:<\/p>\n<ul>\n<li>Add all IDs, of tenants from which tokens should be acquired, to the <code>additionallyAllowedTenants<\/code> array in the credential options. For example:\n<pre><code class=\"language-typescript\">const credential = new DefaultAzureCredential({\r\nadditionallyAllowedTenants: [\"&lt;tenant_id_1&gt;\", \"&lt;tenant_id_2&gt;\"]\r\n});<\/code><\/pre>\n<\/li>\n<li>Add <code>*<\/code> to enable token acquisition from any tenant, which is the original behavior. For example:\n<pre><code class=\"language-typescript\">const credential = new DefaultAzureCredential({\r\nadditionallyAllowedTenants: [\"*\"]\r\n});<\/code><\/pre>\n<\/li>\n<\/ul>\n<h4>Python<\/h4>\n<h3>Behavioral change to credential types supporting multi-tenant authentication<\/h3>\n<p>As of <code>azure-identity<\/code> 1.11.0, the default behavior of credentials supporting multi-tenant authentication has changed. Each of these credentials will throw an <code>ClientAuthenticationError<\/code> if the requested <code>tenant_id<\/code> doesn&#8217;t match the tenant ID originally configured on the credential. Apps must now do one of the following things:<\/p>\n<ul>\n<li>Add all IDs, of tenants from which tokens should be acquired, to the <code>additionally_allowed_tenants<\/code> list in the credential options. For example:<\/li>\n<\/ul>\n<pre><code class=\"language-py\">credential = DefaultAzureCredential(additionally_allowed_tenants = [\"&lt;tenant_id_1&gt;\", \"&lt;tenant_id_2&gt;\"])<\/code><\/pre>\n<ul>\n<li>Add <code>*<\/code> to enable token acquisition from any tenant. This is the original behavior and is compatible with previous versions supporting multi tenant authentication. For example:<\/li>\n<\/ul>\n<pre><code class=\"language-py\">credential = DefaultAzureCredential(additionally_allowed_tenants=['*'])<\/code><\/pre>\n<h2>Summary<\/h2>\n<p>Make sure your application validates that all user-provided URIs to Azure resources are owned by the customer supplying them to avoid unauthorized cross tenant access. Update your Azure Identity package references to the latest package versions to ensure your application is secure by default against unauthorized cross tenant access. Update credentials used in your application which require multi-tenant access to specify any additional tenants the credential may access. For more information on impacted credential types, see the release notes for the language specific Azure Identity library referenced by your application.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Guidelines for multi-tenant applications to validate tenant ownership of user-provided URIs for Azure resources.<\/p>\n","protected":false},"author":101500,"featured_media":2214,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[831,158,705],"class_list":["post-2204","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-guidelines","tag-identity","tag-sdk"],"acf":[],"blog_post_summary":"<p>Guidelines for multi-tenant applications to validate tenant ownership of user-provided URIs for Azure resources.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2204","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/101500"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=2204"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2204\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/2214"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=2204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=2204"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=2204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}