<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cost Management on Digi Hunch</title><link>https://static.digihunch.com/tag/cost-management/</link><description>Recent content in Cost Management on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 02 Apr 2025 12:51:03 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/cost-management/index.xml" rel="self" type="application/rss+xml"/><item><title>AKS Lessons Learned 2 of 2</title><link>https://static.digihunch.com/2021/12/aks-lessons-learned-2-of-2/</link><pubDate>Sat, 18 Dec 2021 01:18:00 -0400</pubDate><guid>https://static.digihunch.com/2021/12/aks-lessons-learned-2-of-2/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-aks-lession-2.webp" alt="Featured image of post AKS Lessons Learned 2 of 2" /&gt;&lt;p class="wp-block-paragraph"&gt;Even though Azure Kubernetes Service (AKS) is a managed service, building a cluster is not trivial. For help resources, I would start with the webinar &amp;#8220;Configure Your AKS cluster with Confidence&amp;#8221; from April 2021, which focuses on a set of working best practices (convention over configuration) but obviously not every recommendation suits every use case. For a deeper technical tour, the &lt;a href="https://www.youtube.com/channel/UCpIn7ox7j7bH_OFj7tYouOQ"&gt;John Savill&amp;#8217;s Technical Training channel&lt;/a&gt; has good videos (from 2020) on AKS &lt;a href="https://www.youtube.com/watch?v=c4nTKMU6fBU"&gt;overview&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=gksFrKiZjMc"&gt;high availability&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=6TZsd4toIbg"&gt;networking&lt;/a&gt;. Lastly, there is also an &lt;a href="https://www.the-aks-checklist.com/"&gt;AKS checklist&lt;/a&gt; to remind you of the implementation details to consider.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All the references aside, I need to write down some gotchas from my implementation experience in the last two month.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="identity-and-access-management"&gt;Identity and Access Management&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AKS is a special type of Azure resource in the sense that it manages other Azure services on user&amp;#8217;s behalf. Therefore the access management needs to consider several aspects:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-very-light-gray-to-cyan-bluish-gray-gradient-background has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Access Type&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Mechanisms involved&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;User access Kubernetes API&lt;/td&gt;&lt;td&gt;Azure AD, Azure RBAC and Kubernetes RBAC. &lt;br&gt;&amp;#8211; Azure AD is for authentication&lt;br&gt;&amp;#8211; Azure RBAC for Kubernetes&lt;br&gt;&amp;#8211; Kubernetes RBAC&lt;/td&gt;&lt;td&gt;A user connects to Kube-API server using kubectl&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AKS access other Azure resource&lt;/td&gt;&lt;td&gt;There are several identities that represents different components of AKS. For example, the AKS cluster, the node agent pool, and each add-on.&lt;br&gt;The AKS cluster can be represented as a service principal, or managed identity (system assigned or user assigned). &lt;br&gt;The node agent pool can be represented as a managed identity&lt;/td&gt;&lt;td&gt;AKS cluster connects to a VNet in a different resource group. (requiring cluster&amp;#8217;s identity to have network contributor role on the target network resource group)&lt;br&gt;AKS node agent pulls images from ACR (requiring the node agent pool&amp;#8217;s identity to have ArcPull role on the target ACR)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pod access other Azure resource&lt;/td&gt;&lt;td&gt;AAD-Pod Managed Identity&lt;/td&gt;&lt;td&gt;Business workload connects to managed database service such as PostgreSQL on Azure.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pod access Kubernetes API&lt;/td&gt;&lt;td&gt;Access Kubernetes API using Service Account. This issue is solved completely by Kubernetes native mechanisms. Roles and ClusterRoles defines permissions. RoleBindings and ClusterRoleBindings associates Service Accounts with permissions&lt;/td&gt;&lt;td&gt;Workload access ConfigMap, Secret etc.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the first access type, for RBAC with user to access Kubernetes API, there is an overlap between Azure RBAC and Kubnernetes RBAC. Azure RBAC has four &lt;a href="https://docs.microsoft.com/en-us/azure/aks/manage-azure-rbac#create-role-assignments-for-users-to-access-cluster"&gt;built-in roles&lt;/a&gt; and three of them (reader, writer, admin) are namespaced. When you use Azure CLI to manage to assign one of those roles, the rolebinding and cluster rolebinding record stored in etcd will be updated accordingly. &lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-black-color has-cyan-bluish-gray-background-color has-text-color has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;RBAC mechansim&lt;/td&gt;&lt;td&gt;Use case&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Azure RBAC for Kubernetes&lt;/td&gt;&lt;td&gt;Manage RBAC programmatically using Azure CLI, or infrastructure as code&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Kubernetes RBAC&lt;/td&gt;&lt;td&gt;Manage RBAC declaratively with more granularity for all types of Kubernetes resources including CRD&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For ease of operation it is advised to use Kubernetes RBAC whenever possible. Azure RBAC is still used for RBAC at the level of Azure resource but not at the level of Kubernetes resource.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the the second access type, AKS cluster may use managed identity or service principal. Azure&amp;#8217;s recommendation is managed identity over service principal. Managed Identity is a wrapper around Service Principal with less overhead. Managed Identity can be system assigned (created at the time of cluster creation), or user assigned (can be created ahead of time by Azure administrator and imported to the cluster&amp;#8217;s context).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The second access type can be further broken down because there are several components in AKS that uses their own identities. I list the &lt;a href="https://docs.microsoft.com/en-us/azure/aks/use-managed-identity"&gt;related managed identities&lt;/a&gt; as below:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-very-light-gray-to-cyan-bluish-gray-gradient-background has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Name&lt;/td&gt;&lt;td&gt;Purpose&lt;/td&gt;&lt;td&gt;BYO identity with Terraform&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;cluster identity&lt;/td&gt;&lt;td&gt;This identity represents the cluster&lt;/td&gt;&lt;td&gt;Specify in &lt;a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#identity"&gt;identity&lt;/a&gt; block in kubernetes_cluster resource&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;agent pool identity&lt;/td&gt;&lt;td&gt;This identity represents kubelet running in the agent pool&lt;/td&gt;&lt;td&gt;Specify in &lt;a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#kubelet_identity"&gt;kubelet_identity&lt;/a&gt; block. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;addon: azurepolicy&lt;/td&gt;&lt;td&gt;This identity represents azure policy addon to access the policy&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;addon: omsagent&lt;/td&gt;&lt;td&gt;This identity represents OMS agent to access monitoring etc&lt;/td&gt;&lt;td&gt;Specify in &lt;a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#oms_agent_identity"&gt;oms_agent_identity&lt;/a&gt; block &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;addon: secret&lt;/td&gt;&lt;td&gt;This identity represents to the secret addon, to access AKV&lt;/td&gt;&lt;td&gt;Specify in &lt;a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#secret_identity"&gt;secret_identity&lt;/a&gt; block &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;addon: ingress gateway &lt;/td&gt;&lt;td&gt;This identity represents the ingress application gateway&lt;/td&gt;&lt;td&gt;&lt;a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster#ingress_application_gateway_identity"&gt;ingress_application_gateway_identity&lt;/a&gt; block&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;By default, the system creates a new managed identity for each of the required identity above. For simplicity with identity management, we may create a managed identity and use it for all the occasions where an identity is needed and user assigned (BYO) identity is supported.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the &amp;#8220;az aks show&amp;#8221; command return (a JSON document), the &lt;em&gt;identity&lt;/em&gt; section (root level) reports the cluster identity, the &lt;em&gt;identityProfile&lt;/em&gt; section (root level) reports the agent pool (kubelet) identity. Other identities such as omsagent, are reported in their own child document.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="node-networking"&gt;Node Networking &lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In Azure, a subnet can span across multiple availability zones. Therefore an AKS cluster can put its nodes on a single subnet with nodes evenly distributed across three AZs for high availability. The AZ of each node is indicated in the node label, and can be &lt;a href="https://docs.microsoft.com/en-us/azure/aks/availability-zones#verify-node-distribution-across-zones"&gt;displayed&lt;/a&gt; with kubectl command.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Within a single AZ, a good practice to minimize latency between nodes is to place the nodes in a proximity placement group (PPG). However, only a &lt;a href="https://docs.microsoft.com/en-us/azure/aks/reduce-latency-ppg#node-pools-and-proximity-placement-groups"&gt;single PPG&lt;/a&gt; can be associated with a node group. You can&amp;#8217;t have three PPGs, one in each AZ, for a single subnet. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="pod-networking"&gt;Pod Networking&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The default Pod networking model is kubenet, which involves overlay network. Pod-to-Pod traffic across nodes requires Network Address Translation (NAT). To overcome this performance tax, Azure introduces Azure CNI which gives each Pod an routable IP address from the VNet&amp;#8217;s CIDR. This requires advanced IP planning to prevent IP exhaustion. A risk introduced in Azure CNI is that all Pods are exposed on the V-net, which needs to be protected by Network Security Group and/or outbound firewall.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="dns"&gt;DNS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the DNS side, when AKS cluster integrate with an external node network, it may create weird issues that are hard to troubleshoot. Another example is with DNS. If the V-Net uses an external DNS server (which is common for enterprises with hybrid network to use an on-premise DNS server), then the cluster creation failed with time-out with misleading error messages (for example, this&amp;nbsp;&lt;a href="https://github.com/Azure/AKS/issues/1972#issuecomment-868478020"&gt;comment&lt;/a&gt;). This is because the DNS name of the newly created cluster is not resolvable within the V-NET, which points to the on-prem DNS server. The fix to that is:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Use a BYO DNS zone (in Azure) for AKS cluster creation;&lt;/li&gt;&#10;&lt;li&gt;The AKS cluster will publish the A-record to the zone. To allow this to happen, the AKS cluster’s managed identity needs to have DNS contributor permission for the zone;&lt;/li&gt;&#10;&lt;li&gt;Configure the on-prem DNS for conditional forwarding to the DNS zone&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This fix will allow AKS to resolve its name and therefore confirm its own creation. Here is a good blog about the DNS zone&amp;nbsp;&lt;a href="https://blog.baeke.info/2021/07/01/dns-options-for-private-azure-kubernetes-service/"&gt;option&lt;/a&gt;s.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another potential issue introduced with the use of on-prem DNS server, is the resolution of single-label hostname of the nodes. This is not just an issue in the context of AKS. It is a generic issue with VMs running on a V-Net pointing to on-prem DNS, as explained in detail&amp;nbsp;&lt;a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-networks-name-resolution-for-vms-and-role-instances#name-resolution-that-uses-your-own-dns-server"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this situation, we should use the fully qualified hostname instead of single-label hostname. The fully qualified hostname with DNS suffix can help the on-prem server to configure conditional forwarding. For example, when the DNS suffix is *.internal.cloudapp.net, then forward it to Azure’s virtual internal DNS server 168.63.129.16 which can resolve the hostname.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If only the Pods need to resolve those FQDNs, then we can configure Core-DNS with&amp;nbsp;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/coredns-custom"&gt;conditional forwarding&lt;/a&gt;, which will take effect only at the cluster level without the need for changing the on-prem DNS. The Core-DNS configuration looks like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ConfigMap&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;coredns&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;custom&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;configmap&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;you&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;can&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;overwrite&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;your&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;changes&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kube&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;system&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cloudapp&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;override&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;you&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;may&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;select&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;any&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;here&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;but&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;it&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;must&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; .&lt;span style="color:#a6e22e"&gt;override&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;file&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;extension&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;rewrite&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;continue&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;regex&lt;/span&gt; &lt;span style="color:#f92672"&gt;^&lt;/span&gt;(.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;]{&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt;}&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;vmss&lt;/span&gt;[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;]{&lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;})&lt;span style="color:#a6e22e"&gt;$&lt;/span&gt; {&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;}.&lt;span style="color:#a6e22e"&gt;internal&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;cloudapp&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;net&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;answer&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;^&lt;/span&gt;(.&lt;span style="color:#f92672"&gt;*&lt;/span&gt;)&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;internal&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;cloudapp&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;net$&lt;/span&gt; {&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;forward&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;internal&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;cloudapp&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;net&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;168.63&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;129.16&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cloudapp&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;server&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;|&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;internal&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;cloudapp&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;net&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;53&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;errors&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cache&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;forward&lt;/span&gt; . &lt;span style="color:#ae81ff"&gt;168.63&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;129.16&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Alternatively, use Pod&amp;nbsp;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy"&gt;DNS policy&lt;/a&gt;&amp;nbsp;so that the Pod can use an external DNS server.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="initial-service-account"&gt;Initial Service Account&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When a cluster is created, an Azure AD user or group can be assigned as cluster administrator. For a CI/CD pipeline to interact with the newly created cluster, a service account in Kubernetes is needed. Suppose we use &lt;a href="https://static.digihunch.com/2021/11/infrastructure-deployment-in-terraform-2-2/"&gt;Terraform&lt;/a&gt; to create the AKS cluster, we can create such service account automatically with the Kubernetes provider. This requires that the Terraform execution environment to have network access to the cluster. If the AKS cluster is located in a private network, then the agent where Terraform CLI runs should also be on the network. Alternatively, use Terraform Enterprise hosted in an environment with access to the cluster&amp;#8217;s network.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="integration-with-azure-keyvault"&gt;Integration with Azure KeyVault&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure Key Vault can store several types of secrets, key value pair, X509 keys and certificate. When AKV is &lt;a href="https://docs.microsoft.com/en-us/azure/aks/csi-secrets-store-identity-access"&gt;integrated&lt;/a&gt; with an AKS cluster, the Kubernetes workload can access the secrets as mounted volumes, using CRD named SecretProviderClass. Further, they can be presented as Kubernetes Secret, using a Pod to &lt;a href="https://docs.microsoft.com/en-us/azure/aks/csi-secrets-store-driver#sync-mounted-content-with-a-kubernetes-secret"&gt;sync&lt;/a&gt; between mounted content and Secret. AKV has three types of entries: key, certificate and secret (key-value). The certificate entry requires both key and certificate are stored, with optional certificate chain. In my opinion this is an over design. Unless we need Azure to manage the certificate (e.g. rotation) I would simply use secret to store my own X509 key and certificate.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/12/aks-troubleshooting-lessons-learned/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;AKS Lessons Learned 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/12/from-ingress-to-gateway-why-you-need-istio-gateways-on-kubernetes-platforms/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;From Ingress to CRD: why my solution needs Istio Gateways on Kubernetes platforms&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>