{"id":27231,"date":"2022-11-28T15:40:01","date_gmt":"2022-11-28T14:40:01","guid":{"rendered":"https:\/\/device-insight.com\/?post_type=developers-blog&#038;p=27231"},"modified":"2024-03-04T09:15:16","modified_gmt":"2024-03-04T08:15:16","slug":"use-azure-ad-workload-identity-for-pod-assigned-managed-identity-in-aks","status":"publish","type":"developers-blog","link":"https:\/\/device-insight.com\/en\/developers-blog\/use-azure-ad-workload-identity-for-pod-assigned-managed-identity-in-aks\/","title":{"rendered":"Use Azure AD Workload Identity for Pod-Assigned Managed Identity in AKS"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"27231\" class=\"elementor elementor-27231\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\" data-elementor-post-type=\"developers-blog\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-101820ed devel_blog_title elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"101820ed\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-29d693ae blog_col\" data-id=\"29d693ae\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-12558619 elementor-align-left devel_blog_back_btn ha-has-bg-overlay elementor-widget elementor-widget-button\" data-id=\"12558619\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-button-wrapper\">\n\t\t\t\t\t<a class=\"elementor-button elementor-size-sm\" role=\"button\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t<span class=\"elementor-button-icon\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"hm hm-arrow-left1\"><\/i>\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Back<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3a39fbd4 elementor-widget elementor-widget-theme-post-title elementor-page-title elementor-widget-heading\" data-id=\"3a39fbd4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"theme-post-title.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Use Azure AD Workload Identity for Pod-Assigned Managed Identity in AKS<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-67af190d elementor-widget elementor-widget-post-info\" data-id=\"67af190d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"post-info.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul class=\"elementor-inline-items elementor-icon-list-items elementor-post-info\">\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-6345c40 elementor-inline-item\" itemprop=\"author\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-author\">\n\t\t\t\t\t\t\t\t\t\tRobert Lohr\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-a6f20de elementor-inline-item\">\n\t\t\t\t\t\t<a href=\"https:\/\/de.linkedin.com\/in\/robert-lohr-27928117b\" target=\"_blank\" rel=\"noopener\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fab fa-linkedin\"><\/i>\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-custom\">\n\t\t\t\t\t\t\t\t\t\thttps:\/\/www.linkedin.com\/in\/robert-lohr-27928117b\/\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t<\/li>\n\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-b86a0c7 elementor-inline-item\" itemprop=\"datePublished\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date\">\n\t\t\t\t\t\t\t\t\t\t<time>2022\/11\/28<\/time>\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-808e92e elementor-inline-item\" itemprop=\"about\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-terms\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-post-info__terms-list\">\n\t\t\t\t<a href=\"https:\/\/device-insight.com\/en\/developers_blog_category\/azure\/\" class=\"elementor-post-info__terms-list-item\">Azure<\/a>\t\t\t\t<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-60166579 elementor-widget elementor-widget-text-editor\" data-id=\"60166579\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"1\">Is there anything worse than managing a cloud service\u2019s credentials and connection strings to infrastructure services? Well, maybe strawberries, but that is beside the point.<\/p><p data-renderer-start-pos=\"177\">Every secret you must manage has the potential for errors and is a security liability. Oh, and as we programmers love, it is also additional tedious work. Can you do something about that when you deploy your services to an Azure Kubernetes cluster? Yes, and it is called <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/workload-identity-overview\" href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/workload-identity-overview\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">Azure Active Directory Workload Identity<\/a> &#8211; catchy. It is the successor to <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/use-azure-ad-pod-identity\" href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/use-azure-ad-pod-identity\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">Pod Managed Identity<\/a>, which suffered a Google fate and did not make it past its preview status.<\/p><p data-renderer-start-pos=\"619\"><strong data-renderer-mark=\"true\"><span id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\" data-renderer-mark=\"true\" data-mark-type=\"annotation\" data-mark-annotation-type=\"inlineComment\" data-id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\">Note:<\/span><\/strong><span id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\" data-renderer-mark=\"true\" data-mark-type=\"annotation\" data-mark-annotation-type=\"inlineComment\" data-id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\"> At the time of writing, Azure AD Workload Identity is also still in preview. <\/span><a class=\"css-tgpl01\" title=\"https:\/\/github.com\/Azure\/AKS\/issues\/1480#issuecomment-1209778772\" href=\"https:\/\/github.com\/Azure\/AKS\/issues\/1480#issuecomment-1209778772\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\"><span id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\" data-renderer-mark=\"true\" data-mark-type=\"annotation\" data-mark-annotation-type=\"inlineComment\" data-id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\">From what I could find<\/span><\/a><span id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\" data-renderer-mark=\"true\" data-mark-type=\"annotation\" data-mark-annotation-type=\"inlineComment\" data-id=\"5b6fae96-cd79-45fd-84c9-d5967bd57e37\">, it is slated to reach the Generally Available status (GA) at the end of 2022.<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-193e547 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"193e547\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4e095fee blog_col\" data-id=\"4e095fee\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-67a2341 elementor-widget elementor-widget-heading\" data-id=\"67a2341\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">What is a Managed Identity?<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-57c605bb elementor-widget elementor-widget-text-editor\" data-id=\"57c605bb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"834\">Visit <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/managed-identities-azure-resources\/overview\" href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity\/managed-identities-azure-resources\/overview\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">Microsoft\u2019s documentation<\/a> for all the gritty details. The short version is that it saves a lot of the headaches that come with an AD application registration and Service Principal.<\/p><ul class=\"ak-ul\" data-indent-level=\"1\"><li><p data-renderer-start-pos=\"1024\">There is no password to configure for the service that uses the identity.<\/p><\/li><li><p data-renderer-start-pos=\"1101\">There is no password to rotate after X amount of time.<\/p><\/li><li><p data-renderer-start-pos=\"1159\">There is no need to do anything in Azure AD, bypassing the one thing that IT Ops departments usually guard with their life. Besides the network. And the coffee maker.<\/p><\/li><\/ul><p data-renderer-start-pos=\"1329\">A Managed Identity lives in your Resource Group along with other infrastructure resources and does not require a password. Azure manages that part for you. Yet still, you can assign RBAC permissions to it as you would to a Service Principal.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-7637fa6c elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"7637fa6c\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4a3b225c blog_col\" data-id=\"4a3b225c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-859699c elementor-widget elementor-widget-heading\" data-id=\"859699c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">How do I assign that to my pod?<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3c3519d2 elementor-widget elementor-widget-text-editor\" data-id=\"3c3519d2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"1605\">Enter <span data-renderer-mark=\"true\"><del datetime=\"2022-11-25T14:09:43+00:00\">Sandman<\/del><\/span> Azure AD Workload Identity.<\/p><p data-renderer-start-pos=\"1648\"><a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/use-managed-identity\" href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/use-managed-identity\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">AKS can have a System- or User-Assigned Managed Identity<\/a>. But all that does is allow AKS to access resources it requires for its operation, like a load balancer. It is not a thing you can take advantage of in your microservice that you have imprisoned inside a pod. Nor would you want to. Your microservice is not AKS, and it should not impersonate one.<\/p><p data-renderer-start-pos=\"2003\">Additionally, you would want every one of your microservices to have its own identity so you have fine-grained control over what other services your application can access. In the olden days, when usernames and passwords were more pervasive, it was essential to revoke only a specific set of credentials if they were ever compromised, thus limiting the impact on the system. Managed Identities cannot leak credentials, but your microservice could still get hacked, and this also limits the impact to a single Managed Identity and the resources it can access.<\/p><p data-renderer-start-pos=\"2563\">But the question was how to enable this for a pod, so let me finally answer that.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-31ec46e8 elementor-widget elementor-widget-heading\" data-id=\"31ec46e8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h4 class=\"elementor-heading-title elementor-size-default\">The AKS puzzle<\/h4>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4a1b69ca elementor-widget elementor-widget-text-editor\" data-id=\"4a1b69ca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>First, you must install the az command line utility and the aks-preview extension. If you have already done so, perform an update to be safe.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-401c9fce elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"401c9fce\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\taz extension add\/update --name aks-preview\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-57b3625e elementor-widget elementor-widget-text-editor\" data-id=\"57b3625e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"2849\">The minimum requirements are az version 2.40+, aks-preview 0.5.102+, and Kubernetes 1.22+.<\/p><p data-renderer-start-pos=\"2941\">Now you can create a new <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/cluster-configuration#oidc-issuer\" href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/cluster-configuration#oidc-issuer\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">AKS cluster or update an existing one with the OIDC issuer feature<\/a>. I will show a diagram of how all the pieces fit together once they are on the table. Let\u2019s assume an upgrade of an existing testing cluster named <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">mi-test-aks<\/code>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-21a92448 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"21a92448\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\taz aks update -g mi-test-group --name mi-test-aks --enable-oidc-issuer\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-21e7be2 elementor-widget elementor-widget-text-editor\" data-id=\"21e7be2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"3266\">With this feature enabled, you can retrieve the issuer URL with this command.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-64916901 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"64916901\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\taz aks show --resource-group mi-test-group --name mi-test-aks --query &quot;oidcIssuerProfile.issuerUrl&quot; -otsv\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-421cc53a elementor-widget elementor-widget-text-editor\" data-id=\"421cc53a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"3452\">It spits out something like this.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3fab5e1b elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"3fab5e1b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\thttps:\/\/oidc.prod-aks.azure.com\/0eb05a4c-2d75-4568-ad04-0bb03f6a99b1\/\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6750b68c elementor-widget elementor-widget-text-editor\" data-id=\"6750b68c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"3452\">The <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">\/<\/code> at the end is <strong data-renderer-mark=\"true\">very important<\/strong>. If you forget it in later steps, you do not pass Go, do not collect 200 money, and go directly to jail, where you must solve the riddle of unhelpful error messages like this for eternity.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7163653b elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"7163653b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\tAzure Identity =&gt; ERROR in getToken() call for scopes [https:\/\/vault.azure.net\/.default]: Server returned HTTP response code: 400 for URL\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-48d3dafa elementor-widget elementor-widget-text-editor\" data-id=\"48d3dafa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"3922\">The official documentation has a <a class=\"css-tgpl01\" title=\"https:\/\/azure.github.io\/azure-workload-identity\/docs\/troubleshooting.html#aadsts70021-no-matching-federated-identity-record-found-for-presented-assertion\" href=\"https:\/\/azure.github.io\/azure-workload-identity\/docs\/troubleshooting.html#aadsts70021-no-matching-federated-identity-record-found-for-presented-assertion\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">dedicated troubleshooting section<\/a> for the <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">\/<\/code> error that mentions yet another failure reason.<\/p><p data-renderer-start-pos=\"4048\">The next step is to <a class=\"css-tgpl01\" title=\"https:\/\/azure.github.io\/azure-workload-identity\/docs\/installation\/mutating-admission-webhook.html\" href=\"https:\/\/azure.github.io\/azure-workload-identity\/docs\/installation\/mutating-admission-webhook.html\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">install a mutating admission webhook<\/a> that injects the identity information as environment variables into your pods. I have found two ways of enabling this functionality, but unfortunately, I failed to verify them in isolation. I had both enabled simultaneously, and once I had the AKS feature flag set, it could not be reverted. So, let me start with this option.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2173a5c8 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"2173a5c8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\taz aks update -g mi-test-group --name mi-test-aks --enable-workload-identity\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3c4001b8 elementor-widget elementor-widget-text-editor\" data-id=\"3c4001b8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"4511\">Another way that is independent of AKS is an installation via Helm.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-780f175f elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"780f175f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\thelm repo add azure-workload-identity https:\/\/azure.github.io\/azure-workload-identity\/charts\nhelm repo update\nhelm install workload-identity-webhook azure-workload-identity\/workload-identity-webhook \\\n   --namespace azure-workload-identity-system \\\n   --create-namespace \\\n   --set azureTenantID=a1cd6959-ac13-4052-987d-067f854223c3\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2a654924 elementor-widget elementor-widget-text-editor\" data-id=\"2a654924\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"4914\">The result is two additional controllers in the azure-workload-identity-system namespace.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-74b69c26 elementor-widget elementor-widget-image\" data-id=\"74b69c26\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"580\" height=\"41\" src=\"https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-Workload-Identity-Webhook-Controller-Pods-1024x73.jpg\" class=\"attachment-large size-large wp-image-27350\" alt=\"\" srcset=\"https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-Workload-Identity-Webhook-Controller-Pods-1024x73.jpg 1024w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-Workload-Identity-Webhook-Controller-Pods-300x21.jpg 300w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-Workload-Identity-Webhook-Controller-Pods-768x55.jpg 768w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-Workload-Identity-Webhook-Controller-Pods-1200x85.jpg 1200w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-Workload-Identity-Webhook-Controller-Pods.jpg 1240w\" sizes=\"(max-width: 580px) 100vw, 580px\" \/>\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Azure Workload Identity Webhook Controller Kubernetes Pods<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3fcfb807 elementor-widget elementor-widget-text-editor\" data-id=\"3fcfb807\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"5008\"><em data-renderer-mark=\"true\">Speculation:<\/em> I think both approaches are interchangeable on AKS.<\/p><p data-renderer-start-pos=\"5074\">The documentation always talks about installing the admission webhook so I would opt for the Helm method.<\/p><p data-renderer-start-pos=\"5181\">You also require a Managed Identity, of course. For the rest of this tutorial, I use the client-id <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">0ea4d539-3998-43a6-b30d-317889dc34cd<\/code> as an example. You can get it from the Azure Portal if you like the visual approach or with some command line fu.<\/p><div class=\"fabric-editor-block-mark css-1mg5rgz\" data-align=\"center\"><p data-renderer-start-pos=\"5432\">(To tease my Linux-using colleagues, I went with PowerShell syntax \ud83d\ude01)<\/p><\/div>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-70ef8d53 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"70ef8d53\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"powershell\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-powershell\">\n\t\t\t\t\tPS &gt; $APPLICATION_NAME=&quot;managed-identity-test&quot;\nPS &gt; $APPLICATION_CLIENT_ID=&quot;$(az ad sp list --display-name &quot;${APPLICATION_NAME}&quot; --query &#039;[0].appId&#039; -otsv)&quot;&quot;\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6839940 elementor-widget elementor-widget-text-editor\" data-id=\"6839940\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"5663\">The AKS puzzle is now complete, and you can move on to deploying a microservice.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6c088808 elementor-widget elementor-widget-heading\" data-id=\"6c088808\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h4 class=\"elementor-heading-title elementor-size-default\">YAML is yummie<\/h4>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2ad6dda elementor-widget elementor-widget-text-editor\" data-id=\"2ad6dda\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"5663\">No, not really. Fortunately, you do not require much of it to achieve your goal. Azure AD Workload Identity attempts to utilize standard Kubernetes concepts, and one is the Service Account resource. You create one of those, link it to your deployment, link it to the Managed Identity, and you\u2019re good to go.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-25d0457c elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"25d0457c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"yaml\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-yaml\">\n\t\t\t\t\tapiVersion: v1\nkind: ServiceAccount\nmetadata:\n  annotations:\n    azure.workload.identity\/client-id: 0ea4d539-3998-43a6-b30d-317889dc34cd\n  labels:\n    azure.workload.identity\/use: &quot;true&quot;\n  name: managed-identity-test\n  namespace: platform\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7f956a1d elementor-widget elementor-widget-text-editor\" data-id=\"7f956a1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"6310\">The two essential parts are the annotation and the label. The first is the link to the Managed Identity, and the second basically enables the feature. I assume that the admission webhook looks for it.<\/p>\n<p data-renderer-start-pos=\"6512\">In the Deployment resource, you must set two things:<\/p>\n\n<ol>\n \t<li data-renderer-start-pos=\"6512\">The <code>serviceAccountName<\/code>.<\/li>\n \t<li data-renderer-start-pos=\"6512\">The label <code>azure.workload.identity\/use: \"true\"<\/code>.<\/li>\n<\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4125c362 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"4125c362\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"yaml\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-yaml\">\n\t\t\t\t\tapiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: managed-identity-test\nspec:\n  template:\n    metadata:\n      labels:\n        azure.workload.identity\/use: &quot;true&quot;\n    spec:\n      serviceAccountName: managed-identity-test\n      ...\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-63f00c5e elementor-widget elementor-widget-text-editor\" data-id=\"63f00c5e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"6695\"><a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/workload-identity-overview#service-account-labels-and-annotations\" href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/workload-identity-overview#service-account-labels-and-annotations\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">More annotations are available on the Service Account and Deployment<\/a> but are only necessary for specific situations.<\/p><p data-renderer-start-pos=\"6813\">What this all does is project several environment variables into the Pod containing authentication information, and I explain later how to utilize them in a Spring Boot microservice.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-61527c36 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"61527c36\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\tAZURE_CLIENT_ID:             0ea4d539-3998-43a6-b30d-317889dc34cd\nAZURE_TENANT_ID:             a1cd6959-ac13-4052-987d-067f854223c3\nAZURE_FEDERATED_TOKEN_FILE:  \/var\/run\/secrets\/azure\/tokens\/azure-identity-token\nAZURE_AUTHORITY_HOST:        https:\/\/login.microsoftonline.com\/\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c34a653 elementor-widget elementor-widget-text-editor\" data-id=\"c34a653\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"6695\">Lastly, you create a federated credential that binds the Service Account to the Managed Identity. It contains links to many resources you have created so far. The name of the Managed Identity and the Resource Group it resides in, the OIDC URL of AKS, and the Service Account\u2019s name and namespace.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-300f2460 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"300f2460\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"bash\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-bash\">\n\t\t\t\t\taz identity federated-credential create \\\n  --name managed-identity-test-fed-cred \\\n  --identity-name managed-identity-test \\\n  --resource-group mi-test-group \\\n  --issuer https:\/\/oidc.prod-aks.azure.com\/0eb05a4c-2d75-4568-ad04-0bb03f6a99b1\/ \\\n  --subject system:serviceaccount:platform:managed-identity-test\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6e508dc0 elementor-widget elementor-widget-text-editor\" data-id=\"6e508dc0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"7882\">Remember the all-important trailing <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">\/<\/code> in the OIDC URL.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-199ae741 elementor-widget elementor-widget-image\" data-id=\"199ae741\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"580\" height=\"133\" src=\"https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Managed-Identity-Federated-Credential-768x176.png\" class=\"attachment-medium_large size-medium_large wp-image-27352\" alt=\"\" srcset=\"https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Managed-Identity-Federated-Credential-768x176.png 768w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Managed-Identity-Federated-Credential-300x69.png 300w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Managed-Identity-Federated-Credential-1024x235.png 1024w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Managed-Identity-Federated-Credential-1536x353.png 1536w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Managed-Identity-Federated-Credential-1200x275.png 1200w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Managed-Identity-Federated-Credential.png 1616w\" sizes=\"(max-width: 580px) 100vw, 580px\" \/>\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Azure Portal Managed Identity Federated Credential<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1ac574d elementor-widget elementor-widget-heading\" data-id=\"1ac574d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h4 class=\"elementor-heading-title elementor-size-default\">Big picture mode<\/h4>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2c730e1d elementor-widget elementor-widget-text-editor\" data-id=\"2c730e1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"7959\">I promised an image once the puzzle was complete, so here it is. Microsoft has much good documentation spread across numerous web pages, but it can still be tricky to understand what is happening where precisely.<\/p><p data-renderer-start-pos=\"8173\">The following diagram is what I pieced together from Microsoft\u2019s more generally verbalized documentation <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/workload-identity-overview#how-it-works\" href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/aks\/workload-identity-overview#how-it-works\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">here<\/a> and <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/develop\/workload-identity-federation#how-it-works\" href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/workload-id\/workload-identity-federation#how-it-works\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">here<\/a> and <a class=\"css-tgpl01\" title=\"https:\/\/azure.github.io\/azure-workload-identity\/docs\/concepts.html\" href=\"https:\/\/azure.github.io\/azure-workload-identity\/docs\/concepts.html\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">here<\/a>. The concept of federated credentials that are the basis of AAD Workload Identity supposedly works for more use cases than AKS pods. Examples that Microsoft uses include GitHub Actions or even <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/develop\/workload-identity-federation-create-trust-gcp?tabs=azure-cli%2Ctypescript\" href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/workload-id\/workload-identity-federation?tabs=azure-cli%2Ctypescript\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">Google Cloud<\/a>.<\/p><p data-renderer-start-pos=\"8509\">I narrowed the scope to just the Azure Kubernetes use case I am discussing here, and, therefore, I omitted a few elements for simplicity.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-359c864d elementor-widget elementor-widget-image\" data-id=\"359c864d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<figure class=\"wp-caption\">\n\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"580\" height=\"458\" src=\"https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-AD-Workflow-Identiy-AKS-Architecture-768x607.jpg\" class=\"attachment-medium_large size-medium_large wp-image-27354\" alt=\"\" srcset=\"https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-AD-Workflow-Identiy-AKS-Architecture-768x607.jpg 768w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-AD-Workflow-Identiy-AKS-Architecture-300x237.jpg 300w, https:\/\/device-insight.com\/wp-content\/uploads\/2022\/12\/Azure-AD-Workflow-Identiy-AKS-Architecture.jpg 949w\" sizes=\"(max-width: 580px) 100vw, 580px\" \/>\t\t\t\t\t\t\t\t\t\t\t<figcaption class=\"widget-image-caption wp-caption-text\">Azure AD Workflow Identity AKS Architecture<\/figcaption>\n\t\t\t\t\t\t\t\t\t\t<\/figure>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-585c723f elementor-widget elementor-widget-text-editor\" data-id=\"585c723f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"8651\">The previous sections should already explain enough about what happens inside the Kubernetes cluster. The remaining question revolves around how authentication against AAD works. The microservice trapped in the Pod reads the federated token from the file mounted into the Pod. The application uses the federated token to authenticate against Azure AD and exchange it for an Azure AD token. At this point, the microservice can authenticate itself as the Managed Identity and access the Azure infrastructure to which the Managed Identity was granted access.<\/p><p data-renderer-start-pos=\"9208\">How exactly AAD draws the connection from the federated token to the Managed Identity is not exactly clear to me, but it is also not important. It would be obvious if it were a Service Principal, as they are part of AAD.<\/p><p data-renderer-start-pos=\"9430\">The federated token contains the following information, among which is the <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">sub<\/code> also present in the federated credential that connects the Kubernetes Service Account and Managed Identity.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-75f34f2a elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"75f34f2a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"json\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-json\">\n\t\t\t\t\t{\n    &quot;aud&quot;: [\n        &quot;api:\/\/AzureADTokenExchange&quot;\n    ],\n    &quot;exp&quot;: 1668430708,\n    &quot;iat&quot;: 1668427108,\n    &quot;iss&quot;: &quot;https:\/\/oidc.prod-aks.azure.com\/0eb05a4c-2d75-4568-ad04-0bb03f6a99b1\/&quot;,\n    &quot;kubernetes.io&quot;: {\n        &quot;namespace&quot;: &quot;platform&quot;,\n        &quot;pod&quot;: {\n            &quot;name&quot;: &quot;managed-identity-test-5fd59c9658-cp6td&quot;,\n            &quot;uid&quot;: &quot;c0fd7bc6-6609-4016-b093-2a428e250c38&quot;\n        },\n        &quot;serviceaccount&quot;: {\n            &quot;name&quot;: &quot;managed-identity-test&quot;,\n            &quot;uid&quot;: &quot;598427ef-cb54-4f89-9604-a7f4d2645477&quot;\n        }\n    },\n    &quot;nbf&quot;: 1668427108,\n    &quot;sub&quot;: &quot;system:serviceaccount:platform:managed-identity-test&quot;\n}\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-24855baa elementor-widget elementor-widget-text-editor\" data-id=\"24855baa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"8651\">For the curious, here is how the federated token differs from the default Service Account token automatically injected into every Pod.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-33367440 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"33367440\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"json\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-json\">\n\t\t\t\t\t{\n    &quot;aud&quot;: [\n        &quot;https:\/\/oidc.prod-aks.azure.com\/0eb05a4c-2d75-4568-ad04-0bb03f6a99b1\/&quot;,\n        &quot;https:\/\/mi-test-aks-k8s-halo343.hcp.westeurope.azmk8s.io&quot;,\n        &quot;\\&quot;mi-test-aks-k8s-halo343.hcp.westeurope.azmk8s.io\\&quot;&quot;\n    ],\n    &quot;exp&quot;: 1699963108,\n    &quot;iat&quot;: 1668427108,\n    &quot;iss&quot;: &quot;https:\/\/oidc.prod-...\n}\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-40bfea1e elementor-widget elementor-widget-text-editor\" data-id=\"40bfea1e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"10704\">The value of <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">aud<\/code> is not the same, and everything else is (excluding the timestamps).<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5c28d575 elementor-widget elementor-widget-heading\" data-id=\"5c28d575\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h4 class=\"elementor-heading-title elementor-size-default\">What must I do in code?<\/h4>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4db4fb8d elementor-widget elementor-widget-text-editor\" data-id=\"4db4fb8d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"10815\">I certainly spend an awful lot of time explaining infrastructure as someone who prefers to code\u2026<\/p><p data-renderer-start-pos=\"10913\">Speaking of which\u2026<\/p><div class=\"fabric-editor-block-mark css-1mg5rgz\" data-align=\"center\"><p style=\"text-align: center;\" data-renderer-start-pos=\"10933\">(Haha, segue!)<\/p><\/div><p data-renderer-start-pos=\"10949\">How would you take advantage of all the earlier configurations and setup? Let me explain the hard way to provide a complete picture, and then I will show you the more straightforward and practical solution. Either way, you need the <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">azure-identity<\/code> dependency. I based my demo application on Spring Boot and gave my Managed Identity read access to Key Vault secrets. Hence the <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">azure-security-keyvault-secrets<\/code> dependency.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7bc63a69 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"7bc63a69\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"markup\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-markup\">\n\t\t\t\t\t&lt;dependencyManagement&gt;\n   &lt;dependencies&gt;\n      &lt;dependency&gt;\n         &lt;groupId&gt;com.azure&lt;\/groupId&gt;\n         &lt;artifactId&gt;azure-sdk-bom&lt;\/artifactId&gt;\n         &lt;version&gt;1.2.7&lt;\/version&gt;\n         &lt;type&gt;pom&lt;\/type&gt;\n         &lt;scope&gt;import&lt;\/scope&gt;\n      &lt;\/dependency&gt;\n   &lt;\/dependencies&gt;\n&lt;\/dependencyManagement&gt;\n\n&lt;dependencies&gt;\n   &lt;dependency&gt;\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n      &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt;\n   &lt;\/dependency&gt;\n\n   &lt;dependency&gt;\n      &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt;\n      &lt;artifactId&gt;lombok&lt;\/artifactId&gt;\n      &lt;optional&gt;true&lt;\/optional&gt;\n   &lt;\/dependency&gt;\n\n   &lt;dependency&gt;\n      &lt;groupId&gt;com.azure&lt;\/groupId&gt;\n      &lt;artifactId&gt;azure-identity&lt;\/artifactId&gt;\n      &lt;scope&gt;compile&lt;\/scope&gt;\n   &lt;\/dependency&gt;\n\n   &lt;dependency&gt;\n      &lt;groupId&gt;com.azure&lt;\/groupId&gt;\n      &lt;artifactId&gt;azure-security-keyvault-secrets&lt;\/artifactId&gt;\n   &lt;\/dependency&gt;\n&lt;\/dependencies&gt;\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-20e3fac2 elementor-widget elementor-widget-text-editor\" data-id=\"20e3fac2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"12263\">To access Key Vault secrets, you need a <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">SecretClient<\/code>. You can get this from a <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">SecretClientBuilder<\/code>, which itself requires some form of authentication. The Azure SDK abstracts this as a <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/java\/api\/com.azure.core.credential.tokencredential?view=azure-java-stable\" href=\"https:\/\/learn.microsoft.com\/en-us\/java\/api\/com.azure.core.credential.tokencredential?view=azure-java-stable\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">TokenCredential<\/a>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-75d871b4 elementor-widget elementor-widget-heading\" data-id=\"75d871b4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h4 class=\"elementor-heading-title elementor-size-default\">The long road home<\/h4>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6a3bcdad elementor-widget elementor-widget-text-editor\" data-id=\"6a3bcdad\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"12485\">Here is the bean definition.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b1c061a elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"b1c061a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"java\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-java\">\n\t\t\t\t\tprivate final IdentityConfig identityConfig;\n\n@Bean\npublic SecretClient secretClient() {\n   \/\/ Make the vault configurable, of course.\n   return new SecretClientBuilder()\n         .vaultUrl(&quot;https:\/\/&lt;vault-on-pandora&gt;.vault.azure.net&quot;)\n         .credential(identityConfig.workloadIdentityCredential())\n         .buildClient();\n}\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7e1ae799 elementor-widget elementor-widget-text-editor\" data-id=\"7e1ae799\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"12845\">As you now know, you require the federated token to authenticate your microservice against Azure AD. The hard way is to code this yourself and implement the <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">TokenCredential<\/code> interface.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5acf1195 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"5acf1195\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"java\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-java\">\n\t\t\t\t\t@RequiredArgsConstructor\npublic class WorkloadIdentityCredential implements TokenCredential {\n\n   private final String clientID;\n   private final String tenantID;\n   private final String aadAuthority;\n   private final String federatedToken;\n\n   @Override\n   public Mono&lt;AccessToken&gt; getToken(TokenRequestContext requestContext) {\n      try {\n         var clientCredential = ClientCredentialFactory.createFromClientAssertion(\n               federatedToken);\n         var authority = String.format(&quot;%s%s&quot;, aadAuthority, tenantID);\n\n         var app = ConfidentialClientApplication.builder(clientID, clientCredential)\n               .authority(authority)\n               .build();\n\n         var scopes = new HashSet&lt;&gt;(requestContext.getScopes());\n         var clientCredentialParam = ClientCredentialParameters.builder(scopes)\n                 .build();\n\n         var authResult = app.acquireToken(clientCredentialParam).get();\n         var expiresOnInstant = authResult.expiresOnDate().toInstant();\n         var expiresOn = OffsetDateTime.ofInstant(expiresOnInstant, ZoneOffset.UTC);\n\n         var accessToken = new AccessToken(authResult.accessToken(), expiresOn);\n\n         return Mono.just(accessToken);\n      } catch (Exception ex) {\n         return Mono.error(ex);\n      }\n   }\n}\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3244f91b elementor-widget elementor-widget-text-editor\" data-id=\"3244f91b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"12845\">I based this code on an example <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/azure\/active-directory\/develop\/workload-identity-federation-create-trust-gcp?tabs=azure-cli%2Cjava#exchange-the-identity-token-for-an-azure-ad-access-token\" href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/workload-id\/workload-identity-federation?tabs=azure-cli%2Cjava#exchange-the-identity-token-for-an-azure-ad-access-token\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">Microsoft published for use with the Google Cloud<\/a>. The <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">federatedToken<\/code> field contains the actual token, not the path to the file. The magic happens by calling <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">app.acquireToken(clientCredentialParam).get();<\/code>. To complete the picture, here is the bean definition.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6b542db3 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"6b542db3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"java\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-java\">\n\t\t\t\t\t@Slf4j\n@Getter\n@Configuration\npublic class IdentityConfig {\n\n   @Value(&quot;${AZURE_CLIENT_ID}&quot;)\n   private String clientId;\n\n   @Value(&quot;${AZURE_TENANT_ID}&quot;)\n   private String tenantId;\n\n   @Value(&quot;${AZURE_AUTHORITY_HOST}&quot;)\n   private String authorityHost;\n\n   @Value(&quot;${AZURE_FEDERATED_TOKEN_FILE}&quot;)\n   private String tokenFile;\n\n   @Bean\n   public TokenCredential workloadIdentityCredential() {\n      try {\n         var federatedToken = Files.readString(Paths.get(tokenFile));\n         return new WorkloadIdentityCredential(clientId, tenantId, authorityHost, federatedToken);\n      } catch (IOException e) {\n         log.error(&quot;Could not read Azure federated token from file &#039;{}&#039;. Cannot authenticate as Managed Identity &quot; +\n               &quot;&#039;{}&#039;.&quot;, tokenFile, clientId);\n         return null;\n      }\n   }\n}\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8691d9d elementor-widget elementor-widget-text-editor\" data-id=\"8691d9d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"12845\">As you can see, I captured all environment variables injected by the webhook into fields that I use in the <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">WorkloadIdentityCredential<\/code> class.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-59e8583d elementor-widget elementor-widget-heading\" data-id=\"59e8583d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h4 class=\"elementor-heading-title elementor-size-default\">Life in the fast lane<\/h4>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-67fccdaa elementor-widget elementor-widget-text-editor\" data-id=\"67fccdaa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"12845\">The best way to do this in Azure is by utilizing the <a class=\"css-tgpl01\" title=\"https:\/\/learn.microsoft.com\/en-us\/java\/api\/com.azure.identity.defaultazurecredential?view=azure-java-stable\" href=\"https:\/\/learn.microsoft.com\/en-us\/java\/api\/com.azure.identity.defaultazurecredential?view=azure-java-stable\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">DefaultAzureCredential<\/a> class. You can throw away the custom <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">TokenCredential<\/code> implementation like I would strawberries and simply define a bean like this.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2fc6b7f4 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"2fc6b7f4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"java\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-java\">\n\t\t\t\t\t@Bean\npublic TokenCredential defaultAzureCredential() {\n   return new DefaultAzureCredentialBuilder().build();\n}\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3f7e64fb elementor-widget elementor-widget-text-editor\" data-id=\"3f7e64fb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"15899\">That\u2019s it. And it is even more flexible. The bean definition for the Key Vault access becomes the following. You only swap the type of credential you are using but gain so much more in the process.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4f9513e3 elementor-widget elementor-widget-ha-source-code happy-addon ha-source-code happy-addon-pro\" data-id=\"4f9513e3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"ha-source-code.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"ha-source-code prism\" data-lng-type=\"java\" data-after-copy=\"Copied\">\n\t\t\t<pre>\n\t\t\t\t\t\t\t<button class=\"ha-copy-code-button\">Copy to clipboard<\/button>\n\t\t\t\t\t\t\t<code class=\"language-java\">\n\t\t\t\t\t@Bean\npublic SecretClient secretClient() {\n   return new SecretClientBuilder()\n         .vaultUrl(&quot;https:\/\/&lt;vault-on-pandora&gt;.vault.azure.net&quot;)\n         .credential(identityConfig.defaultAzureCredential())\n         .buildClient();\n}\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5f41486e elementor-widget elementor-widget-text-editor\" data-id=\"5f41486e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"16332\">What is it that you get for free? Less code to maintain, for one. More importantly, you cannot authenticate as a Managed Identity from your IDE. Therefore, local debugging is out of the question. The <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">DefaultAzureCredential<\/code> class solves this by checking for several configuration settings in a specific order. It looks at the environment variables, your az CLI login, and more. <a class=\"css-tgpl01\" title=\"https:\/\/plugins.jetbrains.com\/plugin\/8053-azure-toolkit-for-intellij\" href=\"https:\/\/plugins.jetbrains.com\/plugin\/8053-azure-toolkit-for-intellij\" target=\"_blank\" rel=\"noopener\" data-renderer-mark=\"true\">A plugin provides an Azure login context inside the IDE<\/a> for IntelliJ IDEA users. Log in with your Azure account and debug your microservice without problems and without changing the code. You only need to ensure that your account has the same permissions as the Managed Identity would have.<\/p><p data-renderer-start-pos=\"17001\">I haven\u2019t tested all Azure services, of course. Nobody can, as there simply are too many.<\/p><div class=\"fabric-editor-block-mark css-1mg5rgz\" data-align=\"center\"><p style=\"text-align: center;\" data-renderer-start-pos=\"17092\">(Maybe Chuck Norris could \ud83e\udd14.)<\/p><\/div><p data-renderer-start-pos=\"17124\">However, it should work with all services where the SDK supports a <code class=\"code css-z5oxh7\" data-renderer-mark=\"true\">TokenCredential<\/code>, and you can configure the Azure service with RBAC. One exception that I know of is Azure&#8217;s managed PostgreSQL offering. You can use Managed Credentials, but it is very different, and I cover that topic in a separate post. This one is already meaty enough.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-140ec3b6 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"140ec3b6\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-56f40f96 blog_col\" data-id=\"56f40f96\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-20084cb2 elementor-widget elementor-widget-heading\" data-id=\"20084cb2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Famous last words<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-25b14550 elementor-widget elementor-widget-text-editor\" data-id=\"25b14550\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p data-renderer-start-pos=\"17484\">I like this a lot. Looking at a recent project where we manually managed login credentials, connection strings, and more for several different environments, I cannot wait for Azure Active Directory Workload Identity (had to use the full name \ud83d\ude05) to become available for general production use. It can save so much time and effort and even prevent errors from copying the wrong credential. There aren\u2019t any. This happens more often than you would think. The human element strikes at some point.<\/p><p data-renderer-start-pos=\"17979\">I hope this was helpful. Thank you for reading.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-1695442b blog_col elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"1695442b\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-1e2e9e64\" data-id=\"1e2e9e64\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-6a27da93 devel_blog_footer elementor-widget elementor-widget-post-info\" data-id=\"6a27da93\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"post-info.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul class=\"elementor-inline-items elementor-icon-list-items elementor-post-info\">\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-6345c40 elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-custom\">\n\t\t\t\t\t\t\t\t\t\tRobert Lohr\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-7f3e269 elementor-inline-item\">\n\t\t\t\t\t\t<a href=\"https:\/\/de.linkedin.com\/in\/robert-lohr-27928117b\" target=\"_blank\" rel=\"noopener\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fab fa-linkedin\"><\/i>\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-custom\">\n\t\t\t\t\t\t\t\t\t\thttps:\/\/www.linkedin.com\/in\/robert-lohr-27928117b\/\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t<\/li>\n\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-654f7f0 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"654f7f0\" data-element_type=\"section\" data-e-type=\"section\" data-settings=\"{&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-436461c8 blog_col\" data-id=\"436461c8\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-765a5007 elementor-widget elementor-widget-heading\" data-id=\"765a5007\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Recommended posts<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c647cd7 elementor-widget elementor-widget-shortcode\" data-id=\"c647cd7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><div class=\"teasers teasers-single-post\"><div class=\"teasers__container\"><div class=\"teasers__single-teaser teasers__single-teaser--developer\"><div class=\"teasers__content\"><div class=\"date__box\"><div class=\"date__box-name date__box-name--developers\">Stefan Hudelmaier<\/div><div class=\"date__box-date date__box-date--developers\">2023\/01\/25<\/div><div><a href=\"https:\/\/device-insight.com\/en\/developers_blog_category\/azure\/\" class=\"date__box-button date__box-button--developers\">Azure<\/a><\/div><\/div><h2 class=\"headline\"><a href=\"https:\/\/device-insight.com\/en\/developers-blog\/vetting-azure-managed-applications-through-ci-cd\/\">Vetting Azure Managed Applications through CI\/CD<\/a><\/h2><div class=\"description\">How to speed up reviews for Azure Managed Applications with the right validity checks.<\/div><\/div><\/div><div class=\"teasers__single-teaser teasers__single-teaser--developer\"><div class=\"teasers__content\"><div class=\"date__box\"><div class=\"date__box-name date__box-name--developers\">Stefan Hudelmaier<\/div><div class=\"date__box-date date__box-date--developers\">2023\/01\/03<\/div><div><a href=\"https:\/\/device-insight.com\/en\/developers_blog_category\/azure\/\" class=\"date__box-button date__box-button--developers\">Azure<\/a><\/div><\/div><h2 class=\"headline\"><a href=\"https:\/\/device-insight.com\/en\/developers-blog\/azure-managed-applications-and-tags\/\">Managed Applications and tags<\/a><\/h2><div class=\"description\">How to set tags of a managed resource group when deploying Azure Managed Applications.<\/div><\/div><\/div><\/div><\/div>\r\n\n<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>How to make your life easier using Azure AD Workload Identity for authentication within AKS.<\/p>\n","protected":false},"author":15,"featured_media":0,"menu_order":0,"template":"elementor_header_footer","meta":{"_acf_changed":false},"tags":[141],"developers_blog_category":[138],"class_list":["post-27231","developers-blog","type-developers-blog","status-publish","hentry","tag-azure","developers_blog_category-azure"],"acf":[],"_links":{"self":[{"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/developers-blog\/27231","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/developers-blog"}],"about":[{"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/types\/developers-blog"}],"author":[{"embeddable":true,"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/users\/15"}],"version-history":[{"count":37,"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/developers-blog\/27231\/revisions"}],"predecessor-version":[{"id":34905,"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/developers-blog\/27231\/revisions\/34905"}],"wp:attachment":[{"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/media?parent=27231"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/tags?post=27231"},{"taxonomy":"developers_blog_category","embeddable":true,"href":"https:\/\/device-insight.com\/en\/wp-json\/wp\/v2\/developers_blog_category?post=27231"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}