<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ssl on Digi Hunch</title><link>https://static.digihunch.com/tag/ssl/</link><description>Recent content in ssl on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Mon, 12 May 2025 23:27:51 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/ssl/index.xml" rel="self" type="application/rss+xml"/><item><title>IAM Roles for any workload</title><link>https://static.digihunch.com/2024/07/iam-roles-for-any-workload/</link><pubDate>Sun, 14 Jul 2024 23:53:49 -0400</pubDate><guid>https://static.digihunch.com/2024/07/iam-roles-for-any-workload/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-iam-role-anywhere.webp" alt="Featured image of post IAM Roles for any workload" /&gt;&lt;h2 class="wp-block-heading"&gt;Background&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A few month back a client of mine wanted to use GitLab pipeline to deploy infrastructure on AWS with Terraform. The key question is how to authenticate the Terraform process running in the pipeline to AWS with temporary credential. Having &lt;a href="https://static.digihunch.com/2023/01/github-action-gotchas/"&gt;worked it out on GitHub&lt;/a&gt;, my proposal at time was to &lt;a href="https://docs.gitlab.com/ee/ci/cloud_services/aws/"&gt;add OIDC provider&lt;/a&gt; to represent the GitLab runner. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;After a few months, they told me that they are self-hosting their GitLab instance. The idea above was based on exposing an identity provider document on the public Internet, which the client is unable to do. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now, I have an idea: IAM Roles Anywhere.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;IAM Role Introduction&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Many 101 tutorials asks beginners to create standalone IAM users (or group) with IAM policies directly attached. For programatic access they also include creating a pair of access key and secret access key and pass them along to an external application. The keys are long term credentials, and worse, never expires. The leakage of these long-term credentials had been such a headache that AWS strongly discourage the use of long term credentials. You can feel the discouragement when trying to create an access key through the web console, or by the banners on top of the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html"&gt;documentation page&lt;/a&gt; about how to do so. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The recommendation is use temporary security credentials. In the context of AWS that means IAM roles. The users must assume an IAM role by issuing an API call, and the Security Token Service (STS) grants temporary credential in response.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="351px" viewBox="-0.5 -0.5 351 122" style="max-width:100%;max-height:122px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;g data-cell-id="0"&gt;&lt;g data-cell-id="1"&gt;&lt;g data-cell-id="VRZMaZhQ_cbes_kdLvWi-8"&gt;&lt;g&gt;&lt;rect x="0" y="0" width="350" height="120" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="VRZMaZhQ_cbes_kdLvWi-1"&gt;&lt;g&gt;&lt;path d="M 320 76.55 C 320 78.52 318.4 80 316.39 80 L 275.69 80 C 273.24 80 272 78.23 272 76.73 L 272 23.42 C 272 21.21 273.91 20 275.64 20 L 316.61 20 C 318.37 20 320 21.41 320 23.36 Z" fill="#759c3e" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 295.89 56.07 C 287 56.07 278.95 49.27 278.95 39.5 C 278.95 30.98 286.32 23.48 296.19 23.48 C 304.93 23.48 313.05 30.44 313.05 39.71 C 313.05 48.35 305.84 56.07 295.89 56.07 Z" fill="#4f4f4f" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 290.59 67.19 L 289.18 67.19 C 289.18 66.44 288.94 65.57 287.89 65.1 C 287.29 64.88 286.32 64.7 285.21 65.03 C 284.66 65.21 284.16 65.6 284.03 66.33 C 283.83 67.41 284.66 67.82 285.47 68.06 C 287.2 68.52 287.94 68.57 288.78 68.88 C 289.71 69.2 290.7 69.74 291 70.92 C 291.25 72.24 290.73 73.18 290.02 73.74 C 289.29 74.34 288.02 74.8 286.34 74.74 C 284.99 74.68 283.8 74.23 283.11 73.54 C 282.51 72.94 282.12 72.18 282.12 71.01 L 283.51 71.01 C 283.56 72.22 284.17 72.91 285.07 73.32 C 286.09 73.71 287.44 73.72 288.38 73.32 C 288.99 73.06 289.55 72.54 289.54 71.68 C 289.52 70.86 288.97 70.36 287.76 70.05 C 286.65 69.75 285.55 69.68 284.52 69.32 C 283.44 68.93 282.23 68.21 282.53 66.33 C 282.71 65.16 283.64 64.33 285.11 63.98 C 286.46 63.7 287.91 63.83 288.89 64.34 C 289.87 64.87 290.54 65.81 290.59 67.19 Z M 300.45 65.04 L 296.82 65.04 L 296.82 74.38 L 295.34 74.38 L 295.34 65.04 L 291.64 65.04 L 291.64 63.82 L 300.45 63.82 Z M 309.41 67.19 L 308 67.19 C 308 66.44 307.76 65.55 306.71 65.07 C 306.12 64.85 305.15 64.67 304.03 65.01 C 303.48 65.19 302.98 65.57 302.85 66.3 C 302.65 67.4 303.48 67.8 304.3 68.04 C 306.02 68.51 306.75 68.54 307.61 68.85 C 308.53 69.17 309.52 69.71 309.8 70.89 C 310.07 72.22 309.55 73.15 308.85 73.72 C 308.11 74.31 306.84 74.77 305.16 74.71 C 303.81 74.67 302.62 74.2 301.93 73.51 C 301.33 72.93 300.94 72.18 300.94 71.01 L 302.34 71.01 C 302.38 72.22 303 72.88 303.89 73.29 C 304.91 73.69 306.26 73.71 307.2 73.3 C 307.81 73.05 308.38 72.52 308.36 71.65 C 308.35 70.84 307.78 70.35 306.59 70.03 C 305.47 69.72 304.38 69.65 303.34 69.29 C 302.26 68.91 301.05 68.18 301.35 66.32 C 301.54 65.13 302.46 64.31 303.94 63.95 C 305.29 63.67 306.73 63.82 307.7 64.33 C 308.69 64.85 309.36 65.81 309.41 67.19 Z M 298.93 42.57 L 298.93 29.55 L 295.42 29.55 L 295.42 39.21 L 288.94 39.21 L 288.94 42.57 Z M 295.95 52.7 C 288.61 52.7 282.46 46.9 282.46 39.65 C 282.46 32.29 288.96 26.83 296.13 26.83 C 303.15 26.83 309.52 32.51 309.52 39.77 C 309.52 47.09 303.15 52.7 295.95 52.7 Z" fill="#ffffff" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="VRZMaZhQ_cbes_kdLvWi-2"&gt;&lt;g&gt;&lt;path d="M 56.16 79.58 L 48.37 75.17 L 43 78.24 L 30 70.84 L 30 56.08 L 37.43 51.83 L 37.43 32.71 L 59.71 20 L 82 32.69 L 82 58.05 L 64.07 68.25 L 64.07 75.04 Z" fill="#444444" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 59.71 44.44 L 79.65 33.11 L 59.79 21.87 L 39.94 33.11 Z M 42.35 63.72 L 31.21 57.4 L 31.21 70.11 L 42.35 76.5 Z M 42.92 62.75 L 54.06 56.35 L 42.92 50.03 L 31.78 56.35 Z M 54.7 62.3 L 54.7 57.48 L 43.56 63.79 L 43.56 76.5 L 48.17 73.87 L 48.17 65.98 Z M 58.9 63.12 L 58.9 45.9 L 39.04 34.57 L 39.04 50.92 L 42.99 48.66 L 55.91 56.02 L 55.91 61.62 L 56.08 61.54 Z M 64.06 66.51 L 80.46 57.16 L 80.46 34.49 L 60.6 45.82 L 60.6 64.07 L 64.06 66.03 Z M 55.92 69.87 L 62.05 66.39 L 55.99 62.9 L 49.93 66.39 Z M 55.51 77.8 L 55.51 70.84 L 49.37 67.35 L 49.37 74.32 Z M 56.63 77.8 L 62.78 74.32 L 62.78 67.35 L 56.63 70.84 Z" fill="#ffffff" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 87px; margin-left: 56px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;CLI&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="56" y="99" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;CLI&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="VRZMaZhQ_cbes_kdLvWi-4"&gt;&lt;g&gt;&lt;path d="M 82 32.81 L 263.63 32.99" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 268.88 33 L 261.88 36.49 L 263.63 32.99 L 261.89 29.49 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="VRZMaZhQ_cbes_kdLvWi-6"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 20px; margin-left: 163px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;Request: AssumeRole*&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="163" y="23" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px" text-anchor="middle"&gt;Request: AssumeRole*&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="VRZMaZhQ_cbes_kdLvWi-5"&gt;&lt;g&gt;&lt;path d="M 270 60 L 88.37 57.91" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 83.12 57.85 L 90.16 54.43 L 88.37 57.91 L 90.08 61.43 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="VRZMaZhQ_cbes_kdLvWi-7"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 90px; margin-left: 122px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;Response:&lt;div&gt;&amp;#8211; AccessKeyId&lt;/div&gt;&lt;div&gt;&amp;#8211; SecretAccessKey&lt;/div&gt;&lt;div&gt;&amp;#8211; SessionToken&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="122" y="94" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px"&gt;Response:&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This diagram has several variations. For example, the request can be AssumeRole, AssumeRoleWithSAML and AssumeRoleWithWebIdentity, depending on whether and how the user info is federated with external identity store. The returned response, a triplet of three values, makes the temporary credential that we should use in any secure environment. They must be renewed before expiry. This model works not only for human identity (e.g. SAML integration, OIDC integration, cross-account access) but also for workload identity (e.g. EC2 instance profile, Lambda execution role, ECS task role, etc). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another good example is &lt;a href="https://static.digihunch.com/2024/01/workload-identity-on-kubernetes-2-of-2-eks-and-rosa-on-aws/"&gt;IAM Role for Service Account (IRSA)&lt;/a&gt;, where a web identity represents a Kuberentes Service Account to gain role credential using the AssumeRoleWithWebIdentity API. In this post however, I&amp;#8217;d like to explore more about the IAM role for EC2 instance profile.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;The IMDS service &lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For EC2 instance, we all know that we can associate an IAM role as the instance profile and grant the process using AWS SDK running on the instance with permissions associated with the IAM role. At a lower level, this relies on the IMDS (Instance Metadata Service) running on the instance.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If an EC2 instance&amp;#8217;s profile points to an IAM role, a process running on the instance using AWS SDK will also need to get the triplet from the STS. It is summarized in this diagram:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="531px" viewBox="-0.5 -0.5 531 141" style="max-width:100%;max-height:141px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;g data-cell-id="0"&gt;&lt;g data-cell-id="1"&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-1"&gt;&lt;g&gt;&lt;rect x="0" y="0" width="530" height="140" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-2"&gt;&lt;g&gt;&lt;rect x="10" y="10" width="330" height="100" fill="#d5e8d4" stroke="#82b366" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-3"&gt;&lt;g&gt;&lt;path d="M 518 101.55 C 518 103.52 516.4 105 514.39 105 L 473.69 105 C 471.24 105 470 103.23 470 101.73 L 470 48.42 C 470 46.21 471.91 45 473.64 45 L 514.61 45 C 516.37 45 518 46.41 518 48.36 Z" fill="#759c3e" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 493.89 81.07 C 485 81.07 476.95 74.27 476.95 64.5 C 476.95 55.98 484.32 48.48 494.19 48.48 C 502.93 48.48 511.05 55.44 511.05 64.71 C 511.05 73.35 503.84 81.07 493.89 81.07 Z" fill="#4f4f4f" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 488.59 92.19 L 487.18 92.19 C 487.18 91.44 486.94 90.57 485.89 90.1 C 485.29 89.88 484.32 89.7 483.21 90.03 C 482.66 90.21 482.16 90.6 482.03 91.33 C 481.83 92.41 482.66 92.82 483.47 93.06 C 485.2 93.52 485.94 93.57 486.78 93.88 C 487.71 94.2 488.7 94.74 489 95.92 C 489.25 97.24 488.73 98.18 488.02 98.74 C 487.29 99.34 486.02 99.8 484.34 99.74 C 482.99 99.68 481.8 99.23 481.11 98.54 C 480.51 97.94 480.12 97.18 480.12 96.01 L 481.51 96.01 C 481.56 97.22 482.17 97.91 483.07 98.32 C 484.09 98.71 485.44 98.72 486.38 98.32 C 486.99 98.06 487.55 97.54 487.54 96.68 C 487.52 95.86 486.97 95.36 485.76 95.05 C 484.65 94.75 483.55 94.68 482.52 94.32 C 481.44 93.93 480.23 93.21 480.53 91.33 C 480.71 90.16 481.64 89.33 483.11 88.98 C 484.46 88.7 485.91 88.83 486.89 89.34 C 487.87 89.87 488.54 90.81 488.59 92.19 Z M 498.45 90.04 L 494.82 90.04 L 494.82 99.38 L 493.34 99.38 L 493.34 90.04 L 489.64 90.04 L 489.64 88.82 L 498.45 88.82 Z M 507.41 92.19 L 506 92.19 C 506 91.44 505.76 90.55 504.71 90.07 C 504.12 89.85 503.15 89.67 502.03 90.01 C 501.48 90.19 500.98 90.57 500.85 91.3 C 500.65 92.4 501.48 92.8 502.3 93.04 C 504.02 93.51 504.75 93.54 505.61 93.85 C 506.53 94.17 507.52 94.71 507.8 95.89 C 508.07 97.22 507.55 98.15 506.85 98.72 C 506.11 99.31 504.84 99.77 503.16 99.71 C 501.81 99.67 500.62 99.2 499.93 98.51 C 499.33 97.93 498.94 97.18 498.94 96.01 L 500.34 96.01 C 500.38 97.22 501 97.88 501.89 98.29 C 502.91 98.69 504.26 98.71 505.2 98.3 C 505.81 98.05 506.38 97.52 506.36 96.65 C 506.35 95.84 505.78 95.35 504.59 95.03 C 503.47 94.72 502.38 94.65 501.34 94.29 C 500.26 93.91 499.05 93.18 499.35 91.32 C 499.54 90.13 500.46 89.31 501.94 88.95 C 503.29 88.67 504.73 88.82 505.7 89.33 C 506.69 89.85 507.36 90.81 507.41 92.19 Z M 496.93 67.57 L 496.93 54.55 L 493.42 54.55 L 493.42 64.21 L 486.94 64.21 L 486.94 67.57 Z M 493.95 77.7 C 486.61 77.7 480.46 71.9 480.46 64.65 C 480.46 57.29 486.96 51.83 494.13 51.83 C 501.15 51.83 507.52 57.51 507.52 64.77 C 507.52 72.09 501.15 77.7 493.95 77.7 Z" fill="#ffffff" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-4"&gt;&lt;g&gt;&lt;rect x="212.5" y="60" width="105" height="35" rx="5.25" ry="5.25" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 103px; height: 1px; padding-top: 78px; margin-left: 214px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;IMDS v2&lt;div&gt;169.254.169.254&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="265" y="81" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;IMDS v2&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-5"&gt;&lt;g&gt;&lt;rect x="30" y="62.5" width="120" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 78px; margin-left: 31px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;AWS SDK&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="90" y="81" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;AWS SDK&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-6"&gt;&lt;g&gt;&lt;path d="M 149.88 74.26 L 206.76 75.35" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 212.01 75.45 L 204.95 78.81 L 206.76 75.35 L 205.08 71.82 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-7"&gt;&lt;g&gt;&lt;path d="M 211.87 84.5 L 156.37 84.95" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 151.12 84.99 L 158.09 81.43 L 156.37 84.95 L 158.15 88.43 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-8"&gt;&lt;g&gt;&lt;path d="M 317.29 70.78 L 463.63 70.03" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 468.88 70.01 L 461.9 73.54 L 463.63 70.03 L 461.86 66.54 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-9"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 58px; margin-left: 398px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;Request: AssumeRole&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="398" y="61" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px" text-anchor="middle"&gt;Request: AssumeRole&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-10"&gt;&lt;g&gt;&lt;path d="M 470 80 L 322.29 81.53" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 317.04 81.58 L 324.01 78.01 L 322.29 81.53 L 324.08 85.01 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-11"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 112px; margin-left: 352px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;Response:&lt;div&gt;&amp;#8211; AccessKeyId&lt;/div&gt;&lt;div&gt;&amp;#8211; SecretAccessKey&lt;/div&gt;&lt;div&gt;&amp;#8211; SessionToken&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="352" y="115" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px"&gt;Response:&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-12"&gt;&lt;g&gt;&lt;rect x="30" y="25" width="120" height="37.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;path d="M 42 25 L 42 62.5 M 138 25 L 138 62.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 94px; height: 1px; padding-top: 44px; margin-left: 43px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Application&lt;div&gt;Process&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="90" y="47" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Application&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="mtzehsWG86ey03g9Zuuk-13"&gt;&lt;g&gt;&lt;path d="M 180 20 L 210 20 L 210 50 L 180 50 Z" fill="#ed7100" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 189.43 40.57 L 200.14 40.57 L 200.14 29.86 L 189.43 29.86 Z M 201 29.86 L 202.71 29.86 L 202.71 30.71 L 201 30.71 L 201 32.43 L 202.71 32.43 L 202.71 33.29 L 201 33.29 L 201 34.57 L 202.71 34.57 L 202.71 35.43 L 201 35.43 L 201 37.14 L 202.71 37.14 L 202.71 38 L 201 38 L 201 39.71 L 202.71 39.71 L 202.71 40.57 L 201 40.57 L 201 40.63 C 201 41.07 200.64 41.43 200.2 41.43 L 200.14 41.43 L 200.14 43.14 L 199.29 43.14 L 199.29 41.43 L 197.57 41.43 L 197.57 43.14 L 196.71 43.14 L 196.71 41.43 L 195.43 41.43 L 195.43 43.14 L 194.57 43.14 L 194.57 41.43 L 192.86 41.43 L 192.86 43.14 L 192 43.14 L 192 41.43 L 190.29 41.43 L 190.29 43.14 L 189.43 43.14 L 189.43 41.43 L 189.37 41.43 C 188.93 41.43 188.57 41.07 188.57 40.63 L 188.57 40.57 L 187.29 40.57 L 187.29 39.71 L 188.57 39.71 L 188.57 38 L 187.29 38 L 187.29 37.14 L 188.57 37.14 L 188.57 35.43 L 187.29 35.43 L 187.29 34.57 L 188.57 34.57 L 188.57 33.29 L 187.29 33.29 L 187.29 32.43 L 188.57 32.43 L 188.57 30.71 L 187.29 30.71 L 187.29 29.86 L 188.57 29.86 L 188.57 29.8 C 188.57 29.36 188.93 29 189.37 29 L 189.43 29 L 189.43 27.29 L 190.29 27.29 L 190.29 29 L 192 29 L 192 27.29 L 192.86 27.29 L 192.86 29 L 194.57 29 L 194.57 27.29 L 195.43 27.29 L 195.43 29 L 196.71 29 L 196.71 27.29 L 197.57 27.29 L 197.57 29 L 199.29 29 L 199.29 27.29 L 200.14 27.29 L 200.14 29 L 200.2 29 C 200.64 29 201 29.36 201 29.8 Z M 195.43 46.09 C 195.43 46.12 195.4 46.14 195.38 46.14 L 183.91 46.14 C 183.88 46.14 183.86 46.12 183.86 46.09 L 183.86 34.62 C 183.86 34.6 183.88 34.57 183.91 34.57 L 186.43 34.57 L 186.43 33.71 L 183.91 33.71 C 183.41 33.71 183 34.12 183 34.62 L 183 46.09 C 183 46.59 183.41 47 183.91 47 L 195.38 47 C 195.88 47 196.29 46.59 196.29 46.09 L 196.29 44 L 195.43 44 Z M 207 23.91 L 207 35.38 C 207 35.88 206.59 36.29 206.09 36.29 L 203.57 36.29 L 203.57 35.43 L 206.09 35.43 C 206.12 35.43 206.14 35.4 206.14 35.38 L 206.14 23.91 C 206.14 23.88 206.12 23.86 206.09 23.86 L 194.62 23.86 C 194.6 23.86 194.57 23.88 194.57 23.91 L 194.57 26.43 L 193.71 26.43 L 193.71 23.91 C 193.71 23.41 194.12 23 194.62 23 L 206.09 23 C 206.59 23 207 23.41 207 23.91 Z" fill="#ffffff" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 35px; margin-left: 212px;"&gt;&lt;div data-drawio-colors="color: #232F3E; " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(35, 47, 62); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;EC2 Instance&lt;/span&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="212" y="39" fill="#232F3E" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px"&gt;EC2 I&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The IMDS is a service available on one of the link-local IP address (169.254.169.254) on the EC2 instance. Requests made to this IP address are not routed elsewhere. The Instance Metadata Service (IMDS) is a means for the cloud service provider&amp;#8217;s virtualization layer to share information with the processes on the operating system of a virtual machine. It responds with information related to the instance itself, such as the subnets, IAM role, instance ID, AMI ID, security group. The instance metadata also includes user data script for cloud init process to consume, and most relevantly, the role credential for the instance. This also requires that the IMDS service to have connectivity to the STS endpoint, either via interface endpoint or over the Internet. The AssumeRole calls are logged in CloudTrail.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All major cloud vendors (AWS, Azure and GCP) uses the IMDS mechanism, and this mechanism obviously draws the attention of bad actors. I find some good articles on this &lt;a href="https://www.sans.org/blog/cloud-instance-metadata-services-imds-/"&gt;here&lt;/a&gt; and &lt;a href="https://www.tenable.com/blog/secure-your-aws-ec2-instance-metadata-service-imds"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;IAM Role for EC2 Workload&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For EC2 instances at AWS, the initial IMDS v1 was introduced in 2012 and allows a GET method to fetch instance metadata. The IMDS v1 is subject to attacks such as SSRF (Server-side request forgery). In 2019 AWS introduced IMDS v2 which tackles those &lt;a href="https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/"&gt;vulnerabilities&lt;/a&gt;. As of date, the recommendation is to use IMDSv2. Here is an example of how to fetch instance metadata, including the credential:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Grab a token&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;TOKEN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;curl -X PUT &lt;span style="color:#e6db74"&gt;&amp;#34;http://169.254.169.254/latest/api/token&amp;#34;&lt;/span&gt; -H &lt;span style="color:#e6db74"&gt;&amp;#34;X-aws-ec2-metadata-token-ttl-seconds: 21600&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Get top-level instance metadata information&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl http://169.254.169.254/latest/meta-data/profile -H &lt;span style="color:#e6db74"&gt;&amp;#34;X-aws-ec2-metadata-token: &lt;/span&gt;$TOKEN&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Get the name of the role&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -H &lt;span style="color:#e6db74"&gt;&amp;#34;X-aws-ec2-metadata-token: &lt;/span&gt;$TOKEN&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; http://169.254.169.254/latest/meta-data/iam/security-credentials&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Get the credential for the role session&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -H &lt;span style="color:#e6db74"&gt;&amp;#34;X-aws-ec2-metadata-token: &lt;/span&gt;$TOKEN&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; http://169.254.169.254/latest/meta-data/iam/security-credentials/InstanceProfileRoleName&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;These commands emulate how the SDK library fetches the credentials to assume the instance profile role. You can also find similar commands on the &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#instance-metadata-security-credentials"&gt;documentation&lt;/a&gt;. However, there isn&amp;#8217;t much details about how the instance metadata service interacts with the STS service, except a general statement:&lt;/p&gt;&#10;&lt;blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;cite&gt;These security credentials are temporary and we rotate them automatically. We make new credentials available at least five minutes before the expiration of the old credentials.&lt;/cite&gt;&lt;/blockquote&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When creating a new EC2 instance, make sure that the instance metadata option has http_endpoint enabled, to enable the IMDS service. Also set http_tokens to required, which would run IMDSv2 exclusively. With that setup, the application does not have to mana to use an &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/use-a-supported-sdk-version-for-imdsv2.html"&gt;SDK version&lt;/a&gt; that supports IMDSv2. Another metadata option is http_put_response_hop_limit, with default of 1. This limits the number of hops in the metadata request. If the process runs from a Docker container with bridge networking mode, set it to 2 or the process cannot even secure a token.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="581px" viewBox="-0.5 -0.5 581 161" style="max-width:100%;max-height:161px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;g data-cell-id="0"&gt;&lt;g data-cell-id="1"&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-1"&gt;&lt;g&gt;&lt;rect x="0" y="0" width="580" height="160" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-2"&gt;&lt;g&gt;&lt;rect x="10" y="10" width="360" height="138.75" fill="#d5e8d4" stroke="#82b366" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-14"&gt;&lt;g&gt;&lt;rect x="20" y="20" width="190" height="110" rx="16.5" ry="16.5" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-3"&gt;&lt;g&gt;&lt;path d="M 565.5 114.05 C 565.5 116.02 563.9 117.5 561.89 117.5 L 521.19 117.5 C 518.74 117.5 517.5 115.73 517.5 114.23 L 517.5 60.92 C 517.5 58.71 519.41 57.5 521.14 57.5 L 562.11 57.5 C 563.87 57.5 565.5 58.91 565.5 60.86 Z" fill="#759c3e" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 541.39 93.57 C 532.5 93.57 524.45 86.77 524.45 77 C 524.45 68.48 531.82 60.98 541.69 60.98 C 550.43 60.98 558.55 67.94 558.55 77.21 C 558.55 85.85 551.34 93.57 541.39 93.57 Z" fill="#4f4f4f" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 536.09 104.69 L 534.68 104.69 C 534.68 103.94 534.44 103.07 533.39 102.6 C 532.79 102.38 531.82 102.2 530.71 102.53 C 530.16 102.71 529.66 103.1 529.53 103.83 C 529.33 104.91 530.16 105.32 530.97 105.56 C 532.7 106.02 533.44 106.07 534.28 106.38 C 535.21 106.7 536.2 107.24 536.5 108.42 C 536.75 109.74 536.23 110.68 535.52 111.24 C 534.79 111.84 533.52 112.3 531.84 112.24 C 530.49 112.18 529.3 111.73 528.61 111.04 C 528.01 110.44 527.62 109.68 527.62 108.51 L 529.01 108.51 C 529.06 109.72 529.67 110.41 530.57 110.82 C 531.59 111.21 532.94 111.22 533.88 110.82 C 534.49 110.56 535.05 110.04 535.04 109.18 C 535.02 108.36 534.47 107.86 533.26 107.55 C 532.15 107.25 531.05 107.18 530.02 106.82 C 528.94 106.43 527.73 105.71 528.03 103.83 C 528.21 102.66 529.14 101.83 530.61 101.48 C 531.96 101.2 533.41 101.33 534.39 101.84 C 535.37 102.37 536.04 103.31 536.09 104.69 Z M 545.95 102.54 L 542.32 102.54 L 542.32 111.88 L 540.84 111.88 L 540.84 102.54 L 537.14 102.54 L 537.14 101.32 L 545.95 101.32 Z M 554.91 104.69 L 553.5 104.69 C 553.5 103.94 553.26 103.05 552.21 102.57 C 551.62 102.35 550.65 102.17 549.53 102.51 C 548.98 102.69 548.48 103.07 548.35 103.8 C 548.15 104.9 548.98 105.3 549.8 105.54 C 551.52 106.01 552.25 106.04 553.11 106.35 C 554.03 106.67 555.02 107.21 555.3 108.39 C 555.57 109.72 555.05 110.65 554.35 111.22 C 553.61 111.81 552.34 112.27 550.66 112.21 C 549.31 112.17 548.12 111.7 547.43 111.01 C 546.83 110.43 546.44 109.68 546.44 108.51 L 547.84 108.51 C 547.88 109.72 548.5 110.38 549.39 110.79 C 550.41 111.19 551.76 111.21 552.7 110.8 C 553.31 110.55 553.88 110.02 553.86 109.15 C 553.85 108.34 553.28 107.85 552.09 107.53 C 550.97 107.22 549.88 107.15 548.84 106.79 C 547.76 106.41 546.55 105.68 546.85 103.82 C 547.04 102.63 547.96 101.81 549.44 101.45 C 550.79 101.17 552.23 101.32 553.2 101.83 C 554.19 102.35 554.86 103.31 554.91 104.69 Z M 544.43 80.07 L 544.43 67.05 L 540.92 67.05 L 540.92 76.71 L 534.44 76.71 L 534.44 80.07 Z M 541.45 90.2 C 534.11 90.2 527.96 84.4 527.96 77.15 C 527.96 69.79 534.46 64.33 541.63 64.33 C 548.65 64.33 555.02 70.01 555.02 77.27 C 555.02 84.59 548.65 90.2 541.45 90.2 Z" fill="#ffffff" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-4"&gt;&lt;g&gt;&lt;rect x="260" y="72.5" width="105" height="35" rx="5.25" ry="5.25" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 103px; height: 1px; padding-top: 90px; margin-left: 261px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;IMDS v2&lt;div&gt;169.254.169.254&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="313" y="94" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;IMDS v2&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-5"&gt;&lt;g&gt;&lt;rect x="30" y="87.5" width="120" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 103px; margin-left: 31px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;AWS SDK&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="90" y="106" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;AWS SDK&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-8"&gt;&lt;g&gt;&lt;path d="M 364.79 83.28 L 511.13 82.53" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 516.38 82.51 L 509.4 86.04 L 511.13 82.53 L 509.36 79.04 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-9"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 71px; margin-left: 445px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;Request: AssumeRole&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="445" y="74" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px" text-anchor="middle"&gt;Request: AssumeRole&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-10"&gt;&lt;g&gt;&lt;path d="M 517.5 92.5 L 369.79 94.03" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 364.54 94.08 L 371.51 90.51 L 369.79 94.03 L 371.58 97.51 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-11"&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 124px; margin-left: 400px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;Response:&lt;div&gt;&amp;#8211; AccessKeyId&lt;/div&gt;&lt;div&gt;&amp;#8211; SecretAccessKey&lt;/div&gt;&lt;div&gt;&amp;#8211; SessionToken&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="400" y="128" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="11px"&gt;Response:&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-12"&gt;&lt;g&gt;&lt;rect x="30" y="50" width="120" height="37.5" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;path d="M 42 50 L 42 87.5 M 138 50 L 138 87.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 94px; height: 1px; padding-top: 69px; margin-left: 43px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Application&lt;div&gt;Process&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="90" y="72" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Application&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-13"&gt;&lt;g&gt;&lt;path d="M 240 20 L 270 20 L 270 50 L 240 50 Z" fill="#ed7100" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 249.43 40.57 L 260.14 40.57 L 260.14 29.86 L 249.43 29.86 Z M 261 29.86 L 262.71 29.86 L 262.71 30.71 L 261 30.71 L 261 32.43 L 262.71 32.43 L 262.71 33.29 L 261 33.29 L 261 34.57 L 262.71 34.57 L 262.71 35.43 L 261 35.43 L 261 37.14 L 262.71 37.14 L 262.71 38 L 261 38 L 261 39.71 L 262.71 39.71 L 262.71 40.57 L 261 40.57 L 261 40.63 C 261 41.07 260.64 41.43 260.2 41.43 L 260.14 41.43 L 260.14 43.14 L 259.29 43.14 L 259.29 41.43 L 257.57 41.43 L 257.57 43.14 L 256.71 43.14 L 256.71 41.43 L 255.43 41.43 L 255.43 43.14 L 254.57 43.14 L 254.57 41.43 L 252.86 41.43 L 252.86 43.14 L 252 43.14 L 252 41.43 L 250.29 41.43 L 250.29 43.14 L 249.43 43.14 L 249.43 41.43 L 249.37 41.43 C 248.93 41.43 248.57 41.07 248.57 40.63 L 248.57 40.57 L 247.29 40.57 L 247.29 39.71 L 248.57 39.71 L 248.57 38 L 247.29 38 L 247.29 37.14 L 248.57 37.14 L 248.57 35.43 L 247.29 35.43 L 247.29 34.57 L 248.57 34.57 L 248.57 33.29 L 247.29 33.29 L 247.29 32.43 L 248.57 32.43 L 248.57 30.71 L 247.29 30.71 L 247.29 29.86 L 248.57 29.86 L 248.57 29.8 C 248.57 29.36 248.93 29 249.37 29 L 249.43 29 L 249.43 27.29 L 250.29 27.29 L 250.29 29 L 252 29 L 252 27.29 L 252.86 27.29 L 252.86 29 L 254.57 29 L 254.57 27.29 L 255.43 27.29 L 255.43 29 L 256.71 29 L 256.71 27.29 L 257.57 27.29 L 257.57 29 L 259.29 29 L 259.29 27.29 L 260.14 27.29 L 260.14 29 L 260.2 29 C 260.64 29 261 29.36 261 29.8 Z M 255.43 46.09 C 255.43 46.12 255.4 46.14 255.38 46.14 L 243.91 46.14 C 243.88 46.14 243.86 46.12 243.86 46.09 L 243.86 34.62 C 243.86 34.6 243.88 34.57 243.91 34.57 L 246.43 34.57 L 246.43 33.71 L 243.91 33.71 C 243.41 33.71 243 34.12 243 34.62 L 243 46.09 C 243 46.59 243.41 47 243.91 47 L 255.38 47 C 255.88 47 256.29 46.59 256.29 46.09 L 256.29 44 L 255.43 44 Z M 267 23.91 L 267 35.38 C 267 35.88 266.59 36.29 266.09 36.29 L 263.57 36.29 L 263.57 35.43 L 266.09 35.43 C 266.12 35.43 266.14 35.4 266.14 35.38 L 266.14 23.91 C 266.14 23.88 266.12 23.86 266.09 23.86 L 254.62 23.86 C 254.6 23.86 254.57 23.88 254.57 23.91 L 254.57 26.43 L 253.71 26.43 L 253.71 23.91 C 253.71 23.41 254.12 23 254.62 23 L 266.09 23 C 266.59 23 267 23.41 267 23.91 Z" fill="#ffffff" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 35px; margin-left: 272px;"&gt;&lt;div data-drawio-colors="color: #232F3E; " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(35, 47, 62); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;&lt;div&gt;&lt;span style="background-color: initial;"&gt;EC2 Instance&lt;/span&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="272" y="39" fill="#232F3E" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px"&gt;EC2 I&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-23"&gt;&lt;g&gt;&lt;path d="M 150 110 Q 160 170 171.64 113.74" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 172.7 108.59 L 174.71 116.16 L 171.64 113.74 L 167.86 114.74 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-24"&gt;&lt;g&gt;&lt;path d="M 238.45 107.5 Q 260 170 287.49 105.85" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 289.56 101.03 L 290.02 108.84 L 287.49 105.85 L 283.59 106.08 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-26"&gt;&lt;g&gt;&lt;rect x="180" y="87.5" width="50" height="22.5" fill="#75dfff" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 85px; margin-left: 181px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Bridge&lt;div&gt;Network&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="205" y="85" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Bridge&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-22"&gt;&lt;g&gt;&lt;rect x="220" y="87.5" width="30" height="20" fill="none" stroke="none" pointer-events="all"&gt;&lt;/rect&gt;&lt;path d="M 225.13 105.54 L 225.13 100.05 L 235.79 100.05 L 235.79 102.79 L 241.32 102.79 L 241.32 103.58 L 247.24 103.58 L 247.24 101.23 L 241.32 101.23 L 241.32 102.01 L 236.58 102.01 L 236.58 98.09 L 244.08 98.09 L 244.08 98.87 L 248.82 98.87 L 248.82 96.52 L 244.08 96.52 L 244.08 97.3 L 235.79 97.3 L 235.79 99.26 L 225.13 99.26 L 225.13 96.13 L 232.63 96.13 L 232.63 93.38 L 236.58 93.38 L 236.58 94.56 L 242.5 94.56 L 242.5 91.42 L 236.58 91.42 L 236.58 92.6 L 231.84 92.6 L 231.84 95.34 L 225.13 95.34 L 225.13 89.85 L 250 89.85 L 250 105.54 L 239.74 105.54 L 239.74 107.5 L 238.95 107.5 L 238.95 105.54 L 238.16 105.54 L 238.16 107.5 L 237.37 107.5 L 237.37 105.54 L 236.58 105.54 L 236.58 107.5 L 235.79 107.5 L 235.79 105.54 L 235 105.54 L 235 107.5 L 234.21 107.5 L 234.21 105.54 L 233.42 105.54 L 233.42 107.5 L 232.63 107.5 L 232.63 105.54 L 231.84 105.54 L 231.84 107.5 L 231.05 107.5 L 231.05 105.54 L 230.26 105.54 L 230.26 107.5 L 229.47 107.5 L 229.47 105.54 L 228.68 105.54 L 228.68 107.5 L 227.89 107.5 L 227.89 105.54 Z M 222.76 107.5 L 222.76 88.68 L 220 88.68 L 220 87.5 L 223.95 87.5 L 223.95 107.5 Z" fill="#505050" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-16"&gt;&lt;g&gt;&lt;rect x="160" y="87.5" width="30" height="20" fill="none" stroke="none" pointer-events="all"&gt;&lt;/rect&gt;&lt;path d="M 165.13 105.54 L 165.13 100.05 L 175.79 100.05 L 175.79 102.79 L 181.32 102.79 L 181.32 103.58 L 187.24 103.58 L 187.24 101.23 L 181.32 101.23 L 181.32 102.01 L 176.58 102.01 L 176.58 98.09 L 184.08 98.09 L 184.08 98.87 L 188.82 98.87 L 188.82 96.52 L 184.08 96.52 L 184.08 97.3 L 175.79 97.3 L 175.79 99.26 L 165.13 99.26 L 165.13 96.13 L 172.63 96.13 L 172.63 93.38 L 176.58 93.38 L 176.58 94.56 L 182.5 94.56 L 182.5 91.42 L 176.58 91.42 L 176.58 92.6 L 171.84 92.6 L 171.84 95.34 L 165.13 95.34 L 165.13 89.85 L 190 89.85 L 190 105.54 L 179.74 105.54 L 179.74 107.5 L 178.95 107.5 L 178.95 105.54 L 178.16 105.54 L 178.16 107.5 L 177.37 107.5 L 177.37 105.54 L 176.58 105.54 L 176.58 107.5 L 175.79 107.5 L 175.79 105.54 L 175 105.54 L 175 107.5 L 174.21 107.5 L 174.21 105.54 L 173.42 105.54 L 173.42 107.5 L 172.63 107.5 L 172.63 105.54 L 171.84 105.54 L 171.84 107.5 L 171.05 107.5 L 171.05 105.54 L 170.26 105.54 L 170.26 107.5 L 169.47 107.5 L 169.47 105.54 L 168.68 105.54 L 168.68 107.5 L 167.89 107.5 L 167.89 105.54 Z M 162.76 107.5 L 162.76 88.68 L 160 88.68 L 160 87.5 L 163.95 87.5 L 163.95 107.5 Z" fill="#505050" stroke="none" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-cell-id="rtsicqcqSDVIAgyO7OKc-28"&gt;&lt;g&gt;&lt;rect x="30" y="20" width="110" height="30" fill="none" stroke="none" pointer-events="all"&gt;&lt;/rect&gt;&lt;/g&gt;&lt;g&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 35px; margin-left: 31px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Docker Daemon&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="85" y="39" fill="rgb(0, 0, 0)" font-family="&amp;quot;Helvetica&amp;quot;" font-size="12px" text-anchor="middle"&gt;Docker Daemon&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The diagram above illustrates this scenario with two hops.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;IAM Role Anywhere Concept&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As this point, we know that the process of workload assuming an IAM role, is essentially using SDK to gain role credentials from instance metadata. In addition to using SDK and instance metadata, AWS also supports using X.509 certificate to gain role credentials. As a result, workload no longer needs AWS SDK, and it doesn&amp;#8217;t rely on instance metadata from an EC2 instance. This mechanism is known as IAM Role Anywhere, and it greatly expands the use cases for IAM Role. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To make this work, we first have to provide a certificate authority (CA) to AWS as a trust anchor. It can be any X.509 CA including AWS Private CA. The IAM Roles Anywhere will allow any end-entity endorsed by this trust anchor, to assume an IAM role as specified. We also need to create a profile, in which we can add IAM policies directly, or link to an IAM roles with a trust policy for service principal &lt;code&gt;rolesanywhere.amazonaws.com&lt;/code&gt;. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="691" height="283" src="https://static.digihunch.com/wp-content/uploads/2024/07/iam-role-anywhere-diagram.webp" alt="" class="wp-image-12989" srcset="https://static.digihunch.com/wp-content/uploads/2024/07/iam-role-anywhere-diagram.webp 691w, https://static.digihunch.com/wp-content/uploads/2024/07/iam-role-anywhere-diagram-300x123.webp 300w" sizes="auto, (max-width: 691px) 100vw, 691px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To gain role credential, the requestor must provide both the private key, and its end-entity certificate. The certificate proofs the endorsement of the CA as Role&amp;#8217;s trust anchor specifies. The private key proofs the requestor&amp;#8217;s identity. The requestor uses the &lt;a href="https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html"&gt;aws_signing_helper&lt;/a&gt; utility to request role credentials. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The utility is compatible with the &lt;code&gt;credential_process&lt;/code&gt; feature in AWS config, which passes the returned role credentials to the AWS config profile for AWS CLI or SDK running on external virtual machine.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;IAM Role Anywhere Lab&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s tweak the three commands from this &lt;a href="https://static.digihunch.com/2021/08/creating-tls-certificate-kubernetes/"&gt;old post&lt;/a&gt; of mine to create the test materials: a self-signed CA and a certificate signed by the CA:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days &lt;span style="color:#ae81ff"&gt;356&lt;/span&gt; -nodes -subj &lt;span style="color:#e6db74"&gt;&amp;#39;/CN=Health Certificate Authority&amp;#39;&lt;/span&gt; -addext basicConstraints&lt;span style="color:#f92672"&gt;=&lt;/span&gt;critical,CA:TRUE,pathlen:1 -addext keyUsage&lt;span style="color:#f92672"&gt;=&lt;/span&gt;keyCertSign&#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;cat &amp;gt; ext.cnf &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;[v3_leaf]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;keyUsage = digitalSignature&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;basicConstraints=CA:false&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;EOF&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;openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj &lt;span style="color:#e6db74"&gt;&amp;#39;/CN=*.digihunch.com&amp;#39;&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;openssl x509 -req -sha256 -days &lt;span style="color:#ae81ff"&gt;365&lt;/span&gt; -in server.csr -CA ca.crt -CAkey ca.key -set_serial &lt;span style="color:#ae81ff"&gt;01&lt;/span&gt; -out server.crt -extfile ext.cnf -extensions v3_leaf&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;I tweak them to add the &lt;a href="https://static.digihunch.com/2024/02/public-key-infrastructure-1-of-3-basics/"&gt;X.509 extensions&lt;/a&gt; to meet the &lt;a href="https://docs.aws.amazon.com/rolesanywhere/latest/userguide/trust-model.html"&gt;requirement&lt;/a&gt; for signature validation. We need the following files from the output.&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;ca.crt -&amp;gt; the certificate of the CA. We provide this file as the trust anchor&lt;/li&gt;&#10;&lt;li&gt;server.crt -&amp;gt; the certificate of the server, we need it as the end-entity certificate&lt;/li&gt;&#10;&lt;li&gt;server.key -&amp;gt; we need to present this file to proof identity of the requestor&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;First, we go to AWS console and create a new trust anchor. Copy the content of ca.crt as the certificate. Then we can create a profile with an IAM role, with the trust policy looking like &lt;a href="https://docs.aws.amazon.com/rolesanywhere/latest/userguide/trust-model.html"&gt;this&lt;/a&gt; example. Then we can request the role credential with one command:&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws_signing_helper credential-process --certificate server.crt --private-key server.key --trust-anchor-arn $TRUST_ANCHOR_ARN --profile-arn $PROFILE_ARN --role-arn $ROLE_ARN&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Moreover, if the workload supports AWS SDK or can use CLI but not an EC2 instance, we can bake this in the AWS profile on the external machine:&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[profile myprofile]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;output = json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;credential_process = aws_signing_helper credential-process --certificate /path/server.crt --private-key /path/server.key --trust-anchor-arn $TRUST_ANCHOR_ARN --profile-arn $PROFILE_ARN --role-arn $ROLE_ARN&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can even configure this in any &lt;a href="https://aws.amazon.com/blogs/security/enable-external-pipeline-deployments-to-aws-cloud-by-using-iam-roles-anywhere/"&gt;pipeline&lt;/a&gt; as code to allow deployment from a non-AWS pipeline. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In summary, apart from native AWS services, an IAM role can trust the following types of principals:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Native IAM identity such as an IAM user or an IAM group&lt;/li&gt;&#10;&lt;li&gt;Authenticated identity from SAML identity provider that IAM is configured to trust&lt;/li&gt;&#10;&lt;li&gt;Authenticated identity from OIDC identity provider that IAM is configured to trust&lt;/li&gt;&#10;&lt;li&gt;Validated identity endorsed by a Certificate Authority that IAM designate as a trust anchor&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The first type is rarely used because few organizations uses AWS IAM as their identity store. Most organizations have their identity store with federation capability via SAML. On the other hand, a lot of modern applications adopts identity stores with OIDC compliance. Now with IAM Role Anywhere, any entity with X.509 identity can also assume an IAM role. It works with any CI/CD pipeline, whether it is self-hosted. Also, it is now more important to keep the keys safe. &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/2024/05/managing-ec2-instances-across-aws-accounts-ssm/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Managing EC2 instances across accounts with Ansible&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2024/08/test-open-id-connect-flows-locally/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Test Open ID Connect Flows Locally&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Public Key Infrastructure 2 of 3 – Certificate Automation</title><link>https://static.digihunch.com/2024/03/public-key-infrastructure-2-of-3-certificate-automation/</link><pubDate>Fri, 08 Mar 2024 00:14:00 -0400</pubDate><guid>https://static.digihunch.com/2024/03/public-key-infrastructure-2-of-3-certificate-automation/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-pki-2-1.webp" alt="Featured image of post Public Key Infrastructure 2 of 3 – Certificate Automation" /&gt;&lt;p class="wp-block-paragraph"&gt;Following the last post on PKI, we&amp;#8217;ll discuss automation of certificate issuance. Two key activities to automate are: validation of the requestor and issuance of the certificate.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Validation&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Validation isn&amp;#8217;t always required. For private CAs, the trust boundary does not go beyond the internal engineering team, there is little incentive to perform any validation. AWS Private CA is based on this idea. The requestor can claim to be any identity. The private CA, when issuing the certificate, does not perform any validation. Neither is there a need to convince any entity outside of the trust boundary of the validity of the certificate. Validation is optional. For public facing certificate however, validation is a must because we&amp;#8217;re convincing every browser in the world of the validity of the certificate requestor. Common validation levels include:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Domain Validation (DV): the certificate requestor must demonstrate the right to administratively manage the affected DNS domain.&lt;/li&gt;&#10;&lt;li&gt;Organization Validation (OV): in addition to the DV criterion, the issuer verifies the actual existence of the requestor&amp;#8217;s organization as a legal entity.&lt;/li&gt;&#10;&lt;li&gt;Extended Validation (EV): the certificate requestor must persuade the certificate provider of its legal identity, including manual verification checks y a human. Unlike DV and OV certificates, only a subset of CAs can issue EV certificates.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For both OV and EV, a certificate provider publishes its vetting criteria through its certificate policy. They require human validation of any registrants. At corporate level, EV certificates are required for sensitive public-facing workloads (e.g. banking, financial, health information). For non-sensitive public-facing workloads, DV certificates may be sufficient. For non-public facing workloads, such as software testing, they may go with DV certificates or no validation at all, depending on the specific use case. Since I set up PKI for the latter, I&amp;#8217;ll focus on DV. DV is the most basic level and can be fully automated. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="657" src="https://static.digihunch.com/wp-content/uploads/2024/03/dv.webp" alt="" class="wp-image-12980" srcset="https://static.digihunch.com/wp-content/uploads/2024/03/dv.webp 1024w, https://static.digihunch.com/wp-content/uploads/2024/03/dv-300x192.webp 300w, https://static.digihunch.com/wp-content/uploads/2024/03/dv-768x493.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;DigiCert, a well-known trusted third party, has a &lt;a href="https://www.digicert.com/difference-between-dv-ov-and-ev-ssl-certificates"&gt;detailed page&lt;/a&gt; on the differences among DV, OV and EV.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Certificate Automation&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As to automation, there are some common certificate automation protocols:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;ACME (Automated Certificate Management Environment): commonly used in web server automation.&lt;/li&gt;&#10;&lt;li&gt;SCEP (Simple Certificate Enrollment Protocol): commonly used in enterprise environments for managing certificates in the network devices such as routers, switches and IP phones.&lt;/li&gt;&#10;&lt;li&gt;EST (Enrolment over Secure Transport): a more secure alternative to SCEP suitable for various use cases beyond network devices.&lt;/li&gt;&#10;&lt;li&gt;CMP (Certificate Management Protocol): more comprehensive protocol with a wide range of functionalities for complex certificate management scenarios.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SCEP is common in network industry. EST and CMP target very specific scenarios. We&amp;#8217;ll examine ACME as it&amp;#8217;s most relevant to the use case of web service. The biggest advocate of ACME is Let&amp;#8217;s Encrypt, a non-profit CA run by ISRG that provisions X.509 certificates at no charge. Let&amp;#8217;s Encrypt is the world&amp;#8217;s largest CA, aiming to secure all websites with HTTPS. ACME only issues DV certificates, since they can be fully automated.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;The ACME Protocol&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The ACME protocol automates validation and issuance. The certificate requestor will have to use an ACME-capable client. The certificate provider (CA) needs to act as ACME server. At a high level, the flow looks like this:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="918" height="1024" src="https://static.digihunch.com/wp-content/uploads/2024/03/acme-918x1024.webp" alt="" class="wp-image-13092" srcset="https://static.digihunch.com/wp-content/uploads/2024/03/acme-918x1024.webp 918w, https://static.digihunch.com/wp-content/uploads/2024/03/acme-269x300.webp 269w, https://static.digihunch.com/wp-content/uploads/2024/03/acme-768x857.webp 768w, https://static.digihunch.com/wp-content/uploads/2024/03/acme-1377x1536.webp 1377w, https://static.digihunch.com/wp-content/uploads/2024/03/acme.webp 1662w" sizes="auto, (max-width: 918px) 100vw, 918px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I came across this good diagram on the ACME flow from a post from &lt;a href="https://smallstep.com/blog/private-acme-server/"&gt;small step&lt;/a&gt;. It has all the transactions in detail. As it shows, the delivery (issuance) of certificate material is based on HTTP POST method. The domain validation process is based on a challenge-response model. The ACME specification makes this an extension point, with the following most comment challenge types:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;HTTP-01 (HTTP Challenge): the domain in question needs to host a random number at a random URL under /.well-known/acme-challenge on port 80. The CA will fire an HTTP GET request to that URL. This is easy to configure because we usually have full control on the web server. There must be network connectivity between the web server and the CA to allow HTTP traffic.&lt;/li&gt;&#10;&lt;li&gt;DNS-01 (DNS Challenge): the requestor provisions a TXT record with random value. The ACME server does not need to connect to the web server. It only needs to perform a DNS lookup to confirm the challenge. However, the certificate requestor needs the privilege to modify DNS record.&lt;/li&gt;&#10;&lt;li&gt;TLS-ALPN-01 (TLS ALPN Challenge): ALPN is the protocol during TLS negotiation. The client presents a self-signed TLS certificate containing the challenge response as a special X.509 certificate extension. This challenge type is useful when a security policy requires the CA to reach the client via a TLS connection.&lt;/li&gt;&#10;&lt;li&gt;DEVICE-ATTEST-01 (Device Attestation Challenge): This is for Apple Managed Device Attestation (ADA) and other secure zero-touch provisioning (SZTP) applications as part of your device management (MDM) strategy. Certificates identify specific hardware devices, via permanent device IDs. These are typically client certificates that can be used for device authentication.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;At the implementation level, Let&amp;#8217;s encrypt drives its public CA with &lt;a href="https://github.com/letsencrypt/boulder"&gt;Boulder&lt;/a&gt;. It supports two &lt;a href="https://letsencrypt.org/docs/challenge-types/"&gt;challenge types&lt;/a&gt;. When hosting a private CA, you can use Boulder too. Some feel Boulder is complicated and you can consider the following alternatives:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://lab-ca.net/"&gt;LabCA&lt;/a&gt;: based on Boulder and supports hosting in docker.&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://smallstep.com/docs/step-ca/"&gt;Step CA&lt;/a&gt; (open source): a simple CA solution&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://cert-manager.io/docs/configuration/acme/"&gt;Cert Manager&lt;/a&gt;: very popular choice on Kubernetes&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.hashicorp.com/products/vault"&gt;Hashicorp Vault&lt;/a&gt;: a secret management solution including certificate management capability with ACME support.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You may combine different solutions for all level of CAs. For example, use Step CA for internal root CA, and Cert Manager for intermediate CAs for Kubernetes workloads. On the client side, Let&amp;#8217;s Encrypt recommends Certbot. However, there are many choices. Step CLI (by Step CA), acme.sh, etc. Let&amp;#8217;s Encrypt compiled a &lt;a href="https://letsencrypt.org/docs/client-options/"&gt;list&lt;/a&gt; here. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If we&amp;#8217;re not seeking automation with ACME in our process, and just want to manually sign certificates, we can use generic tools (e.g. openSSL, cfssl, easyRSA, etc). They act both as client (gingnerate CSR) and server (signing CSR) using different command switches.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Renewal and Revocation&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lifecycle management involves renewal and revocations. Renewal is essentially re-issue certificates closer to expiration date. In software testing, we often use short-lived certificates, to ensure that our test scenario covers automated certificate renewal as well. It is the responsibility of requestor to initiate the renewal, and distribute the renewed certificates. With Let&amp;#8217;s Encrypt, the renewal process will challenge the requestor again for validation purpose. However, in some cases, the certificate provider may choose not to perform validation on every renewal. For example, short-lived certificate gets renewed every week, while validation is performed every year. During the renewal process, the private key of the website does not change. Note the difference between renewal and rekey. If the website&amp;#8217;s private key is compromised, then instead of renewal, we should re-issue a private key and request a new certificate.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Revocation is a challenging process. To declare that a certificate should no longer be trusted, there are currently two ways: CRL and OCSP but both have drawbacks. CRLs are lists of all the certificates that a CA has issued but revoked. This list can grow very large. It is not feasible for the application (e.g. Browser) to download the giant list for each CA regularly and check for every website that matches the CA. OCSP provides a query-based method. The application can query the revocation status against the OCSP endpoint. It however brings its own challenges. The OCSP server is subject to downtime. The network connectivity between application and OCSP server causes latency. Many applications simply treats query timeout as not revoked. To reduce the load, application may cache OCSP responses, leading to potentially out-dated status. Worse, a malicious CA can track website of the application user.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s encrypt has a page on these challenges, and it proposes a new &lt;a href="https://letsencrypt.org/2022/09/07/new-life-for-crls.html"&gt;browser-summarized CRLs&lt;/a&gt;. It was still a recent effort so we&amp;#8217;ll see how that plays out.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Following the first post on the PKI concepts, we discussed the automation of certificate issuance in this post. In the next one, let&amp;#8217;s go over some labs. &lt;br&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/2024/02/public-key-infrastructure-1-of-3-basics/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Public Key Infrastructure 1 of 3 – Basics&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2024/03/public-key-infrastructure-3-of-3-use-cases/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Public Key Infrastructure 3 of 3 – PKI Implementation&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Public Key Infrastructure 1 of 3 – Basics</title><link>https://static.digihunch.com/2024/02/public-key-infrastructure-1-of-3-basics/</link><pubDate>Tue, 20 Feb 2024 00:05:00 -0400</pubDate><guid>https://static.digihunch.com/2024/02/public-key-infrastructure-1-of-3-basics/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-pki-2.webp" alt="Featured image of post Public Key Infrastructure 1 of 3 – Basics" /&gt;&lt;p class="wp-block-paragraph"&gt;In 2021, I wrote an &lt;a href="https://static.digihunch.com/2021/04/public-key-infrastructure-pki/"&gt;intro to Public Key Infrastructure (PKI)&lt;/a&gt;. Now that I have to host my own certificate authority, I decide to dive a little deeper into PKI in this series of posts. In software testing scenario, we need to issue (and recycle) a lot of certificates, and manage their lifecycle events such as (renewal, revocation). As a result, the corporate should establish its own private key infrastructure (PKI). This effort includes hosing their own Certificate Authority.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Concepts&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;IT professions often use the acronyms PKI and CA interchangeably in the context of implementation. However, strictly speaking, PKI is the entire framework (strategy, policy, etc) around managing certificate at corporate level, and CA is the specific entity that issues certificates. When it comes to architecting PKI, a key design decision is the hierarchy of CAs. Microsoft has a &lt;a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn786436(v=ws.11)#ca-hierarchy-options"&gt;good page&lt;/a&gt; explaining the common options. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In a single-tier CA hierarchy, the root CA is also issuing CA. The root CA as the anchor of trust of the PKI also issues certificates to the end entities. Obviously, this does not scale. It is only for sandbox testing, and not suitable for any environment that needs to scale. It also carries significant risk because the private key at the anchor of trust has to remain online.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With a two-tier CA hierarchy, the root CA only issues certificates to its subordinate CAs. Therefore the root CA can go offline. As a result, the subordinate CAs issue certificates to end entities. Since the root CA can remain offline (except for issuing certificates for new CAs), the chance compromise is reduced significantly. This option also scales better with multiple issuing CAs. If one of them gets compromised, then only the end entities of the compromised CA are impacted. The root CA still needs to be online from time to time. Apart from granting new subordinate CA, the team may also need root CA online to sign CRLs, which is a management overhead.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="511px" viewBox="-0.5 -0.5 511 701" style="max-width:100%;max-height:701px;"&gt;&lt;defs&gt;&lt;style type="text/css"&gt;@import url(https://fonts.googleapis.com/css2?family=Architects+Daughter:wght@400;500);&amp;#xa;&lt;/style&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="0" width="510" height="700" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;rect x="90" y="20" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 111.87 29.03 L 111.87 26.77 L 95.28 26.77 L 95.28 29.03 Z M 90 72.69 L 90 22.94 C 90 21.27 91.51 20 92.92 20 L 114.19 20 C 115.61 20 117.15 21.19 117.15 23.03 L 117.15 50.85 L 110.21 50.85 L 103.57 57.48 L 103.57 57.63 L 95.28 57.63 L 95.28 59.89 L 103.57 59.89 L 103.57 64.41 L 95.28 64.41 L 95.28 66.67 L 103.57 66.67 L 103.57 72.69 Z M 105.84 59.14 L 105.84 58.39 L 111.11 53.12 L 111.87 53.12 L 111.87 59.14 Z M 105.84 72.69 L 105.84 60.64 L 113.38 60.64 L 113.38 53.12 L 131.48 53.12 L 131.48 58.9 C 130.57 58.39 129.26 57.91 127.74 57.94 C 123.97 57.94 120.18 60.95 120.18 65.48 C 120.15 67.92 121.29 69.67 122.35 70.81 L 121.36 72.69 Z M 127.74 70.42 C 130.67 70.42 132.67 68.12 132.67 65.48 C 132.67 62.99 130.64 60.64 127.74 60.64 C 125.01 60.64 122.87 62.92 122.87 65.48 C 122.87 68.59 125.42 70.42 127.74 70.42 Z M 127.74 69.23 C 125.84 69.23 124.09 67.68 124.09 65.48 C 124.09 63.64 125.66 61.85 127.74 61.85 C 130.04 61.85 131.48 63.73 131.48 65.48 C 131.48 67.58 129.86 69.23 127.74 69.23 Z M 127.74 68.47 C 129.44 68.47 130.72 67.16 130.72 65.48 C 130.72 64.13 129.63 62.59 127.74 62.59 C 126.48 62.59 124.84 63.58 124.84 65.48 C 124.84 67.09 126.1 68.47 127.74 68.47 Z M 120.7 77.43 L 124.4 70.51 C 122.83 69.39 121.82 67.67 121.82 65.48 C 121.82 62.09 124.72 59.52 127.74 59.52 C 131.52 59.52 133.89 62.55 133.89 65.48 C 133.9 67.77 132.75 69.27 131.49 70.36 L 136 76.9 L 132.45 76.08 L 130.5 78.79 L 127.74 71.71 L 125.9 79 L 123.85 76.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 86px; margin-left: 113px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Root CA &amp;amp;&lt;br /&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="113" y="98" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Root CA&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="170" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 111.87 179.03 L 111.87 176.77 L 95.28 176.77 L 95.28 179.03 Z M 90 222.69 L 90 172.94 C 90 171.27 91.51 170 92.92 170 L 114.19 170 C 115.61 170 117.15 171.19 117.15 173.03 L 117.15 200.85 L 110.21 200.85 L 103.57 207.48 L 103.57 207.63 L 95.28 207.63 L 95.28 209.89 L 103.57 209.89 L 103.57 214.41 L 95.28 214.41 L 95.28 216.67 L 103.57 216.67 L 103.57 222.69 Z M 105.84 209.14 L 105.84 208.39 L 111.11 203.12 L 111.87 203.12 L 111.87 209.14 Z M 105.84 222.69 L 105.84 210.64 L 113.38 210.64 L 113.38 203.12 L 131.48 203.12 L 131.48 208.9 C 130.57 208.39 129.26 207.91 127.74 207.94 C 123.97 207.94 120.18 210.95 120.18 215.48 C 120.15 217.92 121.29 219.67 122.35 220.81 L 121.36 222.69 Z M 127.74 220.42 C 130.67 220.42 132.67 218.12 132.67 215.48 C 132.67 212.99 130.64 210.64 127.74 210.64 C 125.01 210.64 122.87 212.92 122.87 215.48 C 122.87 218.59 125.42 220.42 127.74 220.42 Z M 127.74 219.23 C 125.84 219.23 124.09 217.68 124.09 215.48 C 124.09 213.64 125.66 211.85 127.74 211.85 C 130.04 211.85 131.48 213.73 131.48 215.48 C 131.48 217.58 129.86 219.23 127.74 219.23 Z M 127.74 218.47 C 129.44 218.47 130.72 217.16 130.72 215.48 C 130.72 214.13 129.63 212.59 127.74 212.59 C 126.48 212.59 124.84 213.58 124.84 215.48 C 124.84 217.09 126.1 218.47 127.74 218.47 Z M 120.7 227.43 L 124.4 220.51 C 122.83 219.39 121.82 217.67 121.82 215.48 C 121.82 212.09 124.72 209.52 127.74 209.52 C 131.52 209.52 133.89 212.55 133.89 215.48 C 133.9 217.77 132.75 219.27 131.49 220.36 L 136 226.9 L 132.45 226.08 L 130.5 228.79 L 127.74 221.71 L 125.9 229 L 123.85 226.89 Z" fill="#505050" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 200px; margin-left: 88px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Root CA&lt;br /&gt;(Offline)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="88" y="203" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end"&gt;Root CA&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="270" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 111.87 279.03 L 111.87 276.77 L 95.28 276.77 L 95.28 279.03 Z M 90 322.69 L 90 272.94 C 90 271.27 91.51 270 92.92 270 L 114.19 270 C 115.61 270 117.15 271.19 117.15 273.03 L 117.15 300.85 L 110.21 300.85 L 103.57 307.48 L 103.57 307.63 L 95.28 307.63 L 95.28 309.89 L 103.57 309.89 L 103.57 314.41 L 95.28 314.41 L 95.28 316.67 L 103.57 316.67 L 103.57 322.69 Z M 105.84 309.14 L 105.84 308.39 L 111.11 303.12 L 111.87 303.12 L 111.87 309.14 Z M 105.84 322.69 L 105.84 310.64 L 113.38 310.64 L 113.38 303.12 L 131.48 303.12 L 131.48 308.9 C 130.57 308.39 129.26 307.91 127.74 307.94 C 123.97 307.94 120.18 310.95 120.18 315.48 C 120.15 317.92 121.29 319.67 122.35 320.81 L 121.36 322.69 Z M 127.74 320.42 C 130.67 320.42 132.67 318.12 132.67 315.48 C 132.67 312.99 130.64 310.64 127.74 310.64 C 125.01 310.64 122.87 312.92 122.87 315.48 C 122.87 318.59 125.42 320.42 127.74 320.42 Z M 127.74 319.23 C 125.84 319.23 124.09 317.68 124.09 315.48 C 124.09 313.64 125.66 311.85 127.74 311.85 C 130.04 311.85 131.48 313.73 131.48 315.48 C 131.48 317.58 129.86 319.23 127.74 319.23 Z M 127.74 318.47 C 129.44 318.47 130.72 317.16 130.72 315.48 C 130.72 314.13 129.63 312.59 127.74 312.59 C 126.48 312.59 124.84 313.58 124.84 315.48 C 124.84 317.09 126.1 318.47 127.74 318.47 Z M 120.7 327.43 L 124.4 320.51 C 122.83 319.39 121.82 317.67 121.82 315.48 C 121.82 312.09 124.72 309.52 127.74 309.52 C 131.52 309.52 133.89 312.55 133.89 315.48 C 133.9 317.77 132.75 319.27 131.49 320.36 L 136 326.9 L 132.45 326.08 L 130.5 328.79 L 127.74 321.71 L 125.9 329 L 123.85 326.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 336px; margin-left: 113px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="113" y="348" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="170" y="270" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 191.87 279.03 L 191.87 276.77 L 175.28 276.77 L 175.28 279.03 Z M 170 322.69 L 170 272.94 C 170 271.27 171.51 270 172.92 270 L 194.19 270 C 195.61 270 197.15 271.19 197.15 273.03 L 197.15 300.85 L 190.21 300.85 L 183.57 307.48 L 183.57 307.63 L 175.28 307.63 L 175.28 309.89 L 183.57 309.89 L 183.57 314.41 L 175.28 314.41 L 175.28 316.67 L 183.57 316.67 L 183.57 322.69 Z M 185.84 309.14 L 185.84 308.39 L 191.11 303.12 L 191.87 303.12 L 191.87 309.14 Z M 185.84 322.69 L 185.84 310.64 L 193.38 310.64 L 193.38 303.12 L 211.48 303.12 L 211.48 308.9 C 210.57 308.39 209.26 307.91 207.74 307.94 C 203.97 307.94 200.18 310.95 200.18 315.48 C 200.15 317.92 201.29 319.67 202.35 320.81 L 201.36 322.69 Z M 207.74 320.42 C 210.67 320.42 212.67 318.12 212.67 315.48 C 212.67 312.99 210.64 310.64 207.74 310.64 C 205.01 310.64 202.87 312.92 202.87 315.48 C 202.87 318.59 205.42 320.42 207.74 320.42 Z M 207.74 319.23 C 205.84 319.23 204.09 317.68 204.09 315.48 C 204.09 313.64 205.66 311.85 207.74 311.85 C 210.04 311.85 211.48 313.73 211.48 315.48 C 211.48 317.58 209.86 319.23 207.74 319.23 Z M 207.74 318.47 C 209.44 318.47 210.72 317.16 210.72 315.48 C 210.72 314.13 209.63 312.59 207.74 312.59 C 206.48 312.59 204.84 313.58 204.84 315.48 C 204.84 317.09 206.1 318.47 207.74 318.47 Z M 200.7 327.43 L 204.4 320.51 C 202.83 319.39 201.82 317.67 201.82 315.48 C 201.82 312.09 204.72 309.52 207.74 309.52 C 211.52 309.52 213.89 312.55 213.89 315.48 C 213.9 317.77 212.75 319.27 211.49 320.36 L 216 326.9 L 212.45 326.08 L 210.5 328.79 L 207.74 321.71 L 205.9 329 L 203.85 326.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 336px; margin-left: 193px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="193" y="348" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="250" y="270" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 271.87 279.03 L 271.87 276.77 L 255.28 276.77 L 255.28 279.03 Z M 250 322.69 L 250 272.94 C 250 271.27 251.51 270 252.92 270 L 274.19 270 C 275.61 270 277.15 271.19 277.15 273.03 L 277.15 300.85 L 270.21 300.85 L 263.57 307.48 L 263.57 307.63 L 255.28 307.63 L 255.28 309.89 L 263.57 309.89 L 263.57 314.41 L 255.28 314.41 L 255.28 316.67 L 263.57 316.67 L 263.57 322.69 Z M 265.84 309.14 L 265.84 308.39 L 271.11 303.12 L 271.87 303.12 L 271.87 309.14 Z M 265.84 322.69 L 265.84 310.64 L 273.38 310.64 L 273.38 303.12 L 291.48 303.12 L 291.48 308.9 C 290.57 308.39 289.26 307.91 287.74 307.94 C 283.97 307.94 280.18 310.95 280.18 315.48 C 280.15 317.92 281.29 319.67 282.35 320.81 L 281.36 322.69 Z M 287.74 320.42 C 290.67 320.42 292.67 318.12 292.67 315.48 C 292.67 312.99 290.64 310.64 287.74 310.64 C 285.01 310.64 282.87 312.92 282.87 315.48 C 282.87 318.59 285.42 320.42 287.74 320.42 Z M 287.74 319.23 C 285.84 319.23 284.09 317.68 284.09 315.48 C 284.09 313.64 285.66 311.85 287.74 311.85 C 290.04 311.85 291.48 313.73 291.48 315.48 C 291.48 317.58 289.86 319.23 287.74 319.23 Z M 287.74 318.47 C 289.44 318.47 290.72 317.16 290.72 315.48 C 290.72 314.13 289.63 312.59 287.74 312.59 C 286.48 312.59 284.84 313.58 284.84 315.48 C 284.84 317.09 286.1 318.47 287.74 318.47 Z M 280.7 327.43 L 284.4 320.51 C 282.83 319.39 281.82 317.67 281.82 315.48 C 281.82 312.09 284.72 309.52 287.74 309.52 C 291.52 309.52 293.89 312.55 293.89 315.48 C 293.9 317.77 292.75 319.27 291.49 320.36 L 296 326.9 L 292.45 326.08 L 290.5 328.79 L 287.74 321.71 L 285.9 329 L 283.85 326.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 336px; margin-left: 273px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="273" y="348" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="410" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 111.87 419.03 L 111.87 416.77 L 95.28 416.77 L 95.28 419.03 Z M 90 462.69 L 90 412.94 C 90 411.27 91.51 410 92.92 410 L 114.19 410 C 115.61 410 117.15 411.19 117.15 413.03 L 117.15 440.85 L 110.21 440.85 L 103.57 447.48 L 103.57 447.63 L 95.28 447.63 L 95.28 449.89 L 103.57 449.89 L 103.57 454.41 L 95.28 454.41 L 95.28 456.67 L 103.57 456.67 L 103.57 462.69 Z M 105.84 449.14 L 105.84 448.39 L 111.11 443.12 L 111.87 443.12 L 111.87 449.14 Z M 105.84 462.69 L 105.84 450.64 L 113.38 450.64 L 113.38 443.12 L 131.48 443.12 L 131.48 448.9 C 130.57 448.39 129.26 447.91 127.74 447.94 C 123.97 447.94 120.18 450.95 120.18 455.48 C 120.15 457.92 121.29 459.67 122.35 460.81 L 121.36 462.69 Z M 127.74 460.42 C 130.67 460.42 132.67 458.12 132.67 455.48 C 132.67 452.99 130.64 450.64 127.74 450.64 C 125.01 450.64 122.87 452.92 122.87 455.48 C 122.87 458.59 125.42 460.42 127.74 460.42 Z M 127.74 459.23 C 125.84 459.23 124.09 457.68 124.09 455.48 C 124.09 453.64 125.66 451.85 127.74 451.85 C 130.04 451.85 131.48 453.73 131.48 455.48 C 131.48 457.58 129.86 459.23 127.74 459.23 Z M 127.74 458.47 C 129.44 458.47 130.72 457.16 130.72 455.48 C 130.72 454.13 129.63 452.59 127.74 452.59 C 126.48 452.59 124.84 453.58 124.84 455.48 C 124.84 457.09 126.1 458.47 127.74 458.47 Z M 120.7 467.43 L 124.4 460.51 C 122.83 459.39 121.82 457.67 121.82 455.48 C 121.82 452.09 124.72 449.52 127.74 449.52 C 131.52 449.52 133.89 452.55 133.89 455.48 C 133.9 457.77 132.75 459.27 131.49 460.36 L 136 466.9 L 132.45 466.08 L 130.5 468.79 L 127.74 461.71 L 125.9 469 L 123.85 466.89 Z" fill="#505050" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 440px; margin-left: 88px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Root CA&lt;br /&gt;(Offline)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="88" y="443" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end"&gt;Root CA&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="610" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 111.87 619.03 L 111.87 616.77 L 95.28 616.77 L 95.28 619.03 Z M 90 662.69 L 90 612.94 C 90 611.27 91.51 610 92.92 610 L 114.19 610 C 115.61 610 117.15 611.19 117.15 613.03 L 117.15 640.85 L 110.21 640.85 L 103.57 647.48 L 103.57 647.63 L 95.28 647.63 L 95.28 649.89 L 103.57 649.89 L 103.57 654.41 L 95.28 654.41 L 95.28 656.67 L 103.57 656.67 L 103.57 662.69 Z M 105.84 649.14 L 105.84 648.39 L 111.11 643.12 L 111.87 643.12 L 111.87 649.14 Z M 105.84 662.69 L 105.84 650.64 L 113.38 650.64 L 113.38 643.12 L 131.48 643.12 L 131.48 648.9 C 130.57 648.39 129.26 647.91 127.74 647.94 C 123.97 647.94 120.18 650.95 120.18 655.48 C 120.15 657.92 121.29 659.67 122.35 660.81 L 121.36 662.69 Z M 127.74 660.42 C 130.67 660.42 132.67 658.12 132.67 655.48 C 132.67 652.99 130.64 650.64 127.74 650.64 C 125.01 650.64 122.87 652.92 122.87 655.48 C 122.87 658.59 125.42 660.42 127.74 660.42 Z M 127.74 659.23 C 125.84 659.23 124.09 657.68 124.09 655.48 C 124.09 653.64 125.66 651.85 127.74 651.85 C 130.04 651.85 131.48 653.73 131.48 655.48 C 131.48 657.58 129.86 659.23 127.74 659.23 Z M 127.74 658.47 C 129.44 658.47 130.72 657.16 130.72 655.48 C 130.72 654.13 129.63 652.59 127.74 652.59 C 126.48 652.59 124.84 653.58 124.84 655.48 C 124.84 657.09 126.1 658.47 127.74 658.47 Z M 120.7 667.43 L 124.4 660.51 C 122.83 659.39 121.82 657.67 121.82 655.48 C 121.82 652.09 124.72 649.52 127.74 649.52 C 131.52 649.52 133.89 652.55 133.89 655.48 C 133.9 657.77 132.75 659.27 131.49 660.36 L 136 666.9 L 132.45 666.08 L 130.5 668.79 L 127.74 661.71 L 125.9 669 L 123.85 666.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 676px; margin-left: 113px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="113" y="688" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="170" y="610" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 191.87 619.03 L 191.87 616.77 L 175.28 616.77 L 175.28 619.03 Z M 170 662.69 L 170 612.94 C 170 611.27 171.51 610 172.92 610 L 194.19 610 C 195.61 610 197.15 611.19 197.15 613.03 L 197.15 640.85 L 190.21 640.85 L 183.57 647.48 L 183.57 647.63 L 175.28 647.63 L 175.28 649.89 L 183.57 649.89 L 183.57 654.41 L 175.28 654.41 L 175.28 656.67 L 183.57 656.67 L 183.57 662.69 Z M 185.84 649.14 L 185.84 648.39 L 191.11 643.12 L 191.87 643.12 L 191.87 649.14 Z M 185.84 662.69 L 185.84 650.64 L 193.38 650.64 L 193.38 643.12 L 211.48 643.12 L 211.48 648.9 C 210.57 648.39 209.26 647.91 207.74 647.94 C 203.97 647.94 200.18 650.95 200.18 655.48 C 200.15 657.92 201.29 659.67 202.35 660.81 L 201.36 662.69 Z M 207.74 660.42 C 210.67 660.42 212.67 658.12 212.67 655.48 C 212.67 652.99 210.64 650.64 207.74 650.64 C 205.01 650.64 202.87 652.92 202.87 655.48 C 202.87 658.59 205.42 660.42 207.74 660.42 Z M 207.74 659.23 C 205.84 659.23 204.09 657.68 204.09 655.48 C 204.09 653.64 205.66 651.85 207.74 651.85 C 210.04 651.85 211.48 653.73 211.48 655.48 C 211.48 657.58 209.86 659.23 207.74 659.23 Z M 207.74 658.47 C 209.44 658.47 210.72 657.16 210.72 655.48 C 210.72 654.13 209.63 652.59 207.74 652.59 C 206.48 652.59 204.84 653.58 204.84 655.48 C 204.84 657.09 206.1 658.47 207.74 658.47 Z M 200.7 667.43 L 204.4 660.51 C 202.83 659.39 201.82 657.67 201.82 655.48 C 201.82 652.09 204.72 649.52 207.74 649.52 C 211.52 649.52 213.89 652.55 213.89 655.48 C 213.9 657.77 212.75 659.27 211.49 660.36 L 216 666.9 L 212.45 666.08 L 210.5 668.79 L 207.74 661.71 L 205.9 669 L 203.85 666.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 676px; margin-left: 193px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="193" y="688" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="296" y="610" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 317.87 619.03 L 317.87 616.77 L 301.28 616.77 L 301.28 619.03 Z M 296 662.69 L 296 612.94 C 296 611.27 297.51 610 298.92 610 L 320.19 610 C 321.61 610 323.15 611.19 323.15 613.03 L 323.15 640.85 L 316.21 640.85 L 309.57 647.48 L 309.57 647.63 L 301.28 647.63 L 301.28 649.89 L 309.57 649.89 L 309.57 654.41 L 301.28 654.41 L 301.28 656.67 L 309.57 656.67 L 309.57 662.69 Z M 311.84 649.14 L 311.84 648.39 L 317.11 643.12 L 317.87 643.12 L 317.87 649.14 Z M 311.84 662.69 L 311.84 650.64 L 319.38 650.64 L 319.38 643.12 L 337.48 643.12 L 337.48 648.9 C 336.57 648.39 335.26 647.91 333.74 647.94 C 329.97 647.94 326.18 650.95 326.18 655.48 C 326.15 657.92 327.29 659.67 328.35 660.81 L 327.36 662.69 Z M 333.74 660.42 C 336.67 660.42 338.67 658.12 338.67 655.48 C 338.67 652.99 336.64 650.64 333.74 650.64 C 331.01 650.64 328.87 652.92 328.87 655.48 C 328.87 658.59 331.42 660.42 333.74 660.42 Z M 333.74 659.23 C 331.84 659.23 330.09 657.68 330.09 655.48 C 330.09 653.64 331.66 651.85 333.74 651.85 C 336.04 651.85 337.48 653.73 337.48 655.48 C 337.48 657.58 335.86 659.23 333.74 659.23 Z M 333.74 658.47 C 335.44 658.47 336.72 657.16 336.72 655.48 C 336.72 654.13 335.63 652.59 333.74 652.59 C 332.48 652.59 330.84 653.58 330.84 655.48 C 330.84 657.09 332.1 658.47 333.74 658.47 Z M 326.7 667.43 L 330.4 660.51 C 328.83 659.39 327.82 657.67 327.82 655.48 C 327.82 652.09 330.72 649.52 333.74 649.52 C 337.52 649.52 339.89 652.55 339.89 655.48 C 339.9 657.77 338.75 659.27 337.49 660.36 L 342 666.9 L 338.45 666.08 L 336.5 668.79 L 333.74 661.71 L 331.9 669 L 329.85 666.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 676px; margin-left: 319px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="319" y="688" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="510" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 111.87 519.03 L 111.87 516.77 L 95.28 516.77 L 95.28 519.03 Z M 90 562.69 L 90 512.94 C 90 511.27 91.51 510 92.92 510 L 114.19 510 C 115.61 510 117.15 511.19 117.15 513.03 L 117.15 540.85 L 110.21 540.85 L 103.57 547.48 L 103.57 547.63 L 95.28 547.63 L 95.28 549.89 L 103.57 549.89 L 103.57 554.41 L 95.28 554.41 L 95.28 556.67 L 103.57 556.67 L 103.57 562.69 Z M 105.84 549.14 L 105.84 548.39 L 111.11 543.12 L 111.87 543.12 L 111.87 549.14 Z M 105.84 562.69 L 105.84 550.64 L 113.38 550.64 L 113.38 543.12 L 131.48 543.12 L 131.48 548.9 C 130.57 548.39 129.26 547.91 127.74 547.94 C 123.97 547.94 120.18 550.95 120.18 555.48 C 120.15 557.92 121.29 559.67 122.35 560.81 L 121.36 562.69 Z M 127.74 560.42 C 130.67 560.42 132.67 558.12 132.67 555.48 C 132.67 552.99 130.64 550.64 127.74 550.64 C 125.01 550.64 122.87 552.92 122.87 555.48 C 122.87 558.59 125.42 560.42 127.74 560.42 Z M 127.74 559.23 C 125.84 559.23 124.09 557.68 124.09 555.48 C 124.09 553.64 125.66 551.85 127.74 551.85 C 130.04 551.85 131.48 553.73 131.48 555.48 C 131.48 557.58 129.86 559.23 127.74 559.23 Z M 127.74 558.47 C 129.44 558.47 130.72 557.16 130.72 555.48 C 130.72 554.13 129.63 552.59 127.74 552.59 C 126.48 552.59 124.84 553.58 124.84 555.48 C 124.84 557.09 126.1 558.47 127.74 558.47 Z M 120.7 567.43 L 124.4 560.51 C 122.83 559.39 121.82 557.67 121.82 555.48 C 121.82 552.09 124.72 549.52 127.74 549.52 C 131.52 549.52 133.89 552.55 133.89 555.48 C 133.9 557.77 132.75 559.27 131.49 560.36 L 136 566.9 L 132.45 566.08 L 130.5 568.79 L 127.74 561.71 L 125.9 569 L 123.85 566.89 Z" fill="#505050" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 540px; margin-left: 88px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Intermediate CA&lt;br /&gt;(Offline)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="88" y="543" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end"&gt;Intermed&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="296" y="510" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 317.87 519.03 L 317.87 516.77 L 301.28 516.77 L 301.28 519.03 Z M 296 562.69 L 296 512.94 C 296 511.27 297.51 510 298.92 510 L 320.19 510 C 321.61 510 323.15 511.19 323.15 513.03 L 323.15 540.85 L 316.21 540.85 L 309.57 547.48 L 309.57 547.63 L 301.28 547.63 L 301.28 549.89 L 309.57 549.89 L 309.57 554.41 L 301.28 554.41 L 301.28 556.67 L 309.57 556.67 L 309.57 562.69 Z M 311.84 549.14 L 311.84 548.39 L 317.11 543.12 L 317.87 543.12 L 317.87 549.14 Z M 311.84 562.69 L 311.84 550.64 L 319.38 550.64 L 319.38 543.12 L 337.48 543.12 L 337.48 548.9 C 336.57 548.39 335.26 547.91 333.74 547.94 C 329.97 547.94 326.18 550.95 326.18 555.48 C 326.15 557.92 327.29 559.67 328.35 560.81 L 327.36 562.69 Z M 333.74 560.42 C 336.67 560.42 338.67 558.12 338.67 555.48 C 338.67 552.99 336.64 550.64 333.74 550.64 C 331.01 550.64 328.87 552.92 328.87 555.48 C 328.87 558.59 331.42 560.42 333.74 560.42 Z M 333.74 559.23 C 331.84 559.23 330.09 557.68 330.09 555.48 C 330.09 553.64 331.66 551.85 333.74 551.85 C 336.04 551.85 337.48 553.73 337.48 555.48 C 337.48 557.58 335.86 559.23 333.74 559.23 Z M 333.74 558.47 C 335.44 558.47 336.72 557.16 336.72 555.48 C 336.72 554.13 335.63 552.59 333.74 552.59 C 332.48 552.59 330.84 553.58 330.84 555.48 C 330.84 557.09 332.1 558.47 333.74 558.47 Z M 326.7 567.43 L 330.4 560.51 C 328.83 559.39 327.82 557.67 327.82 555.48 C 327.82 552.09 330.72 549.52 333.74 549.52 C 337.52 549.52 339.89 552.55 339.89 555.48 C 339.9 557.77 338.75 559.27 337.49 560.36 L 342 566.9 L 338.45 566.08 L 336.5 568.79 L 333.74 561.71 L 331.9 569 L 329.85 566.89 Z" fill="#505050" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 540px; margin-left: 294px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Intermediate CA&lt;br /&gt;(Offline)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="294" y="543" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end"&gt;Intermed&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="366" y="610" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 387.87 619.03 L 387.87 616.77 L 371.28 616.77 L 371.28 619.03 Z M 366 662.69 L 366 612.94 C 366 611.27 367.51 610 368.92 610 L 390.19 610 C 391.61 610 393.15 611.19 393.15 613.03 L 393.15 640.85 L 386.21 640.85 L 379.57 647.48 L 379.57 647.63 L 371.28 647.63 L 371.28 649.89 L 379.57 649.89 L 379.57 654.41 L 371.28 654.41 L 371.28 656.67 L 379.57 656.67 L 379.57 662.69 Z M 381.84 649.14 L 381.84 648.39 L 387.11 643.12 L 387.87 643.12 L 387.87 649.14 Z M 381.84 662.69 L 381.84 650.64 L 389.38 650.64 L 389.38 643.12 L 407.48 643.12 L 407.48 648.9 C 406.57 648.39 405.26 647.91 403.74 647.94 C 399.97 647.94 396.18 650.95 396.18 655.48 C 396.15 657.92 397.29 659.67 398.35 660.81 L 397.36 662.69 Z M 403.74 660.42 C 406.67 660.42 408.67 658.12 408.67 655.48 C 408.67 652.99 406.64 650.64 403.74 650.64 C 401.01 650.64 398.87 652.92 398.87 655.48 C 398.87 658.59 401.42 660.42 403.74 660.42 Z M 403.74 659.23 C 401.84 659.23 400.09 657.68 400.09 655.48 C 400.09 653.64 401.66 651.85 403.74 651.85 C 406.04 651.85 407.48 653.73 407.48 655.48 C 407.48 657.58 405.86 659.23 403.74 659.23 Z M 403.74 658.47 C 405.44 658.47 406.72 657.16 406.72 655.48 C 406.72 654.13 405.63 652.59 403.74 652.59 C 402.48 652.59 400.84 653.58 400.84 655.48 C 400.84 657.09 402.1 658.47 403.74 658.47 Z M 396.7 667.43 L 400.4 660.51 C 398.83 659.39 397.82 657.67 397.82 655.48 C 397.82 652.09 400.72 649.52 403.74 649.52 C 407.52 649.52 409.89 652.55 409.89 655.48 C 409.9 657.77 408.75 659.27 407.49 660.36 L 412 666.9 L 408.45 666.08 L 406.5 668.79 L 403.74 661.71 L 401.9 669 L 399.85 666.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 676px; margin-left: 389px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="389" y="688" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="446" y="610" width="46" height="59" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 467.87 619.03 L 467.87 616.77 L 451.28 616.77 L 451.28 619.03 Z M 446 662.69 L 446 612.94 C 446 611.27 447.51 610 448.92 610 L 470.19 610 C 471.61 610 473.15 611.19 473.15 613.03 L 473.15 640.85 L 466.21 640.85 L 459.57 647.48 L 459.57 647.63 L 451.28 647.63 L 451.28 649.89 L 459.57 649.89 L 459.57 654.41 L 451.28 654.41 L 451.28 656.67 L 459.57 656.67 L 459.57 662.69 Z M 461.84 649.14 L 461.84 648.39 L 467.11 643.12 L 467.87 643.12 L 467.87 649.14 Z M 461.84 662.69 L 461.84 650.64 L 469.38 650.64 L 469.38 643.12 L 487.48 643.12 L 487.48 648.9 C 486.57 648.39 485.26 647.91 483.74 647.94 C 479.97 647.94 476.18 650.95 476.18 655.48 C 476.15 657.92 477.29 659.67 478.35 660.81 L 477.36 662.69 Z M 483.74 660.42 C 486.67 660.42 488.67 658.12 488.67 655.48 C 488.67 652.99 486.64 650.64 483.74 650.64 C 481.01 650.64 478.87 652.92 478.87 655.48 C 478.87 658.59 481.42 660.42 483.74 660.42 Z M 483.74 659.23 C 481.84 659.23 480.09 657.68 480.09 655.48 C 480.09 653.64 481.66 651.85 483.74 651.85 C 486.04 651.85 487.48 653.73 487.48 655.48 C 487.48 657.58 485.86 659.23 483.74 659.23 Z M 483.74 658.47 C 485.44 658.47 486.72 657.16 486.72 655.48 C 486.72 654.13 485.63 652.59 483.74 652.59 C 482.48 652.59 480.84 653.58 480.84 655.48 C 480.84 657.09 482.1 658.47 483.74 658.47 Z M 476.7 667.43 L 480.4 660.51 C 478.83 659.39 477.82 657.67 477.82 655.48 C 477.82 652.09 480.72 649.52 483.74 649.52 C 487.52 649.52 489.89 652.55 489.89 655.48 C 489.9 657.77 488.75 659.27 487.49 660.36 L 492 666.9 L 488.45 666.08 L 486.5 668.79 L 483.74 661.71 L 481.9 669 L 479.85 666.89 Z" fill="#0050ef" stroke="#001dbc" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 676px; margin-left: 469px;"&gt;&lt;div data-drawio-colors="color: #000000; " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"&gt;Issuing CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="469" y="688" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Issuing&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 113 469 L 113 503.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 113 508.88 L 109.5 501.88 L 113 503.63 L 116.5 501.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 136 439.56 L 319 440 L 319 503.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 319 508.88 L 315.5 501.88 L 319 503.63 L 322.5 501.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 113 569 L 113 603.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 113 608.88 L 109.5 601.88 L 113 603.63 L 116.5 601.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 319 569 L 319 603.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 319 608.88 L 315.5 601.88 L 319 603.63 L 322.5 601.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 339.65 569 L 364.7 604.78" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 367.71 609.08 L 360.83 605.36 L 364.7 604.78 L 366.56 601.34 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 342 554.83 L 440.7 620.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 445.07 623.55 L 437.3 622.58 L 440.7 620.63 L 441.19 616.75 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 136 568.25 L 166.02 605.78" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 169.3 609.88 L 162.2 606.6 L 166.02 605.78 L 167.66 602.22 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 113 229 L 113 263.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 113 268.88 L 109.5 261.88 L 113 263.63 L 116.5 261.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 136 228.25 L 166.02 265.78" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 169.3 269.88 L 162.2 266.6 L 166.02 265.78 L 167.66 262.22 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 136 213.88 L 244.6 281.75" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 249.05 284.53 L 241.26 283.79 L 244.6 281.75 L 244.97 277.85 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;rect x="362" y="49" width="130" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 64px; margin-left: 363px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"&gt;Single-Tier&lt;br /&gt;CA Model&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="427" y="69" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px" text-anchor="middle" font-weight="bold"&gt;Single-Tier&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="350" y="229" width="130" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 244px; margin-left: 351px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"&gt;Two-Tier &lt;br /&gt;CA Model&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="415" y="249" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px" text-anchor="middle" font-weight="bold"&gt;Two-Tier&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="360" y="510" width="130" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 525px; margin-left: 361px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;"&gt;Three-Tier &lt;br /&gt;CA Model&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="425" y="530" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px" text-anchor="middle" font-weight="bold"&gt;Three-Tier&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The two-tier hierarchy introduces another problem. The root CA also needs to restrict the certificates that its subordinate CAs can issue. For example, one issuing CA can only issue certificates in the *.dev.digihunch.com domain, and another CA can only issue *.ops.digihunch.com. No subordinate CA shall issue &amp;#8220;rogue&amp;#8221; certificate beyond their authorized scope. In order to enforce issue boundaries on issuing CAs, RFC 5280 defines multiple ways to express constraints, such as basic constraints (including path length), name constraints, policy constraints, and EKU.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In a three-tier CA hierarchy, the top-level is still a root CA that stays offline. One level below, is a layer of CAs that also stay offline and we refer to them as intermediate CAs. Going down one more level down, there are the issuing CAs for end-entity certificates. Oftentimes, we use the intermediate CAs as policy CAs where we introduce restrictions to the subordinates. In this model, the root CA can remain offline nearly all the time because we can issue CRLs at the intermediate level. This is more flexible, but also more management overhead.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Implementation Options&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The two-tier hierarchy is good in most scenarios but the three-tier hierarchy is also common for large organizations. The next consideration is implementation strategy. Take two-tier model for example. We can think about these options:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Implement a self-managed PKI, with an internal root CA. The internal subordinate CAs are the issuing CAs. They are chained to the internal root CA.&lt;/li&gt;&#10;&lt;li&gt;Implement a self-managed PKI, with its certificate purchased from a commercial CA. The internal subordinate CAs are the issuing CAs. They are chained to the external root CA, as the TPP (trusted third party). The external CA may or may not be a public root CA.&lt;/li&gt;&#10;&lt;li&gt;Purchase certificates from a commercial CA that are chained to a public root CA&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Option 3 essentially delegates the PKI to a commercial provider. This is usually not a favourable option due to the hefty charge and minimal control. In option 2, when the third party is a public root CA, you can have all your certificates with public trust, although this is a pricey option too. Even if the third-party isn&amp;#8217;t a public root CA, there is still a benefit of delegating the management of Root CA to commercial provider.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Option 1 is for use cases where we need a lot of certificates quick, for example, in agile development iterations. The certificates do not need trust beyond the organization, and the risk of root CA being compromised is manageable. In this option all CAs are private CAs. Option 2 on the other hand, is flexible in terms of trust boundary. You can just rely on the commercial provider as a TTP. If the TPP supports public root CA, you can issue certificates for public facing workload. In other words, you can choose either a private CA or a public CA. When we work with a private CA, we have to import the certificate to the trust stores of the organization.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="571px" viewBox="-0.5 -0.5 571 231" style="max-width:100%;max-height:231px;"&gt;&lt;defs&gt;&lt;style type="text/css"&gt;@import url(https://fonts.googleapis.com/css2?family=Architects+Daughter:wght@400;500);&amp;#xa;&lt;/style&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="0" width="570" height="230" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;rect x="30" y="30" width="290" height="140" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-end; width: 288px; height: 1px; padding-top: 37px; margin-left: 30px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;CA&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="318" y="49" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end"&gt;CA&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="130" y="40" width="80" height="30" rx="4.5" ry="4.5" fill="#f9f7ed" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 47px; margin-left: 131px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;CAS&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="170" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;CAS&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="135" y="120" width="70" height="40" rx="6" ry="6" fill="#eeeeee" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 127px; margin-left: 136px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;RA&lt;br /&gt;region-2&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="170" y="139" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;RA&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="40" y="120" width="70" height="40" rx="6" ry="6" fill="#eeeeee" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 127px; margin-left: 41px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;RA&lt;br /&gt;region-1&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="75" y="139" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;RA&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="230" y="120" width="75" height="40" rx="6" ry="6" fill="#eeeeee" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 73px; height: 1px; padding-top: 127px; margin-left: 231px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;RA&lt;br /&gt;region-3&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="268" y="139" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;RA&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 150 70 L 75 120" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 190 70 L 267.5 120" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 170 120 L 170 70" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;rect x="370" y="30" width="180" height="80" fill="#cce5ff" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 178px; height: 1px; padding-top: 70px; margin-left: 372px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Certificate Authority Service:&lt;br /&gt;&amp;#8211; Holds the CA keys and certs&lt;br style="border-color: var(--border-color);" /&gt;&amp;#8211; signs CSRs from RAs&lt;br /&gt;&amp;#8211; trusts the RAs implicitly&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="372" y="74" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px"&gt;Certificate Authority Service:&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="370" y="130" width="180" height="80" fill="#cce5ff" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 178px; height: 1px; padding-top: 170px; margin-left: 372px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Registration Authority:&lt;br /&gt;&amp;#8211; Authenticates requests&lt;br style="border-color: var(--border-color);" /&gt;&amp;#8211; Relays CSRs and Certs&lt;br style="border-color: var(--border-color);" /&gt;&amp;#8211; Connect to CAS&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="372" y="174" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px"&gt;Registration Authority:&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="50" y="180" width="50" height="30" fill="#ffff88" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 195px; margin-left: 51px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;local&lt;br /&gt;clients&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="75" y="199" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;local&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="145" y="180" width="50" height="30" fill="#ffff88" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 195px; margin-left: 146px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;local&lt;br /&gt;clients&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="170" y="199" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;local&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="242.5" y="180" width="50" height="30" fill="#ffff88" stroke="#36393d" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 195px; margin-left: 244px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;local&lt;br /&gt;clients&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="268" y="199" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;local&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 170 180 L 170 160" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 75 180 L 75 160" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;path d="M 267.5 180 L 267.5 160" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Some PKI topologies splits a CA into two sub-components: the Certificate Authority Service (CAS, or simply CA) and the Registration Authority (RA), as the diagram above shows. With many locations, each location has an RA that communicates with a with a central CAS. The RAs receive requests from local clients and are responsible for authenticating these requests and pass the validated ones along to the CAS. The validation can take place in ACME protocol. The CAS implicitly trusts RAs and will sign the validated requests from RAs before sending them via API calls. The RA then relays the certificates back to the local requestors. This topology is more scalable with the CAS focusing only on signing and the RAs on validation and passing the requests along. Large organizations may have their central CAS hosted on-prem, and remote RAs in the CSP regions.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Components for X.509 Certificate&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;X.509 is the standard for digital certificate. The X.509 standard has the following most important fields:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Subject: The name of the subject (e.g. a user, service, device), commonly represented as X.500 formate distinguished name (DN). For website, the value can be CN=digihunch.com&lt;/li&gt;&#10;&lt;li&gt;Serial Number: A unique identifier for each certificate that a CA issues.&lt;/li&gt;&#10;&lt;li&gt;Issuer: DN of the CA. For a self-signed root CA, the issuer is the subject. They are different otherwise, such as in subordinate CA certificates and end entity certificates.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These fields were introduced in version 1. In addition, X.509 version 3 certificates introduces extensions that provide additional functionality and features to the certificate. Each extension comes in two flavours: critical and non-critical. A certificate-using system MUST reject the certificate if it encounters a critical extension it does not recognize or a critical extension that contains information that it cannot process. A non-critical extension MAY be ignored if it is not recognized, but MUST be processed if it is recognized.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="851px" viewBox="-0.5 -0.5 851 411" style="max-width:100%;max-height:411px;"&gt;&lt;defs&gt;&lt;style type="text/css"&gt;@import url(https://fonts.googleapis.com/css2?family=Architects+Daughter:wght@400;500);&amp;#xa;&lt;/style&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="0" width="850" height="410" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/&gt;&lt;path d="M 90 40 L 90 10 L 550 10 L 550 40" fill="#cce5ff" stroke="#36393d" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;path d="M 90 40 L 90 400 L 550 400 L 550 40" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 40 L 550 40" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 70 L 550 70" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 100 L 550 100" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 130 L 550 130" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 160 L 550 160" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 190 L 550 190" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 220 L 550 220" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 250 L 550 250" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 280 L 550 280" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 310 L 550 310" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 340 L 550 340" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 90 370 L 550 370" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="16px"&gt;&lt;text x="319.5" y="31.5"&gt;X.509 Certificate&lt;/text&gt;&lt;/g&gt;&lt;rect x="90" y="40" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 40 M 550 40 M 550 70 M 90 70" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 55px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Version&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="60" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Version&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="70" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 70 M 550 70 M 550 100 M 90 100" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 85px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Certificate Serial Number&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="90" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Certificate Serial Number&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="100" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 100 M 550 100 M 550 130 M 90 130" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 115px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Certificate Algorithm Identifier for Certificate Issuer&amp;#8217;s Signature&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="120" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Certificate Algorithm Identifier for Certificate Issuer&amp;#8217;s&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="130" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 130 M 550 130 M 550 160 M 90 160" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 145px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Issuer&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="150" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Issuer&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="160" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 160 M 550 160 M 550 190 M 90 190" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 175px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Validity Period&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="180" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Validity Period&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="190" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 190 M 550 190 M 550 220 M 90 220" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 205px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Subject&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="210" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Subject&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="220" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 220 M 550 220 M 550 250 M 90 250" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 235px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Subject Public-Key Information (Algorithm Identifier and Value)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="240" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Subject Public-Key Information (Algorithm Identifier and&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="250" width="460" height="30" fill="#eeeeee" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 250 M 550 250 M 550 280 M 90 280" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 265px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Issuer Unique Identifier&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="270" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Issuer Unique Identifier&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="280" width="460" height="30" fill="#eeeeee" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 280 M 550 280 M 550 310 M 90 310" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 295px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Subject Unique Identifier&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="300" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Subject Unique Identifier&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="310" width="460" height="30" fill="#eeeeee" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 310 M 550 310 M 550 340 M 90 340" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 325px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Extensions&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="330" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Extensions&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="340" width="460" height="30" fill="#f9f7ed" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 340 M 550 340 M 550 370 M 90 370" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 355px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Certificate Authority&amp;#8217;s Digital Signature&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="360" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Certificate Authority&amp;#8217;s Digital Signature&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="90" y="370" width="460" height="30" fill="#eeeeee" stroke="none" pointer-events="all"/&gt;&lt;path d="M 90 370 M 550 370 M 550 400 M 90 400" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 458px; height: 1px; padding-top: 385px; margin-left: 92px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Extension Fields &amp;#8230;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="92" y="390" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Extension Fields &amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 80 250 L 75 250 Q 70 250 70 260 L 70 285 Q 70 295 65 295 L 62.5 295 Q 60 295 65 295 L 67.5 295 Q 70 295 70 305 L 70 330 Q 70 340 75 340 L 80 340" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;rect x="0" y="280" width="60" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 295px; margin-left: 1px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 15px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Optional&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="30" y="300" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="15px" text-anchor="middle"&gt;Optional&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 70 385 L 90 385" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/&gt;&lt;rect x="0" y="370" width="60" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 385px; margin-left: 1px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 15px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Optional&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="30" y="390" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="15px" text-anchor="middle"&gt;Optional&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="100" width="250" height="300" fill="#eeeeee" stroke="none" pointer-events="none"/&gt;&lt;path d="M 590 100 L 840 100 L 840 400 L 590 400 L 590 100" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 130 L 840 130" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 160 L 840 160" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 190 L 840 190" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 220 L 840 220" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 250 L 840 250" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 280 L 840 280" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 310 L 840 310" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 340 L 840 340" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;path d="M 590 370 L 840 370" fill="none" stroke="#36393d" stroke-miterlimit="10" pointer-events="none"/&gt;&lt;rect x="590" y="100" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 100 M 840 100 M 840 130 M 590 130" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 115px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Subject Alternative Name (SAN)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="120" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Subject Alternative Name (SAN)&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="130" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 130 M 840 130 M 840 160 M 590 160" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 145px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Key Usage&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="150" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Key Usage&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="160" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 160 M 840 160 M 840 190 M 590 190" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 175px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Basic Constraints&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="180" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Basic Constraints&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="190" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 190 M 840 190 M 840 220 M 590 220" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 205px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Name Constraints&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="210" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Name Constraints&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="220" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 220 M 840 220 M 840 250 M 590 250" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 235px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;CRL distribution Points (CDP)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="240" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;CRL distribution Points (CDP)&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="250" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 250 M 840 250 M 840 280 M 590 280" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 265px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Authority Information Access (AIA)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="270" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Authority Information Access (A&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="280" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 280 M 840 280 M 840 310 M 590 310" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 295px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Subject Key Identification (SKI)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="300" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Subject Key Identification (SKI)&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="310" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 310 M 840 310 M 840 340 M 590 340" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 325px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Authority Key Identification (AKI)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="330" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Authority Key Identification (A&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="340" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 340 M 840 340 M 840 370 M 590 370" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 355px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Extended Key Usage (EKU)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="360" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Extended Key Usage (EKU)&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="370" width="250" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;path d="M 590 370 M 840 370 M 840 400 M 590 400" fill="none" stroke="#36393d" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 248px; height: 1px; padding-top: 385px; margin-left: 592px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Certificate Policies&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="592" y="390" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px"&gt;Certificate Policies&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="590" y="70" width="160" height="30" fill="none" stroke="none" pointer-events="all"/&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 85px; margin-left: 591px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Common Extensions&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="670" y="90" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="16px" text-anchor="middle"&gt;Common Extensions&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 550 385 L 590 100.99" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/&gt;&lt;path d="M 550 385 L 589 397.99" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here are some common extensions that a lot of implementations use:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Subject Alternative Name (SAN): only used in end entity certificates, not in CA certificates. The format of SAN is flexible and it does not have to be X.500 DN. For website certificate, we often place alternative DNS names here.&lt;/li&gt;&#10;&lt;li&gt;Key Usage: The intended scope of usage for a private key is specified through the Key Usage and Extended Key Usage (EKU) extensions in the associated certificate. Example: &amp;#8220;Certificate Sign, CRL Sign&amp;#8221;&lt;/li&gt;&#10;&lt;li&gt;Basic Constraints: Used to distinguish between end-entity cert and CA cert. You should also specify path length. The value can be: &amp;#8220;CA:TRUE, pathlen:1&amp;#8221;. If the path length constraint is 0, the CA may have one more level of subordinate CA. But these subordinate CAs must have path length of 0 on their own certs, and cannot extend one more level as their own subordinates. Those subordinate CAs can only issue end-entity certificates. If the path length value is none, then there is no restriction on the levels of subordinate CAs.&lt;/li&gt;&#10;&lt;li&gt;Name Constraints: for CA certs only, defined in RFC5280, to limit the scope to certain names on the certificate that the CA issues. Client must verify that a certificate is allowed to be signed by CA.&lt;/li&gt;&#10;&lt;li&gt;CDP (CRL distribution points): URL(s) where the application or service can retrieve the certificate revocation list (CRL).&lt;/li&gt;&#10;&lt;li&gt;AIA (Authority Information Access): URL(s) where the application or service can retrieve the revocation list for CA&amp;#8217;s certificate&lt;/li&gt;&#10;&lt;li&gt;SKI (Subject Key Identifier): the SHA-1 hash of the subject&amp;#8217;s public key&lt;/li&gt;&#10;&lt;li&gt;AKI (Authority Key Identifier): the SHA-1 hash of the issuer&amp;#8217;s public key&lt;/li&gt;&#10;&lt;li&gt;EKU (Extended Key Usage, also Enhanced Key Usage): an object identifier (OID) for each application or service a certificate can be used for. It needs to align with Key Usage&lt;/li&gt;&#10;&lt;li&gt;Certificate Policy: reference to the certification practice statement (CPS) of the issuer. During exchange, any relying party can access the assurance level associated with the certificate, and decide on the level of trust to put in the certificate.&lt;/li&gt;&#10;&lt;li&gt;Policy Constraints: for path validation, it can be used to prohibit policy mapping or to require that each certificate in a path contain an acceptable policy identifier.&lt;/li&gt;&#10;&lt;li&gt;Policy Mappings: in CA certificates to restrict the certificates that the CA can issue.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This isn&amp;#8217;t a complete list. Plus, X.509 V3 also supports custom extensions. &lt;a href="https://en.wikipedia.org/wiki/X.509#Sample_X.509_certificates"&gt;Here&lt;/a&gt; is a sample certificate. In real life, the way each implementation uses these extensions may vary slightly, so interoperability issues between PKIs exist. When designing your own PKI, it is important to examine the usage of extensions to comply with the standard. For example, Microsoft has the following &lt;a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn786428(v=ws.11)#constraining-ca-certificates"&gt;recommendations&lt;/a&gt; to restrict certificates: &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;For subordinate CA certificates, the Basic Constraints extension should be present and marked as critical&lt;/li&gt;&#10;&lt;li&gt;The cA field should be set to TRUE&lt;/li&gt;&#10;&lt;li&gt;The pathLenConstraint field should be set to the minimum value required to enable the business scenario (i.e. 0 if that CA will issue certificates only to End Entities)&lt;/li&gt;&#10;&lt;li&gt;The EKU extension should be present and contain the minimum set of EKU object identifiers (OIDs) to enable the business scenario. Furthermore, the anyExtendedKeyUsage OID (2.5.29.37.0) should not be specified.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This post discussed the basic concepts in public key infrastructure. In the next post, I&amp;#8217;ll cover the automation of certificate issuance.&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/2024/01/workload-identity-on-kubernetes-2-of-2-eks-and-rosa-on-aws/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Workload Identity on Kubernetes 2 of 2 – EKS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2024/03/public-key-infrastructure-2-of-3-certificate-automation/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Public Key Infrastructure 2 of 3 – Certificate Automation&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Authentication to kube-apiserver via OIDC</title><link>https://static.digihunch.com/2023/07/authenticate-kube-apiserver-via-oidc/</link><pubDate>Fri, 28 Jul 2023 09:20:00 -0400</pubDate><guid>https://static.digihunch.com/2023/07/authenticate-kube-apiserver-via-oidc/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-kubectl-oidc.webp" alt="Featured image of post Authentication to kube-apiserver via OIDC" /&gt;&lt;h2 class="wp-block-heading"&gt;Background&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are many benefits of using OIDC to authenticate to kube-api server, especially with multiple clusters that need consistent log-in experience. With the &lt;a href="https://static.digihunch.com/2023/07/oauth-2-0-and-oidc-2-of-2/"&gt;last post&lt;/a&gt; on how OIDC Authorization Code Flow works, now I will discuss options with authentication for kubectl to connect to kube API server.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To start, let&amp;#8217;s look at the anatomy of kubeconfig file. The full schema is in the &lt;a href="https://kubernetes.io/docs/reference/config-api/kubeconfig.v1/"&gt;documentation&lt;/a&gt;. Looking at my kubeconfig file, there are three sections:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;clusters: each entry specifies a cluster&amp;#8217;s name, server address and certificate authority data (in base64 encoding or a file location). &lt;/li&gt;&#10;&lt;li&gt;users: each entry specifies a username. Some users are identified with client key and certificate. Some specify a command to provide client authentication. Refer to the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/"&gt;authentication strategies&lt;/a&gt;.&lt;/li&gt;&#10;&lt;li&gt;contexts: each entry links a user to a cluster&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Therefore, the key to use OIDC integration, is to use command to provide client authentication. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-vanilla-kubernetes"&gt;Vanilla Kubernetes&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The documentation on authenticating has a diagram on how to use &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens"&gt;OpenID Connect tokens&lt;/a&gt;. The diagram does not give details on how access_token and id_token were obtained. So it could be any OIDC flow (Authorization Code Flow, Implicit Flow, etc) as we have &lt;a href="https://static.digihunch.com/2023/07/oauth-2-0-and-oidc-2-of-2/"&gt;discussed&lt;/a&gt;.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full is-resized"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="828" src="https://static.digihunch.com/wp-content/uploads/2023/07/oidc-flow.webp" alt="" class="wp-image-12940" style="width:651px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/oidc-flow.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/07/oidc-flow-300x243.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/oidc-flow-768x621.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although the instruction does not mandate which OIDC flow to use, we should use Authorization Code Flow in this architecture. The API server needs to trust the OIDC issuer, and the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuring-the-api-server"&gt;document&lt;/a&gt; covers how to configure API server.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the diagram, step 2 and step 3 are required by kubectl itself does not perform these activities. All kubectl does is carry the JWT token in the Authorization Bearer. Vanilla Kubernetes does not provide a solution for OIDC integration. It only provides some instructions and we still need some helper scripts to glue all these instruction steps together.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are many open-source project for this purpose. For example, Jetstack has &lt;a href="https://github.com/jetstack/kube-oidc-proxy"&gt;kube-oidc-proxy&lt;/a&gt; and Int128 developed &lt;a href="https://github.com/int128/kubelogin"&gt;kubelogin&lt;/a&gt;. Other projects such as &lt;a href="https://github.com/vimond/k8s-auth-client"&gt;k8s-auth-client&lt;/a&gt;, &lt;a href="https://github.com/micahhausler/k8s-oidc-helper"&gt;k8s-oidc-helper&lt;/a&gt;, and &lt;a href="https://github.com/vmware-archive/gangway"&gt;gangway&lt;/a&gt; are no longer being updated. The kubelogin project remains influential. It has a clear diagram too:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="503" src="https://static.digihunch.com/wp-content/uploads/2023/07/kube-oidc-proxy.webp" alt="" class="wp-image-12941" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/kube-oidc-proxy.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/07/kube-oidc-proxy-300x147.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/kube-oidc-proxy-768x377.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;From the diagram we can see kubelogin proposes authorization code flow. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Also, one design concern with Kubernetes control plane is the placement of endpoint. From this diagram we can see that even if the cluster endpoint is on private subnet, OIDC integration should still work. The control plane (specifically kube-apiserver) initiates outbound connection to OIDC Provider. There is no inbound connection to it from the OIDC provider.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the kubelogin setup, the redirect URI is set to localhost:8080 because it stands up a server on the same host where browser is running. The browser can always resolve localhost. For a full configuration steps, Okta has &lt;a href="https://developer.okta.com/blog/2021/11/08/k8s-api-server-oidc"&gt;this blog post&lt;/a&gt; on how to use kubelogin as helper, and Okta as Authorization Server to authenticate kubectl via OIDC. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Step-by-step with kubelogin&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We&amp;#8217;ll go through an example with int128/kubelogin because it works with any Kubernetes flavour, including managed Kubernetes services. It is also fairly simple. The instruction covers a few types of Authorization Servers (Google Identity Platform, KeyCloak, Dex with GitHub, Okta and Ping Identity). I&amp;#8217;ll take KinD cluster as an example and use Azure AD as Authorization Server.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;First, we&amp;#8217;ll register an App in Azure Portal. Go to &amp;#8220;App Registrations&amp;#8221; and &amp;#8220;New registration&amp;#8221;. Give it a name &amp;#8220;kubeoidc&amp;#8221; and set Redirect URI to &amp;#8220;Web&amp;#8221; with URL &amp;#8220;localhost:8000&amp;#8221;. Click on Register.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="399" src="https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-1.webp" alt="" class="wp-image-12942" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-1.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-1-300x117.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-1-768x299.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The next page shows the details for this app. The Application (client) ID is important for next steps. Click on &amp;#8220;Add a certificate or secret&amp;#8221;, then &amp;#8220;New client secret&amp;#8221;, put in expiry and description. The secret value is generated and displayed on the next page, which is important for our next step. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="204" src="https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-2.webp" alt="" class="wp-image-12943" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-2.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-2-300x60.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/kubeoidc-entra-2-768x153.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We also need to find out the issuer URL. From the App page above, click on &amp;#8220;Endpoints&amp;#8221; and find out the URL from field &amp;#8220;OpenID Connect metadata document&amp;#8221;. My metadata document URL looks like: &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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://login.microsoftonline.com/xx8x8xx8-7777-66yy-55b5-444aaaaa3322/v2.0/.well-known/openid-configuration&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The OIDC Issuer URL is the part before .well-known. In this case, it is:&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;https://login.microsoftonline.com/xx8x8xx8-7777-66yy-55b5-444aaaaa3322/v2.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we have collected what we need for the next few steps: ClientID, ClientSecret and OIDC Issuer URL. We can then create the KinD cluster, and reference ClientID and IssuerURL in the cluster configuration:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat &lt;span style="color:#e6db74"&gt;&amp;lt;&amp;lt; EOF &amp;gt; kind-config.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;kind: Cluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;apiVersion: kind.x-k8s.io/v1alpha4&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;nodes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; - role: control-plane&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; kubeadmConfigPatches:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; - |&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; kind: ClusterConfiguration&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; apiServer:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; extraArgs:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; oidc-issuer-url: https://login.microsoftonline.com/xx8x8xx8-7777-66yy-55b5-444aaaaa3322/v2.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; oidc-client-id: 99999e88-e777-6666-c5c5-c444444d3d22&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; - role: worker&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; - role: worker&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; - role: worker&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;EOF&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;kind create cluster --config&lt;span style="color:#f92672"&gt;=&lt;/span&gt;kind-config.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The command will create cluster and configure kubeconfig file with a user named kind-kind as admin, which isn&amp;#8217;t what we need. Now we use kubelogin helper command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl oidc-login setup &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --oidc-issuer-url&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ISSUER_URL &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --oidc-client-id&lt;span style="color:#f92672"&gt;=&lt;/span&gt;YOUR_CLIENT_ID &lt;span style="color:#ae81ff"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --oidc-client-secret&lt;span style="color:#f92672"&gt;=&lt;/span&gt;YOUR_CLIENT_SECRET&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This command will act as the client in the OIDC flow and prompts you to log in to Azure in a Browser. Once logged on, it gives you the next few commands to run. Since we&amp;#8217;ve already created a cluster with the Issuer URL and Client ID, we can skip creating cluster, and run the steps to:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;bind the Azure user to a ClusterRole&lt;/li&gt;&#10;&lt;li&gt;set up the kubeconfig locally with a user oidc, which needs to execute the oidc-login command&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Lastly, we can test the oidc user with &lt;code&gt;kubectl --user=oidc get nodes&lt;/code&gt;. We can also set the context to use oidc user by default. Voila.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;From this example, we learned how to configure OIDC integration for any Kubernetes distros. The steps that we need to take are:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;On the cluster side, we customize kube-api-server flag with OIDC provider info. Specifically, we provided Issuer URL and client ID in this example. In the OIDC Flow diagram, this step establish a trust from the Resource Server (K8s cluster) to the OIDC provider. &lt;/li&gt;&#10;&lt;li&gt;On the kubectl side, kubectl itself cannot fulfill all the duties of a client app in the OIDC Flow. It needs a helper script and we&amp;#8217;ve made friend with int128/kubelogin.&lt;/li&gt;&#10;&lt;li&gt;On the Identity Store side, we expect it to be an OIDC-compliant Authorization Server. Otherwise, we consider using Dex as a broker in between. &lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When it comes to managed service, many allows us to customize the OIDC related flags for kube-api-server. Let&amp;#8217;s look at how some managed services get this to work.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-azure-kubernetes-service"&gt;Azure Kubernetes Service&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I find the kubectl authentication with AKS highly opinionated in its documentation. The recommendation is using Azure Active Directory as identity store but I don&amp;#8217;t find it work with other OIDC providers.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To work with Azure Active Directory, you would configure the cluster and specify Azure role-based access control with the Group UUID in Azure AD. On the client side, you will need to install &lt;a href="https://github.com/Azure/kubelogin"&gt;Azure&amp;#8217;s kubelogin&lt;/a&gt; utility. Do not confuse it with int128&amp;#8217;s kubelogin, which is for any cluster. This &lt;a href="https://blog.baeke.info/2021/06/03/a-quick-look-at-azure-kubelogin/"&gt;kubelogin&lt;/a&gt; is just for Azure. Once installed, you can use az-cli command to update your kubeconfig file, which call this utility from kubeconfig. To examine details about &lt;a href="https://github.com/digihunch/cloudkube/blob/4735426f5c3e8f3b448bdb4f4b8ef33d340f71eb/azure/modules/bastion/files/bastion_init_sh.tpl#L27"&gt;client configuration&lt;/a&gt; and &lt;a href="https://github.com/digihunch/cloudkube/blob/4735426f5c3e8f3b448bdb4f4b8ef33d340f71eb/azure/modules/aks/main.tf#L43"&gt;AAD integration&lt;/a&gt;, check out the Terraform template in the &lt;a href="https://github.com/digihunch/cloudkube/tree/main/azure"&gt;azure&lt;/a&gt; directory of my &lt;a href="https://github.com/digihunch/cloudkube"&gt;cloudkube&lt;/a&gt; project.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full is-resized"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="620" src="https://static.digihunch.com/wp-content/uploads/2023/07/aks-kubeconfig.webp" alt="" class="wp-image-12944" style="width:782px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/aks-kubeconfig.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/07/aks-kubeconfig-300x182.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/aks-kubeconfig-768x465.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The document only covers &lt;a href="https://learn.microsoft.com/en-us/azure/aks/concepts-identity#azure-ad-integration"&gt;Azure AD integration&lt;/a&gt; and I tried to find if there&amp;#8217;s a way to integrate with third-party OIDC providers. Unfortunately I have no luck. ChatGPT points me to &lt;a href="https://learn.microsoft.com/en-gb/azure/aks/use-oidc-issuer"&gt;a page about enabling OIDC provider&lt;/a&gt; but it is in the context of workload identity and it does not allow you to customize the issuer. So it&amp;#8217;s completely irrelevant. Because you cannot customize OIDC issuer, etc, it simply won&amp;#8217;t work with any third-party OIDC provider. Sure enough, most of Azure&amp;#8217;s client use Azure AD anyways.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure makes it streamlined to configure OIDC integration of AKS with Azure AD, its own identity store. To my disappointment, it is currently not possible to integrate with third-party OIDC provider for authentication at cluster endpoint. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-rosa"&gt;ROSA&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RedHat OpenShift on AWS (ROSA) is a. However it reflects how OpenShift configures third-party identity provider. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s first create a cluster off custom VPC and private endpoint. This is covered in my previous &lt;a href="https://static.digihunch.com/2023/06/kubernetes-paas-and-red-hat-openshift/"&gt;post&lt;/a&gt; about ROSA. After the cluster creation, we&amp;#8217;re at the point where we can run &lt;code&gt;oc&lt;/code&gt; command against cluster endpoint from Bastion host because it is a private cluster. However, being a private cluster is irrelevant to how we configure OIDC integration. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We&amp;#8217;ll use Azure AD again as OIDC provider. So we need to register an app the same way as I did above in the kubelogin example. We need to have Client ID, Secret and OIDC issuer URL. For RedirectURI, go to your &lt;a href="https://console.redhat.com/openshift/"&gt;OpenShift console&lt;/a&gt;, and under &lt;code&gt;Cluster&lt;/code&gt;, click on the cluster name → access control → identity providers → select OpenID. Note the page clearly states that this is Authorization Code Flow, and the OAuth Callback URL is provided. Use it to regiter App in Azure, and fill in the page with Client ID, Secret and OIDC issuer URL. Also fill in other fields accordingly and click on Add. Now you should have it configured!&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="288" src="https://static.digihunch.com/wp-content/uploads/2023/07/rosa-idp.webp" alt="" class="wp-image-12946" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/rosa-idp.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/07/rosa-idp-300x84.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/rosa-idp-768x216.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Identity Providers for OpenShift cluster&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The next step is trying to login. From Bastion host, run &lt;code&gt;oc login&lt;/code&gt; and it will give me an URL to use. The URL contains the cluster endpoint, which resolvable from the Bastion Host itself. However I need a Browser session here, so I have to run Bastion host as SOCKS5 proxy and tell Chrome on my MacBook to use it:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~ open /Applications/Google&lt;span style="color:#ae81ff"&gt;\ &lt;/span&gt;Chrome.app --args --proxy-server&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;socks5://localhost:1080&amp;#34;&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;The browser session redirects to Azure AD for log in. Once completed the webpage will display a token that I can use with &lt;code&gt;oc login&lt;/code&gt; command. Run this command with token from Bastion, I&amp;#8217;m logged in:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oc login --token&lt;span style="color:#f92672"&gt;=&lt;/span&gt;sha256~3ZT5JGWELOcBzfohftEm9D2UwoOVFvATASuZk3_uxps --server&lt;span style="color:#f92672"&gt;=&lt;/span&gt;https://api.dhc.62q3.p1.openshiftapps.com:6443&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oc whoami&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;oc get no&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;At this point, if I run &lt;code&gt;oc whoami&lt;/code&gt;, I get the user name. However, this user cannot do anything. This is because it is not associated with a role yet. You grant more permission to this user: go back to OpenShift console, Clusters → ClusterName → Access Control → Cluster Roles and Access → Add user. Here you can map the user name to a role (let&amp;#8217;s say ClusterAdmin). Then this user will have its priviledge:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="346" src="https://static.digihunch.com/wp-content/uploads/2023/07/oc-command.webp" alt="" class="wp-image-12947" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/oc-command.webp 1024w, https://static.digihunch.com/wp-content/uploads/2023/07/oc-command-300x101.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/oc-command-768x260.webp 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The whole Flow works with private cluster, because the redirect URI is resolvable from the Bastion host. If you chose to expose cluster endpoint publicly (not recommended), you can perform the above steps directly from your MacBook or Laptop. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;So the ROSA experience has been smooth. Unlike kubectl, the &lt;code&gt;oc&lt;/code&gt; utility can act as the Client App in Authorization Code Flow. The other part of the configuration such as client secret and issuer URL are made in OpenShift console. Good job!&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-elastic-kuberentes-service"&gt;Elastic Kuberentes Service&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;EKS allows you to specify &lt;a href="https://aws.amazon.com/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks/"&gt;OIDC issuers&lt;/a&gt; from console or CLI to set up third-party OIDC configuration. There is a blog &lt;a href="https://developer.okta.com/blog/2021/10/08/secure-access-to-aws-eks#add-okta-as-an-oidc-provider-on-your-eks-cluster"&gt;post&lt;/a&gt; from Okta on this, which works for private clusters. In the instruction, the author first manually created kubeconfig file with int128 kubelogin, and then bind ClusterRole with the user.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full is-resized"&gt;&lt;img loading="lazy" decoding="async" width="1021" height="1024" src="https://static.digihunch.com/wp-content/uploads/2023/07/eks-idp.webp" alt="" class="wp-image-12948" style="width:556px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2023/07/eks-idp.webp 1021w, https://static.digihunch.com/wp-content/uploads/2023/07/eks-idp-300x300.webp 300w, https://static.digihunch.com/wp-content/uploads/2023/07/eks-idp-150x150.webp 150w, https://static.digihunch.com/wp-content/uploads/2023/07/eks-idp-768x770.webp 768w, https://static.digihunch.com/wp-content/uploads/2023/07/eks-idp-410x410.webp 410w" sizes="auto, (max-width: 1021px) 100vw, 1021px" /&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The blog post is very detailed. Instead of repeating it, I would like to discuss two SSO models available in AWS. I summarize them as below:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="721px" viewBox="-0.5 -0.5 721 671" style="max-width:100%;max-height:671px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="0" width="720" height="670" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;rect x="30" y="375" width="220" height="235" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 382px; margin-left: 31px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;EKS Cluster&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="140" y="394" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;EKS Cluster&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="60" y="480" width="110" height="40" rx="6" ry="6" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 500px; margin-left: 61px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;RoleBinding&lt;br&gt;ClusterRoleBinding&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="115" y="504" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;RoleBinding&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="440" cy="430" rx="60" ry="25" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 430px; margin-left: 381px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;OIDC compatible&lt;br&gt;Identity Provider&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="440" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;OIDC compatible&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="30" y="40" width="230" height="220" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 228px; height: 1px; padding-top: 47px; margin-left: 31px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;EKS Cluster&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="145" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;EKS Cluster&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="620" cy="95" rx="50" ry="25" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 95px; margin-left: 571px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;SAML compliant&lt;br&gt;Identity Provider&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="620" y="99" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;SAML compliant&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="280" y="65" width="100" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 95px; margin-left: 281px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;IAM Role via&lt;br&gt;PermissionSet&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="330" y="99" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;IAM Role via&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="410" y="65" width="100" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 95px; margin-left: 411px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;AWS IAM&lt;br&gt;Identity Center&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="460" y="99" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;AWS IAM&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 380 95 L 410 95" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 250 95 L 280 95" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 570 95 L 510 95" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 96px; margin-left: 541px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;SAML&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="541" y="99" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;SAML&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="180" y="75" width="70" height="40" rx="6" ry="6" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 95px; margin-left: 181px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;ConfigMap&lt;br&gt;aws-auth&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="215" y="99" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;ConfigMap&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="80" y="75" width="70" height="40" rx="6" ry="6" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 95px; margin-left: 81px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;group&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="115" y="99" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;group&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="80" y="410" width="70" height="40" rx="6" ry="6" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 430px; margin-left: 81px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;group&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="115" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;group&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="30" y="260" width="270" height="30" fill="none" stroke="none" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 268px; height: 1px; padding-top: 275px; margin-left: 31px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;EKS SSO Model 1 &amp;#8211; IAM Identity Center&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="165" y="279" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;EKS SSO Model 1 &amp;#8211; IAM Identity Center&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="50" y="610" width="180" height="30" fill="none" stroke="none" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 625px; margin-left: 51px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;EKS SSO Model 2 &amp;#8211; direct OIDC&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="140" y="629" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;EKS SSO Model 2 &amp;#8211; direct OIDC&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 150 430 L 380 430" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 431px; margin-left: 311px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"&gt;OIDC&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="311" y="434" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;OIDC&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="60" y="140" width="110" height="40" rx="6" ry="6" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 160px; margin-left: 61px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;RoleBinding&lt;br&gt;ClusterRoleBinding&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="115" y="164" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;RoleBinding&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 150 95 L 180 95" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;rect x="80" y="210" width="70" height="40" rx="6" ry="6" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 230px; margin-left: 81px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Role&lt;br&gt;ClusterRole&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="115" y="234" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Role&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 115 180 L 115 210" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 115 115 L 115 140" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;rect x="60" y="555" width="110" height="40" rx="6" ry="6" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 575px; margin-left: 61px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Role&lt;br&gt;ClusterRole&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="115" y="579" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Role&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 115 450 L 115 480" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 115 520 L 115 555" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 270 330 L 370 330 L 370 380 L 340 380 L 320 410 L 320 380 L 270 380 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 355px; margin-left: 271px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;OIDC claim:&lt;br&gt;user=john&lt;br&gt;group=admin&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="320" y="359" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;OIDC claim:&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="280" y="160" width="100" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 190px; margin-left: 281px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;AssumeRole&lt;br&gt;WithWebIdentity&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="330" y="194" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;AssumeRole&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="480" cy="190" rx="60" ry="20" fill="#ffe6cc" stroke="#d79b00" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 190px; margin-left: 421px;"&gt;&lt;div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"&gt;Pipeline&lt;br&gt;User&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="480" y="194" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Pipeline&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 380 190 L 420 190" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 250 115 L 280 190" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Text is not SVG &amp;#8211; cannot display&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both are SSO models for EKS. Model 1 (IAM Identity Center) is home grown as AWS using IAM Identity Center (formerly AWS SSO). Users start with an IAM principal (AWS construct) and use the &lt;code&gt;aws-auth&lt;/code&gt; config map to tie them to Kubernetes groups. This AWS &lt;a href="https://aws.amazon.com/blogs/containers/a-quick-path-to-amazon-eks-single-sign-on-using-aws-sso/"&gt;blog post &lt;/a&gt;and this &lt;a href="https://repost.aws/knowledge-center/eks-configure-sso-user"&gt;support article&lt;/a&gt; are based on the IAM Identity Center model. On the other hand, Model 2 (Direct OIDC) is the vanilla Kubernetes approach. It takes group claim from OIDC identity token. The Okta blog &lt;a href="https://developer.okta.com/blog/2021/10/08/secure-access-to-aws-eks#add-okta-as-an-oidc-provider-on-your-eks-cluster"&gt;post&lt;/a&gt; is based on this model.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The IAM identity center model works with SAML compliant identity providers, oftentimes Active Directory, although there seems to be a plan to &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html"&gt;support OIDC-compliant identity provider&lt;/a&gt; as well in the future. Even if it was supported today, I&amp;#8217;d still prefer model 2 for working with any OIDC compliant identity provider because it&amp;#8217;s simple. Why not leverage K8s&amp;#8217; native capability? For identity providers that do not support OIDC natively, or does not issue group claim (e.g. &lt;a href="https://aws.amazon.com/blogs/containers/authenticate-to-amazon-eks-using-google-workspace/"&gt;Google workspace&lt;/a&gt;), as we &lt;a href="https://static.digihunch.com/2023/07/oauth-2-0-and-oidc-2-of-2/"&gt;discussed&lt;/a&gt;, we can also consider alternatives such as Dex as identity broker. However, this model comes handy when a pipeline user with IAM role needs to authenticate into EKS.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;One should always go for the direct OIDC model, if the upstream identity provider supports OIDC. The provider itself can even be AWS Cognito User pool. Cognito User Pool itself supports federated identity but again, I would directly connect EKS cluster to the OIDC compatible identity provider, instead of going through Cognito User Pool. As a result, the only use case where Cognito user pool is absolutely necessary, is when we need the Cognito user pool itself as the identity provider, as we have in &lt;a href="https://github.com/digihunch/cloudkube"&gt;CloudKube&lt;/a&gt;&amp;#8216;s &lt;a href="https://github.com/digihunch/cloudkube"&gt;eks&lt;/a&gt; directory. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-summary"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Configuring OIDC provider for cluster endpoint can be confusing and we need to understand how OIDC flows work. I dived into OIDC in the previous post and in this post, I explained how to get it to work with vanilla Kubernetes. I summarized the three requirements and looked at the OIDC provider option with some managed services. Then I went through OIDC options for AKS, ROSA and EKS.&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/2023/07/oauth-2-0-and-oidc-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;OAuth 2.0 and OIDC 2 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2023/08/control-tower-aws-landing-zone/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Orchestrate Landing Zone with AWS Control Tower&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Etcd – the key-value store for Kubernetes</title><link>https://static.digihunch.com/2022/06/etcd-the-key-value-store-for-kubernetes/</link><pubDate>Tue, 14 Jun 2022 00:10:00 -0400</pubDate><guid>https://static.digihunch.com/2022/06/etcd-the-key-value-store-for-kubernetes/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-etcd.webp" alt="Featured image of post Etcd – the key-value store for Kubernetes" /&gt;&lt;h2 class="wp-block-heading"&gt;Etcd in Kubernetes&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In Kubernetes &lt;a href="https://static.digihunch.com/2021/04/preparing-certified-kubernetes-administrator-exam/"&gt;architecture&lt;/a&gt;, &lt;a href="https://etcd.io/"&gt;etcd&lt;/a&gt; is the data store. It stores the desired state of Kubernetes object. API server is the only client that connects to etcd (via &lt;a href="https://grpc.io/"&gt;gRPC&lt;/a&gt; protocol). Cluster builder specifies the endpoint of etcd as a parameter to the kube-api-server process. Other Kubernetes components, whether in the control plane or from the nodes, connect to API server. API server translates their request into etcd query, and then translates etcd query result into what its clients ask for. For this reason, communication with etcd accounts for a lot of network traffic in a Kubernetes cluster.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The etcd store is a CNCF project for &amp;#8220;a distributed, reliable key-value store for critical data in a distributed system&amp;#8221;, developed by CoreOS team. So it is essentially a distributed key-value store for any distributed application. If an application runs on Kubernetes, it can leverage etcd store, by keeping their configurations in ConfigMap and Secret objects. One key feature is to watch for specific keys or directories for changes, and react to the changes. Voila! This is the underlying mechanism for &lt;a href="https://kubernetes.io/docs/concepts/architecture/controller/"&gt;controller&lt;/a&gt;!&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A Kubernetes cluster may have stacked etcd deployment or connect to an external etcd store.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="848" height="560" src="https://static.digihunch.com/wp-content/uploads/2022/05/stacked.png" alt="" class="wp-image-5250"/&gt;&lt;figcaption class="wp-element-caption"&gt;stacked etcd architecture&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="856" height="601" src="https://static.digihunch.com/wp-content/uploads/2022/05/external.png" alt="" class="wp-image-5251"/&gt;&lt;figcaption class="wp-element-caption"&gt;external etcd architecture&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In managed Kubernetes services such as EKS in AWS and AKS in Azure, users usually do not directly access etcd store. However, it is still a very important component to understand. Its use case includes:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Configuration sharing&lt;/li&gt;&#10;&lt;li&gt;Service discovery&lt;/li&gt;&#10;&lt;li&gt;Consistency&lt;/li&gt;&#10;&lt;li&gt;Watching mechanism&lt;/li&gt;&#10;&lt;li&gt;Expiry and extension of key &lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The consistency use case is based on Raft protocol for distributed consensus.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Raft protocol&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I am not an expert in distributed consensus protocols and nor do I intent to cover it in depth. At a high level, I have heard of three of them so far:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Etcd uses Raft protocol&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2020/08/zookeeper/"&gt;Zookeeper&lt;/a&gt; uses ZAB protocol&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2018/03/cassandra-architecture-summary/"&gt;Cassandra&lt;/a&gt; uses paxos protocol&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.alibabacloud.com/blog/a-brief-analysis-of-consensus-protocol-from-logical-clock-to-raft_594675"&gt;Here&lt;/a&gt; is a good intro to the three protocols. Instead of getting into the fine details, I would like to discuss why we need such a consensus protocol (or consensus mechanism) in distributed systems, which are also decentralized systems.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="686" src="https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-1024x686.webp" alt="" class="wp-image-13111" srcset="https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-1024x686.webp 1024w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-300x201.webp 300w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-768x514.webp 768w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-410x275.webp 410w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology.webp 1138w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;figcaption class="wp-element-caption"&gt;Centralized, Decentralized, Distributed systems&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The reason a distributed system needs consensus protocol, is that a distributed system lacks a single source of truth as centralized systems do. Different parts of the distributed system may receive different signals but they must come to agreement of a single plan to act. Lamport studies this with an analogy of &lt;a href="https://en.wikipedia.org/wiki/Byzantine_fault"&gt;Byzantine Generals&lt;/a&gt; problem, and first proposed Paxos protocol. &lt;a href="https://en.wikipedia.org/wiki/Paxos_(computer_science)"&gt;Paxos&lt;/a&gt; has been an important foundation to modern distributed systems. In Paxos, consensus is achieved in &lt;a href="https://martinfowler.com/articles/patterns-of-distributed-systems/paxos.html"&gt;two phases&lt;/a&gt;, which creates the problem of livelocks. Raft is an alternative to Paxos, and is widely adopted today. &lt;a href="http://thesecretlivesofdata.com/raft/"&gt;Here&lt;/a&gt; is a link to an animated illustration for Raft protocol. The Raft protocol is also used in Redis. It has three roles: Leader, Candidate, and follower. ZAB protocol is similar to Raft, where it needs to select a leader.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Etcd Lab&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In troubleshooting, if we suspect that the response from API server is inconsistent with etcd store, we want to directly connect to it.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Managed Kubernetes services do not expose their etcd store. We can use KinD or Minikube. There are two types of jump box to access etcd store: using etcd Pod, or SSH to a Node. To connect to etcd, we also need the X509 key, certificate and CA&amp;#8217;s certificate, in addition to the endpoint, usually an IP with port 2389. When I connect to Pod shell, I find the command shell not easy to use. They might miss basic command such as ls, or do not support auto completion.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Take KinD for example, we first create a secret, then we can connect to the node with docker CLI command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl create ns myns&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n myns create secret generic mysecret --from-literal key1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;value1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n myns get secret mysecret -o jsonpath&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;{.data.key1}&amp;#39;&lt;/span&gt; | base64 -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker exec -it control /bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From the node, &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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt update &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install etcd-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nc -vz localhost &lt;span style="color:#ae81ff"&gt;2379&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd&#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;export ETCDCTL_API&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_CERT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/etc/kubernetes/pki/apiserver-etcd-client.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_KEY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/etc/kubernetes/pki/apiserver-etcd-client.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_CACERT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_ENDPOINTS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;https://127.0.0.1:2379&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl member list write out&lt;span style="color:#f92672"&gt;=&lt;/span&gt;table&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we can see the secret object directly with etcd store:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get /registry/secrets/myns/mysecret&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;With get query, when using &amp;#8211;prefix, we can use &amp;#8211;keys-only switch to list keys without values:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get --prefix /registry/api --keys-only&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get --prefix /registry/namespace -wjson&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can write key-value with put command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl put myloc &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get myloc -wjson&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In Kubernetes, all the key names start with / which makes the key looks like a POSIX path. Every Kubernetes object is stored in etcd with a unique key following a self-explanatory naming pattern. To display the path, we can also use debug log that records the call to API server:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get ns myns -v9&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Look for curl command such as:&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;I0523 22:51:43.517728 32347 round_trippers.go:466] curl -v -XGET -H &amp;#34;Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json&amp;#34; -H &amp;#34;User-Agent: kubectl/v1.23.6 (darwin/amd64) kubernetes/ad33385&amp;#34; &amp;#39;https://127.0.0.1:64081/api/v1/namespaces/myns&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From there we can see the etcd query as the URI is namespaces/myns, which we use in etcdctl query path:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get /registry/namespaces/myns&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Every type of Kubernetes object has a storage.go file in their implementation that defines how api server should write object. &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/pkg/registry/core/pod/storage/storage.go"&gt;Here&lt;/a&gt; is an example for Pod object.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Etcd also supports watch command to watch for changes. For example:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl watch --prefix /registry/namespace &lt;span style="color:#75715e"&gt;# watch output k create ns newns&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;Now we create a namespace with kubectl:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl create ns myns&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The output from etcdctl will reflect the change. The communication between etcdctl and etcd is gRPC protocol. The output is based on stream, as we can see from the watch result.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-etcd-maintenance"&gt;Etcd Maintenance&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Like any distributed store, etcd needs &lt;a href="https://etcd.io/docs/v3.5/op-guide/maintenance/"&gt;maintenance&lt;/a&gt; and operation work. For example, we can check endpoint status with endpoint command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl endpoint status&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can also backup and restore etcd store with etcdctl command:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl snapshot save /tmp/backup.db&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This was an question in &lt;a href="https://static.digihunch.com/2021/04/preparing-certified-kubernetes-administrator-exam/"&gt;CKA exam&lt;/a&gt;. In real life, when the workload scales up, the etcd store may come across many pitfalls, such as degraded performance, unresponsiveness, some etcd member going down, network partition on etcd store causing split brain. It is important to ensure efficient communication between API server and etcd store. The etcdctl provides defrag and compact commands for common maintenance activities.&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/2022/05/hosting-database-on-kubernetes/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Hosting database on Kubernetes&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/06/chaos-mesh-cloud-native-chaos-engineering/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Chaos Mesh – Cloud Native Chaos Engineering&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Service Proxy – from Nginx to Envoy</title><link>https://static.digihunch.com/2022/03/from-nginx-to-envoy-proxy/</link><pubDate>Wed, 09 Mar 2022 21:36:00 -0400</pubDate><guid>https://static.digihunch.com/2022/03/from-nginx-to-envoy-proxy/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-nginx2envoy.webp" alt="Featured image of post Service Proxy – from Nginx to Envoy" /&gt;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Update&lt;/strong&gt; (Nov 20, 2022): 1. Envoy&amp;#8217;s configuration schema can be hard to get used to. It is lacking examples because the documentation is mostly generated. Use its &lt;a href="https://github.com/envoyproxy/examples"&gt;examples&lt;/a&gt; directory to find real-life configuration examples. 2. the Envoy implementation in the example project has been reverted in favour of Nginx.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Envoy proxy is the underlying technology for Istio, as well as a number of other service mesh products, such as AppMesh (AWS), Consul (Hashicorp) and OpenServiceMesh (Azure). Most of the capabilities of Isito is ultimately provided by Envoy proxy. Envoy has a &lt;a href="https://www.envoyproxy.io/docs/envoy/v1.10.0/intro/comparison"&gt;page&lt;/a&gt; outlining its differences with similar technologies. I decided to take a look into Envoy by replacing Nginx with it.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-rate-limiting-and-circuit-breaker"&gt;Rate limiting and Circuit Breaker&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In most SDLC, it is application developers that create backend APIs or server applications. Most developers specializes in application features, and cannot fathom all the nuances with the TCP/IP network stack. Nginx allows them to push network concerns (non-business features) to a dedicated proxy to handle the dynamics in network connection. Nginx can be configured as both a reverse proxy (handling incoming connection on behalf of the process) and a forward proxy (handling outgoing connection on behalf of the process). This is the prototype of sidecar pattern, an important idea behind service mesh. For example, when a sudden increase in connection to the server-side application, the server process could be either unresponsive (refer to &amp;#8220;the &lt;a href="https://queue.acm.org/detail.cfm?id=1854041"&gt;queuing knee&lt;/a&gt;&amp;#8220;, and &lt;a href="https://en.wikipedia.org/wiki/Little%27s_law"&gt;Little&amp;#8217;s Law&lt;/a&gt;), or OOM killed. When such interruptions are not automatically recovered, a downtime is caused. This traditionally requires some congestion control strategy for TCP/IP queue but two features provided by a network proxy can help circumvent this situation: rate limiting, and circuit breaking. Rate limiting keeps more requests above threshold from entering the queue. Circuit breaker releases downstream pressure by cutting out existing in-queue request. Nginx added both over the years but &lt;a href="https://www.nginx.com/blog/microservices-reference-architecture-nginx-circuit-breaker-pattern/"&gt;Circuit breaker&lt;/a&gt; still remains a premium feature exclusive to Nginx Plus. Envoy on the other hand has them free when it was launched.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Envoy also supports other advanced traffic management such as traffic shaping, and mirroring. It is on top of those features that Istio introduces its own abstraction such as virtual service, destination rules to its users. In that sense, we can think of Istio as a configurator (control plane) for Envoy proxy (data plane), similar to Ansible to Nginx proxy instances.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-dynamic-configuration-via-api"&gt;Dynamic Configuration via API&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I used Nginx previously with traditional environment and loved its flexibility. As the system grows, I started to feel the pain of management overhead. With one of the production system, there were 25 + instances of Nginx each running on a VM and I managed configuration files with Ansible. Ansible pushes out configuration files and triggers a reload from each Nginx instance. In the cloud-native era where Pods are ephemeral, this kind of overhead would snowball to an unmanageable level. Envoy was designed for cloud-native applications, with all these kinds of problems in mind. Envoy has dynamic configuration. The majority of the configurations can be pulled from &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/operations/dynamic_configuration"&gt;xDS API&lt;/a&gt;, or file system. Updating configuration drains connections gracefully without runtime having to reload the file. The idea of centrally managing Nginx instances with Ansible, also evolved into the concept of control plane.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-tls-origination"&gt;TLS origination&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the Orthweb project, I used Nginx to proxy TLS and HTTP traffic, and performed TLS termination on both ports. This is know as TLS offloading. The traffic between the proxy and the upstream service takes place in the clear, even though they do not travel across different network interfaces in most cases. For a true end-to-end encryption, it is helpful to also encrypt the traffic between proxy and upstream server. This requires the capability of securing TCP traffic to upstream server. With Nginx, the ability to &lt;a href="https://dzone.com/articles/nginx-rate-limiting"&gt;secure HTTP traffic to upstream&lt;/a&gt; server is offered in open-source. The ability to &lt;a href="https://docs.nginx.com/nginx/admin-guide/security-controls/securing-tcp-traffic-upstream/"&gt;secure TCP traffic&lt;/a&gt; is available in Nginx Plus, or with self-compiled binary. In Envoy, both are available using the UpstreamTlsContext configuration.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-more-pros"&gt;More pros&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In another &lt;a href="https://static.digihunch.com/2020/01/nginx-as-a-reverse-proxy-for-nifi/"&gt;post&lt;/a&gt;, I also discussed Nginx as a LDAP proxy to front services such as Kibana and Nifi. It requires a proxy service (ldap-auth in this case), to defer auth to third party. Envoy has this capability using a &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_authz_filter"&gt;filter&lt;/a&gt; with extension for external authorization. Istio also exposes this capability, an enabler for the configuration proposed in my previous &lt;a href="https://static.digihunch.com/2022/02/istio-external-authorization/"&gt;post&lt;/a&gt;. Envoy also uses WebAssembly for its extensibility.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another useful feature is protocol detection. It can use filters to detect protocol (TLS or regular TCP) and route traffic to predefined destination.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Performance wise, this &lt;a href="https://www.loggly.com/blog/benchmarking-5-popular-load-balancers-nginx-haproxy-envoy-traefik-and-alb/"&gt;benchmark&lt;/a&gt; from 2018 ran a comparison among the popular options where Envoy leads by a margin.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Observability (logging, metrics and tracing) are well supported in Envoy. User can configure format of logs that takes effect immediately. There are many metrics that works with Prometheus and they are expandable using filters. On the tracing side, Envoy supports integration with jaeger, zipkin and datadog.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-basics-of-envoy"&gt;Basics of Envoy&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The configuration of Envoy is more involving. There is an Envoy course by &lt;a href="https://academy.tetrate.io/"&gt;Tetrate&lt;/a&gt;, as well as two blog entries for envoy 101: Envoy as &lt;a href="https://www.tetrate.io/blog/envoy-101-configuring-envoy-as-a-gateway/"&gt;gateway proxy&lt;/a&gt; and File-based &lt;a href="https://www.tetrate.io/blog/envoy-101-file-based-dynamic-configurations/"&gt;dynamic configuration&lt;/a&gt;. Another good way to get started is the Sandboxes &lt;a href="https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/#start-sandboxes"&gt;projects&lt;/a&gt;, which covers a number of different areas of configuration. The admin port (by default at port 9901. Istio&amp;#8217;s default is 15000) provides helpful information. If we need to turn on debug on some features, we can do so with curl:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -X POST http://localhost:9901/logging?client&lt;span style="color:#f92672"&gt;=&lt;/span&gt;debug&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Stats are exposed at the same port:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -X GET http://localhost:9901/stats&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;When packets are received at a listener, the is first processed by listener filters. Then, depending on filter match, one or more network filter chains will further process the packet, including further actions, as illustrated below:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="726" src="https://static.digihunch.com/wp-content/uploads/2024/07/envoy-listener-filters-1024x726.png" alt="" class="wp-image-11357" srcset="https://static.digihunch.com/wp-content/uploads/2024/07/envoy-listener-filters-1024x726.png 1024w, https://static.digihunch.com/wp-content/uploads/2024/07/envoy-listener-filters-300x213.png 300w, https://static.digihunch.com/wp-content/uploads/2024/07/envoy-listener-filters-768x544.png 768w, https://static.digihunch.com/wp-content/uploads/2024/07/envoy-listener-filters-1536x1089.png 1536w, https://static.digihunch.com/wp-content/uploads/2024/07/envoy-listener-filters.png 1920w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Envoy supports dynamic configuration, which uses a set of discovery services (xDS) APIs. Some of the important xDS APIs include:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;LDS (Listener Discovery Service) &amp;#8211; allows you to add listeners dynamically while Envoy is running&lt;/li&gt;&#10;&lt;li&gt;RDS (Route Discovery Service) &amp;#8211; allows you to dynamically update routes for HTTP connection managers&lt;/li&gt;&#10;&lt;li&gt;CDS (Cluster Discovery Service) &amp;#8211; allows you to update cluster definitions dynamically&lt;/li&gt;&#10;&lt;li&gt;EDS (Endpoint Discovery Service) &amp;#8211; allows you to add or remove endpoints dynamically&lt;/li&gt;&#10;&lt;li&gt;Secret DS&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The relation can be illustrated in this diagram below:&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://i0.wp.com/www.tetrate.io/wp-content/uploads/2020/11/Screen-Shot-2020-11-18-at-12.17.08-PM-1.png?resize=1044%2C638&amp;amp;ssl=1" alt="Envoy - xDS configuration API overview"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This &lt;a href="https://www.tetrate.io/blog/envoy-101-file-based-dynamic-configurations/"&gt;post&lt;/a&gt; from Tetrate has more examples.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-nginx-to-envoy"&gt;Nginx to Envoy &lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For the advantages of Envoy, I decided to migrate from Nginx to Envoy on my &lt;a href="https://github.com/digihunch/orthweb"&gt;Orthweb&lt;/a&gt; project. Using Envoy as service proxy is not where Envoy is mostly used (as sidecar), but it is how Envoy was originally used at Lyft to replace ELB in 2015.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The original Nginx configuration was referenced in this &lt;a href="https://static.digihunch.com/2020/11/medical-imaging-web-server-deployment-pipeline/"&gt;old blog post&lt;/a&gt;. The Envoy setup also covers both TCP (&lt;a href="https://static.digihunch.com/2020/11/how-imaging-devices-talk-to-each-other-tip-in-dicom/"&gt;DICOM&lt;/a&gt;) and HTTP (HTTPS) traffic. For HTTP traffic, it also encrypts the traffic to upstream. Below is what it looks like:&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-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;admin&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;socket_address&lt;/span&gt;: { &lt;span style="color:#f92672"&gt;address&lt;/span&gt;: &lt;span style="color:#f92672"&gt;0.0.0.0, port_value&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;9901&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;static_resources&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;listeners&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https_listener&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;socket_address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.0.0.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;port_value&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;filter_chains&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;filters&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;envoy.filters.network.http_connection_manager&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;typed_config&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;@type&amp;#34;: &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;codec_type&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;AUTO&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stat_prefix&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ingress_http&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;route_config&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;local_route&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;virtual_hosts&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;app&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;domains&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;routes&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;match&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;prefix&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;route&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cluster&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;service-https&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;http_filters&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;envoy.filters.http.router&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;transport_socket&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;envoy.transport_sockets.tls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;typed_config&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;@type&amp;#34;: &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;common_tls_context&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls_certificates&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;certificate_chain&lt;/span&gt;: {&lt;span style="color:#f92672"&gt;&amp;#34;filename&amp;#34;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/etc/ssl/certs/site.pem&amp;#34;&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;private_key&lt;/span&gt;: {&lt;span style="color:#f92672"&gt;&amp;#34;filename&amp;#34;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/etc/ssl/certs/site.pem&amp;#34;&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;dicomtls_listener&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;socket_address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0.0.0.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;port_value&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;11112&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;filter_chains&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;filters&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;envoy.filters.network.tcp_proxy&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;typed_config&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;@type&amp;#34;: &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;stat_prefix&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;downstream_cx_total&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cluster&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;service-dicomtls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;transport_socket&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;envoy.transport_sockets.tls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;typed_config&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;@type&amp;#34;: &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;common_tls_context&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;tls_certificates&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;certificate_chain&lt;/span&gt;: {&lt;span style="color:#f92672"&gt;&amp;#34;filename&amp;#34;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/etc/ssl/certs/site.pem&amp;#34;&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;private_key&lt;/span&gt;: {&lt;span style="color:#f92672"&gt;&amp;#34;filename&amp;#34;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/etc/ssl/certs/site.pem&amp;#34;&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;validation_context&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;allow_expired_certificate&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;trusted_ca&lt;/span&gt;: {&lt;span style="color:#f92672"&gt;&amp;#34;filename&amp;#34;: &lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;/etc/ssl/certs/site.pem&amp;#34;&lt;/span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;require_client_certificate&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;clusters&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;service-https&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;type&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;STRICT_DNS&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;lb_policy&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ROUND_ROBIN&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;load_assignment&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cluster_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;service-https&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;endpoints&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;lb_endpoints&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;endpoint&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;socket_address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthanc-backend&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;port_value&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;8042&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;transport_socket&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;envoy.transport_sockets.tls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;typed_config&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;@type&amp;#34;: &lt;/span&gt;&lt;span style="color:#ae81ff"&gt;type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;service-dicomtls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;type&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;STRICT_DNS&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;lb_policy&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ROUND_ROBIN&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;load_assignment&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;cluster_name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;service-dicomtls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;endpoints&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;lb_endpoints&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;endpoint&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;socket_address&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;address&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;orthanc-backend&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;port_value&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;4242&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;layered_runtime&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;layers&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;static_layer_0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;static_layer&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;envoy&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;resource_limits&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;listener&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;https_listener&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;connection_limit&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;overload&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;global_downstream_max_connections&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5000&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;From Nginx to Envoy, to achieve nearly the same functionalities, it takes 100 lines of configuration instead of less than 30. The configuration also appears more abstract, which is one of the cons of Envoy to consider before the migration.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Update from Jan 2025 &amp;#8211; To align with what most uses in Orthanc community, the project switched back to using Nginx. The envoy configuration is kept &lt;a href="https://gist.github.com/digihunch/e3192481f0a54e018442d9629562d40f"&gt;here&lt;/a&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/2022/02/istio-external-authorization/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Istio External Authorization via OIDC&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/03/istio-operation-gotchas/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Istio Operation Gotchas&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Service and Ingress -Traffic Management in Kubernetes</title><link>https://static.digihunch.com/2021/07/traffic-management-in-kubernetes-service-and-ingress/</link><pubDate>Sun, 04 Jul 2021 01:30:00 -0400</pubDate><guid>https://static.digihunch.com/2021/07/traffic-management-in-kubernetes-service-and-ingress/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-ingress-service.webp" alt="Featured image of post Service and Ingress -Traffic Management in Kubernetes" /&gt;&lt;p class="wp-block-paragraph"&gt;Update 2022-08 &amp;#8211; Read my latest article on &lt;a href="https://medium.com/slalom-build/managing-ingress-traffic-on-kubernetes-platforms-ebd537cdfb46"&gt;ingress traffic management&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this post we discuss the traffic management in Kubernetes, specifically on Service and Ingress objects. Let&amp;#8217;s start with a traditional architecture:&lt;/p&gt;&#10;&lt;p class="has-white-background-color has-background wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="463px" viewBox="-0.5 -0.5 463 251" style="max-width:100%;max-height:251px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="70" width="460" height="30" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 458px; height: 1px; padding-top: 85px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Network Load Balancer&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="89" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Network Load Balancer&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="230" cy="20" rx="60" ry="20" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 20px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Client&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="24" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Client&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 230 63.63 L 230 46.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 230 68.88 L 226.5 61.88 L 230 63.63 L 233.5 61.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 230 41.12 L 233.5 48.12 L 230 46.37 L 226.5 48.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="321.43" y="110" width="140" height="140" fill="#f5f5f5" stroke="#666666" pointer-events="none"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 247px; margin-left: 322px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;VM&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="391" y="247" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VM&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="330" y="130" width="122.86" height="30" rx="4.5" ry="4.5" fill="#d5e8d4" stroke="#82b366" pointer-events="none"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 121px; height: 1px; padding-top: 145px; margin-left: 331px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;nginX&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="391" y="149" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;nginX&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="355" cy="205" rx="25" ry="25" fill="#ffffff" stroke="#000000" pointer-events="none"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 205px; margin-left: 331px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;App1&lt;br&gt;Service&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="355" y="209" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;App1&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="427.86" cy="205" rx="25" ry="25" fill="#ffffff" stroke="#000000" pointer-events="none"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 205px; margin-left: 404px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;App2&lt;br&gt;Service&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="428" y="209" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;App2&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 360.71 160 L 356.75 173.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 355.31 178.92 L 353.87 171.23 L 356.75 173.88 L 360.6 173.16 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 422.14 160 L 426.11 173.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 427.56 178.93 L 422.27 173.16 L 426.11 173.88 L 429 171.23 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;rect x="160" y="110" width="140" height="140" fill="#f5f5f5" stroke="#666666" pointer-events="none"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 247px; margin-left: 161px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;VM&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="230" y="247" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VM&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 231 100 L 231.34 123.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 231.41 128.88 L 227.81 121.93 L 231.34 123.63 L 234.81 121.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;rect x="170" y="130" width="122.86" height="30" rx="4.5" ry="4.5" fill="#d5e8d4" stroke="#82b366" pointer-events="none"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 121px; height: 1px; padding-top: 145px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;nginX&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="231" y="149" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;nginX&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="195" cy="205" rx="25" ry="25" fill="#ffffff" stroke="#000000" pointer-events="none"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 205px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;App1&lt;br&gt;Service&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="195" y="209" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;App1&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="267.86" cy="205" rx="25" ry="25" fill="#ffffff" stroke="#000000" pointer-events="none"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 205px; margin-left: 244px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;App2&lt;br&gt;Service&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="268" y="209" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;App2&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 200.71 160 L 196.75 173.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 195.31 178.92 L 193.87 171.23 L 196.75 173.88 L 200.6 173.16 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 262.14 160 L 266.11 173.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 267.56 178.93 L 262.27 173.16 L 266.11 173.88 L 269 171.23 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;rect x="0" y="110" width="140" height="140" fill="#f5f5f5" stroke="#666666" pointer-events="none"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 138px; height: 1px; padding-top: 247px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;VM&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="70" y="247" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VM&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="10" y="130" width="122.86" height="30" rx="4.5" ry="4.5" fill="#d5e8d4" stroke="#82b366" pointer-events="none"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 121px; height: 1px; padding-top: 145px; margin-left: 11px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;nginX&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="71" y="149" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;nginX&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="35" cy="205" rx="25" ry="25" fill="#ffffff" stroke="#000000" pointer-events="none"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 205px; margin-left: 11px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;App1&lt;br&gt;Service&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="35" y="209" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;App1&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="107.86" cy="205" rx="25" ry="25" fill="#ffffff" stroke="#000000" pointer-events="none"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 205px; margin-left: 84px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: none; white-space: normal; word-wrap: normal; "&gt;App2&lt;br&gt;Service&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="108" y="209" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;App2&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 40.72 160 L 36.75 173.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 35.31 178.92 L 33.87 171.23 L 36.75 173.88 L 40.6 173.16 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 102.14 160 L 106.11 173.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 107.56 178.93 L 102.27 173.16 L 106.11 173.88 L 109 171.23 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 71 100 L 71.34 123.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 71.41 128.88 L 67.81 121.93 L 71.34 123.63 L 74.81 121.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 391 100 L 391.34 123.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;path d="M 391.41 128.88 L 387.81 121.93 L 391.34 123.63 L 394.81 121.83 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"&gt;&lt;/path&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank" rel="noopener"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this traditional architecture, we run application as processes on the operating system on each virtual machine. The application process is bound to a certain ports on the operating system, and is wrapped into services (e.g. systemd). On the same virtual machine, there is also a reverse proxy service (e.g. Nginx). There are several main functional areas as listed below, and how they are fulfilled in traditional architecture:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Requirement&lt;/td&gt;&lt;td&gt;Detail&lt;/td&gt;&lt;td&gt;Typically fulfilled by&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;L4 Load balancing&lt;/td&gt;&lt;td&gt;TCP/UDP traffic routing, operating at L3 and L4&lt;/td&gt;&lt;td&gt;Network Load Balancer&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TLS termination&lt;/td&gt;&lt;td&gt;Terminate TLS traffic, operating at L4&lt;/td&gt;&lt;td&gt;TLS termination is available in many products such as Load Balancer (L4/L7), Nginx, or the application itself.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Path-based routing&lt;/td&gt;&lt;td&gt;Route request based on URI path, operating at L7&lt;/td&gt;&lt;td&gt;Nginx, modern L7 Load Balancer.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Authentication&lt;/td&gt;&lt;td&gt;Integrate with external identity store, operating at L7&lt;/td&gt;&lt;td&gt;Nginx, modern L7 Load Balancer.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These requirements are the problems that Kubernetes needs to solve in its own architecture. They are solved by different abstraction objects in Kubernetes. Before getting to traffic management, we first need to expose an application.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-service"&gt;Service&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;During traditional application deployment, we often need to organize a group of homogenous application instances as a single target for batch operation. The Pod object is an abstraction of a single application instance. The Deployment object is an abstraction of a group of homogenous Pods. The purpose of Deployment object is for Pod orchestration only. It is not designed to expose the application. To define how we want to expose an application, we use &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/"&gt;Service&lt;/a&gt; object.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The service object does not carry exactly the same functionalities as an operating system service. It connects to the frontend (client), as well as to the backend (server). There are two ways to connect to a backend:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;To connect to Pods as backend, use &lt;strong&gt;selector&lt;/strong&gt; and &lt;strong&gt;label&lt;/strong&gt;; the target port is Pod&amp;#8217;s port. This is the most common use case.&lt;/li&gt;&#10;&lt;li&gt;To connect to a custom backend (e.g. external database, services in different namespaces, during workload migration), define an &lt;strong&gt;Endpoints object&lt;/strong&gt; (including address and port), and target the port;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the frontend, there are several ways to expose service to client, as defined in ServiceType property. Each represents a level of exposure:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;ClusterIP (default)&lt;/strong&gt;: the service gets an internal IP address in the cluster. This is the lowest level of exposure. The service is only reachable from within the cluster. This is a good choice when the service is for internal assumption, such as database.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;NodePort&lt;/strong&gt;: the service is exposed at a static port on each node. The port must be in a range pre-specified during cluster provisioning (default 30000-32767). Each node proxies traffic to that port to the service. Without a load balancer, each node is a point of entry on its own. &lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;LoadBalancer&lt;/strong&gt;: this option works with external load balancer in cloud deployments. The actual creation of the &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer"&gt;load balancer&lt;/a&gt; happens asynchronously, and information about the provisioned balancer is published in the Service&amp;#8217;s&amp;nbsp;&lt;code&gt;.status.loadBalancer&lt;/code&gt;&amp;nbsp;field. Some cloud providers allow you to specify the&amp;nbsp;&lt;code&gt;loadBalancerIP&lt;/code&gt;. The benefit Load Balancer over NodePort, is it provides a single point of entry (for each service).&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ExternalName&lt;/strong&gt;: rare use case with custom endpoint object.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 class="wp-block-heading" id="h-headless-service"&gt;Headless service&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With service type ClusterIP, if you explicitly specify&amp;nbsp;&lt;code&gt;"None"&lt;/code&gt;&amp;nbsp;for the cluster IP (&lt;code&gt;.spec.clusterIP&lt;/code&gt;), the service is considered a headless service. With a headless service, a cluster IP is not allocated, kube-proxy does not handle these services, and there is no load balancing or proxying done by the platform for them. Each connection to the service is forwarded to one randomly selected backing pod. Hence the document points out that you can use a headless Service to interface with other service discovery mechanisms, without being tied to Kubernetes implementation. The behaviour differs slightly based on whether selectors are present, but both resembles DNS routing with multiple A record.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading" id="h-virtual-ip"&gt;Virtual IP&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Kubernetes manages service traffic with virtual IP. When clients connect to virtual IP (VIP), the traffic is automatically transported to an appropriate endpoint. Virtual IP is implemented with kube-proxy. Kube-proxy can work in three modes: userspace, iptables and IPVS. I discussed these terms in &lt;a href="https://static.digihunch.com/2020/11/ipvs-iptables-and-kube-proxy/"&gt;this&lt;/a&gt; post last year. The takeaway is that IPVS is the recommended mode.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-ingress"&gt;Ingress&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ingress in Kubernetes cannot match up with a counterpart in traditional architecture. It is mainly for path-based request routing. Also, do not confuse Ingress object with Ingress rule as a policy type in Network Policy object. Ingress is a high level abstraction and should be considered over Service object when the followings are involved in the routing.&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Content-based or path-based L7 routing&lt;/li&gt;&#10;&lt;li&gt;Multiple protocols (e.g. gRPC, WebSockets)&lt;/li&gt;&#10;&lt;li&gt;Authentication&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ingress usually work with service object (ClusterIP), as illustrated in Kubernetes documentation:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="661" height="321" src="https://static.digihunch.com/wp-content/uploads/2021/06/image-4.png" alt="" class="wp-image-2452"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Also note that if you have a service other than HTTP or HTTPS, that you need to expose to the Internet, it is recommended to use a service object of NodePort or LoadBalancer type.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We call Ingress a high-level abstraction. Ingress object (aka ingress resource) itself does not expose application. It simply defines a set of routing rules. The implementation is provided by another object (Ingress Controller), who enforces the routing rules by monitoring and manage traffic using its own Service and Pods. You must have an Ingress controller to satisfy an Ingress. Only creating an Ingress resource has no effect. There are a number of &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/"&gt;Ingress Controllers&lt;/a&gt; to choose from. &lt;/p&gt;&#10;&lt;h4 class="wp-block-heading" id="h-ingress-resource"&gt;Ingress Resource&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In an Ingress resource, annotations are used to configure some options, depending on the corresponding Ingress Controller. What annotation can be used depends on the the specific Ingress Controller. The backend can be either a service, or a resource. A common usage for a Resource backend is to ingress data to an object storage backend with static assets. You can define DefaultBackend for an Ingress.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Each Ingress should specify a class, a reference to an IngressClass resource that contains additional configuration including the name of the controller that should implement the class. Before the IngressClass resource and ingressClassname field were added in Kubernetes 1.8, Ingress classes were specified with a &lt;code&gt;kubernetes.io/ingress.class&lt;/code&gt;&amp;nbsp;annotation on the Ingress. This annotation was never formally defined, but was widely supported by Ingress controllers. For example, &lt;a href="https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/"&gt;here&lt;/a&gt; is the annotations supported by Nginx Controllers.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Below is the yaml output of the ingress from Kubernetes &lt;a href="https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/service/networking/minimal-ingress.yaml"&gt;documentation&lt;/a&gt;:&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;networking&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;k8s&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&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;Ingress&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;minimal&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ingress&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;annotations&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;nginx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;ingress&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;kubernetes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rewrite&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&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;spec&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;rules&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:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;http&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;paths&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:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;path&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;/testpath&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;pathType&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Prefix&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;backend&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;service&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;test&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;port&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;number&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 class="wp-block-heading" id="h-ingress-controller"&gt;Ingress Controller&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ingress Controller exists in the form of Pods, usually as daemonSet, sometimes as a deployment. The Pods listens for requests to create or modify Ingress within the cluster, and converts the rules in the manifest into configuration directives for a load balancing components. Below is all the components related to Ingress Controller:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;gt; kubectl -n ingress-nginx get all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME READY STATUS RESTARTS AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pod/ingress-nginx-admission-create-s7486 0/1 Completed &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 11d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pod/ingress-nginx-admission-patch-sjt2q 0/1 Completed &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 11d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pod/ingress-nginx-controller-5b74bc9868-6vmjc 1/1 Running &lt;span style="color:#ae81ff"&gt;18&lt;/span&gt; 11d&#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;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span style="color:#f92672"&gt;(&lt;/span&gt;S&lt;span style="color:#f92672"&gt;)&lt;/span&gt; AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service/ingress-nginx-controller LoadBalancer 10.106.25.194 localhost 80:31774/TCP,443:31576/TCP 11d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;service/ingress-nginx-controller-admission ClusterIP 10.102.38.191 &amp;lt;none&amp;gt; 443/TCP 11d&#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;NAME READY UP-TO-DATE AVAILABLE AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;deployment.apps/ingress-nginx-controller 1/1 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 11d&#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;NAME DESIRED CURRENT READY AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;replicaset.apps/ingress-nginx-controller-5b74bc9868 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 11d&#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;NAME COMPLETIONS DURATION AGE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;job.batch/ingress-nginx-admission-create 1/1 9s 11d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;job.batch/ingress-nginx-admission-patch 1/1 25s 11d&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Ingress Controller can be implemented by load balancer resource from cloud platform, or Nginx. When you have one ingress resource and one controller, the matching is assumed. When you have multiple controllers, you need to use the &lt;a href="https://kubernetes.github.io/ingress-nginx/user-guide/multiple-ingress/"&gt;mechanism&lt;/a&gt; from the ingress controller to ensure correct matching.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Nginx is a popular controller and there are a couple of implementations as illustrated &lt;a href="https://www.nginx.com/blog/guide-to-choosing-ingress-controller-part-4-nginx-ingress-controller-options/#NGINX-vs.-Kubernetes-Community-Ingress-Controller"&gt;here&lt;/a&gt;. Let&amp;#8217;s take a look at Nginx Controller as an example. The troubleshooting &lt;a href="https://docs.nginx.com/nginx-ingress-controller/troubleshooting/"&gt;guide&lt;/a&gt; states that, For each Ingress/VirtualServer resource, the Ingress Controller generates a corresponding NGINX configuration file in the&amp;nbsp;&lt;code&gt;/etc/nginx/conf.d&lt;/code&gt;&amp;nbsp;folder. Additionally, the Ingress Controller generates the main configuration file&amp;nbsp;&lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt;, which includes all the configurations files from&amp;nbsp;&lt;code&gt;/etc/nginx/conf.d&lt;/code&gt;.&amp;nbsp;In the Rancher ingress example above, we can check the nginx &lt;a href="https://docs.nginx.com/nginx-ingress-controller/troubleshooting/#checking-the-generated-config"&gt;configuration&lt;/a&gt; with the commands below:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl exec ingress-nginx-controller-5b74bc9868-6vmjc -n ingress-nginx -- cat /etc/nginx/nginx.conf | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;It is important to understand the difference between a load-balancer type service and an ingress. The &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/#what-is-ingress"&gt;documentation&lt;/a&gt; for ingress states that: An Ingress does &lt;strong&gt;not&lt;/strong&gt; expose &lt;strong&gt;arbitrary ports or protocols&lt;/strong&gt;. Exposing services other than HTTP and HTTPS to the internet typically uses a service of type&amp;nbsp;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#nodeport"&gt;Service.Type=NodePort&lt;/a&gt;&amp;nbsp;or&amp;nbsp;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer"&gt;Service.Type=LoadBalancer&lt;/a&gt;. This is because ingress operates at layer 7, so routes connections based on http host header or url path. Load balanced services operate at layer 4 so can load balance arbitrary tcp/udp/sctp services. Ingress should be backed by L7 load balancer, whereas load-balancer service should be backed by L4 load balancer.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-nginx-ingress-controller"&gt;Nginx Ingress Controller&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are several flavours of Nginx ingress controllers that cause much confusion. It is clarified on a blog &lt;a href="https://www.nginx.com/blog/guide-to-choosing-ingress-controller-part-4-nginx-ingress-controller-options/#NGINX-vs.-Kubernetes-Community-Ingress-Controller"&gt;post&lt;/a&gt; on Nginx website. To recap:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Community version: Found in the &lt;a href="https://github.com/kubernetes/ingress-nginx"&gt;kubernetes/ingress-nginx&lt;/a&gt; repo, the community Ingress controller is based on Nginx Open Source, with docs on &lt;a href="https://kubernetes.github.io/ingress-nginx/"&gt;Kuberentes.io&lt;/a&gt;. It is maintained by the Kubernetes community with &lt;a href="https://www.nginx.com/blog/nginx-sprint-2-0-clear-vision-fresh-code-new-commitments-to-open-source/#resources-for-kubernetes"&gt;assistance&lt;/a&gt; from the F5 Nginx team.&lt;/li&gt;&#10;&lt;li&gt;Nginx version: Found in the &lt;a href="https://github.com/nginxinc/kubernetes-ingress"&gt;nginxinc/kubernetes-ingress&lt;/a&gt; repo, the NGINX Ingress Controller is developed and maintained directly by F5 NGINX team, with docs on &lt;a href="https://docs.nginx.com/nginx-ingress-controller/"&gt;docs.nginx.com&lt;/a&gt;. It is available in two editions:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;NGINX Open Source-based&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.nginx.com/products/nginx-ingress-controller/"&gt;NGINX Plus&lt;/a&gt;-based&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are also a number of other Ingress controller based on NGINX, such as Kong, but their names are easily distinguished. If you&amp;#8217;re not sure which version you&amp;#8217;re using, check the container image, then compare the image name with the repos listed above.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-load-balancer"&gt;Load Balancer&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Kubernetes by itself does not have an object for Load Balancer. The function of traditional Load Balancer is implemented through Service and Ingress objects in Kubernetes, both of which can be satisfied by a load balancer object from the cloud platform (service-managed load balancer and ingress-managed load balancer). Alternatively, you may stand up a standalone load balancer independent of the Kubernetes cluster, which is not recommended.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If your architecture is complex and you have a lot of services (e.g. using microservice), then the overhead of managing everything with Service and Ingress in Kubernetes can be significant. In that case, consider delegating these tasks to a &lt;a href="https://en.wikipedia.org/wiki/Service_mesh"&gt;service mesh&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-troubleshooting"&gt;Troubleshooting&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There isn&amp;#8217;t a single recipe for troubleshooting service and ingress on Kubernetes. There are some good general guide lines &lt;a href="https://itnext.io/kubernetes-troubleshooting-saga-part-1-pods-deployments-and-cluster-52df5017df93"&gt;here&lt;/a&gt; and &lt;a href="https://itnext.io/kubernetes-troubleshooting-saga-part-2-networking-and-dns-connectivity-7f11013f6148"&gt;here&lt;/a&gt;, in addition to the guides (&lt;a href="https://kubernetes.io/docs/tasks/debug-application-cluster/debug-cluster/"&gt;here&lt;/a&gt; and &lt;a href="https://kubernetes.io/docs/tasks/debug-application-cluster/troubleshooting/"&gt;here&lt;/a&gt;) from official documentation. To run networking command from within the Pod network, you can launch a Pod using nicolaka &lt;a href="https://github.com/nicolaka/netshoot"&gt;netshoot&lt;/a&gt; image.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Bottom line&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We compared service and ingress in Kubernetes. In real life, we use both, and oftentimes along with CRDs of service mesh.&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/06/kubernetes-networking-solutions-overview/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Networking Solutions Overview&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/07/helm-configuration-management-for-kubernetes-resources/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Helm – Configuration Management for Kubernetes Resources&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Public Key Infrastructure (PKI) – Introduction</title><link>https://static.digihunch.com/2021/04/public-key-infrastructure-pki/</link><pubDate>Thu, 08 Apr 2021 22:07:00 -0400</pubDate><guid>https://static.digihunch.com/2021/04/public-key-infrastructure-pki/</guid><description>&lt;p class="wp-block-paragraph"&gt;A public-key infrastructure (PKI) is a set of roles, policies, hardware, software and procedures needed to create, manage, distribute, use, store and revoke digital certificates and manage public-key encryption. The algorithms are based on Publick-key cryptography. The format of the digital certificate is defined in X.509 standard.&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Certificate Authority&lt;/strong&gt; &amp;#8211; CA digitally signs and publishes the public key to user. Website requesting certificates start with a key pair. It then converts public key into CSR (certificate signing request), including the identity. Once the identity of requestor is validated, CA will sign the public key of requestor, using its own private key. The output of this is the certificate.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Registration Authority&lt;/strong&gt; &amp;#8211; CA may delegate some roles to registration authority (RA). RA is responsible for accepting requests for certificates and authenticating the entity making the request. However, RAs do not have the signing authority of a CA. Note that Microsoft may have referred to a subordinate CA as an RA, which is incorrect according to X.509 PKI standards.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-validation-types"&gt;Validation types&lt;/h3&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Domain Validation: domain ownerships is usually verified via DNS record.&lt;/li&gt;&#10;&lt;li&gt;Organization Validation: the organization name and address are verified and put into the certificate.&lt;/li&gt;&#10;&lt;li&gt;Extended Validation: verifies existence and location of the legal entity, as well as domain ownership. EV cannot be issued as a wildcard certificate.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading" id="h-private-certificate-authorities"&gt;Private Certificate Authorities&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can create private CA and use it to sign certificates. Your user need to manually install and trust your private CA so that all certificates issued from the CA will inherit that trust. For revocation, you will also need to maintain an HTTP server for the certificate revocation list, or an OCSP responder.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-certificate-revocation-list-crl"&gt;Certificate Revocation List (CRL)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SSL certificates include information on how to access a certificate revocation list. Client will download and check this list to make sure the certificate has not been revoked. This mechanism has largely been replaced by OCSP responders.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-online-certificate-status-protocol-ocsp"&gt;Online Certificate Status Protocol (OCSP)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The OCSP protocol is a replacement for CRLs, with the benefit of being more real-time and requiring less bandwidth. The general operation is similar: clients are to query to OCSP responder to check if a certificate has been revoked.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-commercial-vs-non-profit-ca"&gt;Commercial vs non-profit CA&lt;/h3&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e7f5fe"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Commercial (e.g. SSLs.com)&lt;/td&gt;&lt;td&gt;Non-profit (e.g. Let&amp;#8217;s Encrypt)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Validation&lt;/td&gt;&lt;td&gt;DV, OV and EV&lt;/td&gt;&lt;td&gt;DV only&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wildcard&lt;/td&gt;&lt;td&gt;Supported&lt;/td&gt;&lt;td&gt;Supported (using DNS-01 challenge via ACME v2)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cost&lt;/td&gt;&lt;td&gt;Not Free&lt;/td&gt;&lt;td&gt;Free&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Expiration&lt;/td&gt;&lt;td&gt;1-3 years&lt;/td&gt;&lt;td&gt;90 days&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading" id="h-acme-protocol"&gt;ACME protocol&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Traditionally, there are several command-line utilities such as openssl, cfssl, or keytool (Java) to manage certificate related tasks. The process are mostly manual. The Internet Security Research Group (ISRG) developed the ACME (Automated Certificate management Environment) protocol.&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this protocol, there is a certificate management agent (client) on the given web server. The agent generates a key pair and shares it with the CA at the outset of the validation process. Once validation is finished and the agent is verified as the proven owner of the key pair. It can use its key to digitally sign the CSRs it generates and sends to the CA via HTTPS requests. The CA uses the CSR, along with its associated public key, to issue the certificate and send it back to the agent. The agent downloads and installs it, then notifies the designated contact.&amp;nbsp;The agent can be automated to check in with the CA at given intervals to rotate certificates and keys.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Let&amp;#8217;s encrypt adopts ACME protocol by using &lt;a class="rank-math-link" href="https://github.com/letsencrypt/boulder"&gt;Boulder&lt;/a&gt; on the server side, and the most commonly used client is &lt;a class="rank-math-link" href="https://github.com/certbot/certbot"&gt;certbot&lt;/a&gt;. Smallstep also introduced ACME support in step CA in 2019.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Lets Encrypt&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I have used let&amp;#8217;s encrypt several times because it is free and easy to manage with &lt;strong&gt;certbot&lt;/strong&gt;, which can be installed using &lt;code&gt;brew&lt;/code&gt; on Mac. Here&amp;#8217;s how I quickly generate certificate manually:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;DOMAIN&lt;span style="color:#f92672"&gt;=&lt;/span&gt;orthwebdemo.digihunch.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo $DOMAIN&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo certbot -d $DOMAIN --manual --preferred-challenges dns certonly&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# get ready to change txt record&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ls /etc/letsencrypt/live/orthwebdemo.digihunch.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The &lt;code&gt;--manual&lt;/code&gt; switch starts interactive prompts, which includes configuring TXT record and wait for the update.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-open-source-implementations"&gt;Open source implementations&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here is a list of open-source implementations of PKI management:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://wiki.openssl.org/index.php/Main_Page" class="rank-math-link"&gt;OpenSSL&lt;/a&gt;: classic tool for PKI management. The Mac/BSD implementation and GNU implementation are slightly different.&lt;/li&gt;&#10;&lt;li&gt;Keytool: Java&amp;#8217;s Key and Certificate Management Tool that supports formats used in &lt;a href="https://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html" class="rank-math-link"&gt;Java&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;Cfssl: introduced by &lt;a href="https://blog.cloudflare.com/introducing-cfssl/" class="rank-math-link"&gt;CloudFlare&lt;/a&gt; to simplify the &lt;a href="https://blog.cloudflare.com/how-to-build-your-own-public-key-infrastructure/" class="rank-math-link"&gt;PKI management&lt;/a&gt; process. On Ubuntu, the apt package name is golang-cfssl&lt;/li&gt;&#10;&lt;li&gt;Hashicorp Vault: CA, secret management and encryption.&lt;/li&gt;&#10;&lt;li&gt;Boulder: implemented in Go based on ACME protocol. Let&amp;#8217;s Encrypt uses Boulder on the server side. &lt;/li&gt;&#10;&lt;li&gt;EJBCA: a full-featured, enterprise-grade implementation in Java, managed by Swedish company PrimeKey Solutions AB.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading" id="h-managed-ca-as-service"&gt;Managed CA as service&lt;/h3&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;AWS Certificate Manager: [Update] as of Sep 2022, the managed CA capability was spun off as a new service called &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/09/aws-certificate-manager-private-certificate-authority-now-aws-private-ca/"&gt;AWS Private Certificate Authority&lt;/a&gt;, to distinguish from the certificate management capability. &lt;/li&gt;&#10;&lt;li&gt;EJBCA Enterprise, as Azure Market place&lt;/li&gt;&#10;&lt;li&gt;Google Cloud Certificate Authority Service API&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/03/intro-to-data-analytics-platform/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Intro to Data Analytics Platform on Azure&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/04/preparing-certified-kubernetes-administrator-exam/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Certified Kubernetes Administrator (CKA) Exam&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Automatic deployment of Orthanc on AWS</title><link>https://static.digihunch.com/2020/11/medical-imaging-web-server-deployment-pipeline/</link><pubDate>Sun, 08 Nov 2020 00:54:06 -0400</pubDate><guid>https://static.digihunch.com/2020/11/medical-imaging-web-server-deployment-pipeline/</guid><description>&lt;p class="wp-block-paragraph"&gt;[&lt;strong&gt;Update&lt;/strong&gt;] I changed reverse proxy from Nginx to Envoy. &lt;a href="https://static.digihunch.com/2022/03/from-nginx-to-envoy-proxy/"&gt;Here&lt;/a&gt;&amp;#8216;s the detail.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;[&lt;strong&gt;Update&lt;/strong&gt;] Some security improvement was introduced in may 2021. &lt;a class="rank-math-link" href="https://static.digihunch.com/2021/05/secure-web-application-deployment/"&gt;Here&lt;/a&gt;&amp;#8216;s detail.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;[&lt;strong&gt;Update&lt;/strong&gt;] &lt;a href="https://github.com/digihunch/orthweb"&gt;Here&amp;#8217;s&lt;/a&gt; the link to the orthweb repository.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this project we introduce a medical imaging web service based on Orthanc, an open-source project of DICOM server, and a pipeline to deploy such server automatically and consistently. We deploy Orthanc on AWS automatically. This little project involves a number of technical deets in DevOps, to deliver a web application prototype with an automated deployment pipeline.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-a-brief-on-imaging"&gt;A brief on imaging&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In medical imaging, scanning devices are the data collectors. It consists of various categories of scanners, such as Computed Tomography (CT), and Ultrasound (US). They are collectively referred to as modality, but vary significantly in terms of image generation and hardware manufacturing. The challenges to exchange data between these heterogeneous scanning devices and centralized computers came around as early as the 1980s, which brought about ACR-NEMA standard in 1985, under the initiative between American College Radiology (ACR) and National Electrical Manufacturers Association (NEMA). The standard lately evolved into DICOM (Digital Imaging Communication in Medicine), a comprehensive set of standard in the ISO framework that governs modern imaging data storage and exchange across several disciplines (radiology, cardiology, pathology, etc) that operate around images in medicine.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition to defining a &lt;a href="http://dicom.nema.org/medical/dicom/current/output/chtml/part10/"&gt;file format&lt;/a&gt; to store imaging data, DICOM also includes an upper layer protocol that dictates how two compliant devices (referred as application entity, each identified by AE title) can negotiate a common syntax to transfer objects (e.g. an image, a report or a discovery). Upper layer refers to layer 5-7 in OSI model, or application layer in TCP/IP model.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-imaging-server"&gt;Imaging server&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Once scanner acquires images from patient, they stores the exams to imaging server for persistent storage. The functionalities of such server expands overtime since 1990s and hence go by different names in different eras, such as PACS (Picture Archive and Communication Systems), VNA (Vendor Neutral Archive) and EI (enterprise imaging) archive. Regardless of naming, they can be generally seen as a highly specialized variation of enterprise content management system. They are usually hosted with a centralized database to index clinical information at patient, exam and image levels. The other key component is the persistent storage devices, usually in the form of a &lt;a href="https://en.wikipedia.org/wiki/Network-attached_storage" class="rank-math-link"&gt;NAS&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.orthanc-server.com/" class="rank-math-link"&gt;Orthanc&lt;/a&gt; is an open-source initiative for such imaging servers. It provides a DICOM endpoint, allowing scanning devices to store medical images. It also provides a web viewer allowing users to see the images stored. It is released for many platforms, including Docker images.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-infrastructure-as-code"&gt;Infrastructure as code&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We use Amazon Web Service (AWS) for infrastructure as service, and &lt;a href="https://www.terraform.io/" class="rank-math-link"&gt;Terraform&lt;/a&gt; as the tool to provision resources off AWS, in a reliable and consistent mechanism, known as Infrastructure-as-Code. Terraform is an alternative to CloudFormation, AWS&amp;#8217;s proprietary infrastructure-as-code technology. Terraform is developed by Hashicorp as an open-source project, and therefore is vendor neutral. It supports multiple public cloud vendor through different &lt;a href="https://www.terraform.io/docs/providers/index.html" class="rank-math-link"&gt;providers&lt;/a&gt;. Each provider accesses the vendor specific SDK. For example, the &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs" class="rank-math-link"&gt;AWS provider&lt;/a&gt; integrates with &lt;a href="https://aws.amazon.com/tools/" class="rank-math-link"&gt;AWS SDK&lt;/a&gt;. As a result, the code used in one vendor cannot just be applied to a different vendor without a major overhaul. Terraform&amp;#8217;s current version is 0.13 as of Oct 2020, and has gone through some &lt;a href="https://www.hashicorp.com/blog/announcing-terraform-0-12" class="rank-math-link"&gt;syntax changes&lt;/a&gt; since version 0.11. Terraform also produces files for state management locally in the working directory. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When executing, Terraform combines all files in the working directory to assess variables, and create required resources. It is compatible with the most of AWS resources. For example, you can specify user data with templates when creating EC2 instances. You can also create managed service instance as long as it is supported by the &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs" class="rank-math-link"&gt;provider&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-architecture"&gt;Architecture&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Orthanc web server stores data in sqlite by default, but also has a plugin to support &lt;a href="https://wiki.postgresql.org/wiki/Main_Page" class="rank-math-link"&gt;PostgreSQL&lt;/a&gt;, an open-source relational database. AWS has managed service (&lt;a href="https://aws.amazon.com/rds/postgresql/" class="rank-math-link"&gt;RDS&lt;/a&gt;) based on PostgreSQL. In this project, we create an RDS instance that span across two availability zones for minimum high availability. Orthanc also supports storing imaging data including pixels in PostgreSQL, which obviates the need for a dedicated file storage system.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We deploy the application in Docker&amp;#8217;s containers for compatibility and portability. The Orthanc server is shipped in &lt;a class="rank-math-link" href="https://orthanc.uclouvain.be/book/users/docker.html"&gt;Docker images&lt;/a&gt;, available in &lt;a class="rank-math-link" href="https://hub.docker.com/r/jodogne/orthanc"&gt;Docker hub&lt;/a&gt; registry. The docker environment is configured as part of EC2 instance bootstrapping, including installing packages with &lt;a href="https://static.digihunch.com/2019/02/package-repository-management-in-linux/"&gt;YUM&lt;/a&gt;, initializing and customizing environment variables. The docker-compose file, and the auxiliary configuration files are provided in the repo. The bootstrapping script installs git and pulls required files from this &lt;a class="rank-math-link" href="https://github.com/digihunch/orthweb"&gt;GitHub repo&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This demo project does not include load balancing, DNS management, or container orchestration.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-security"&gt;Security&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Orthanc&amp;#8217;s web browser &lt;a href="https://orthanc.uclouvain.be/book/faq/https.html"&gt;natively supports HTTPS&lt;/a&gt;. However, the DICOM port does not support TLS natively, as their development has made clear in the &lt;a href="https://orthanc.uclouvain.be/book/faq/security.html" class="rank-math-link"&gt;FAQ&lt;/a&gt;. This leaves a severe security vulnerability because all patient data (protected health information in HIPPA context) would be sent across the Internet in the clear, visible to every network interface along the route. To address this issue we brought in Nginx as a reverse proxy to work at TCP layer to terminate encrypted traffic for Orthanc&amp;#8217;s DICOM end point. DICOM upper layer works on top of TCP layer. &lt;/p&gt;&#10;&lt;p class="has-pale-cyan-blue-background-color has-background wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="621px" viewBox="-0.5 -0.5 621 207" style="max-width:100%;max-height:207px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;path d="M 187.5 56 C 157.5 56 150 106 174 116 C 150 138 177 186 196.5 166 C 210 206 255 206 270 166 C 300 166 300 126 281.25 106 C 300 66 270 26 243.75 46 C 225 16 195 16 187.5 56 Z" fill="#fff2cc" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 203px; margin-left: 151px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Internet&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="225" y="203" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Internet&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 120 98.5 L 323.64 86.38" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 328.88 86.07 L 322.1 89.98 L 323.64 86.38 L 321.69 82.99 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 95px; margin-left: 220px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;Encrypted DICOM traffic&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="220" y="98" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;Encrypted DICOM traffic&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="540" y="56" width="80" height="120" rx="12" ry="12" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 116px; margin-left: 541px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;DICOM &lt;br&gt;Archive&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="580" y="120" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;DICOM&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="330" y="56" width="50" height="120" rx="7.5" ry="7.5" fill="#d5e8d4" stroke="#82b366" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 48px; height: 1px; padding-top: 116px; margin-left: 331px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Nginx&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="355" y="120" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Nginx&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 380 86 L 533.63 86" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 538.88 86 L 531.88 89.5 L 533.63 86 L 531.88 82.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 87px; margin-left: 456px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;Unencrypted DICOM traffic&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="456" y="90" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;Unencrypted DICOM traffic&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="86" width="120" height="50" rx="7.5" ry="7.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 111px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;DICOM Device supporting TLS&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="60" y="115" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;DICOM Device support&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 540 146 L 386.37 146" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 381.12 146 L 388.12 142.5 L 386.37 146 L 388.12 149.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 146px; margin-left: 459px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;Unencrypted DICOM traffic&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="459" y="149" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;Unencrypted DICOM traffic&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 330 146 L 126.33 124.18" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 121.11 123.62 L 128.44 120.88 L 126.33 124.18 L 127.7 127.84 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 125px; margin-left: 214px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;Encrypted DICOM traffic&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="214" y="129" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;Encrypted DICOM traffic&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 312 6 L 312 206 M 308 206 L 308 6 M 308 206" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 7px; margin-left: 321px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;corporate firewall&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="321" y="10" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;corporate firewall&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 142 6 L 142 206 M 138 206 L 138 6 M 138 206" fill="none" stroke="#6c8ebf" stroke-linejoin="round" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 7px; margin-left: 151px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;corporate firewall&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="151" y="10" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;corporate firewall&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank" rel="noopener noreferrer"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In Nginx literature, this use case is referred to as &lt;a class="rank-math-link" href="https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/"&gt;SSL Termination for TCP Upstream Servers&lt;/a&gt;. Note that Nginx is providing layer 4 capability in this use case so the certificate and key configuration should not be placed under http section of the configuration file. This layer 4 capability in fact enables security configurations of all protocol that operates in upper layers and can be used in a broad range of situations. It is also noteworthy that Nginx can re-encrypt the traffic on the way out to upstream, for even tighter security control measure as outlined in this &lt;a class="rank-math-link" href="https://docs.nginx.com/nginx/admin-guide/security-controls/securing-tcp-traffic-upstream/"&gt;use case&lt;/a&gt;.&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-groovy" data-lang="groovy"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user nginx&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;worker_processes &lt;span style="color:#ae81ff"&gt;1&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;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;error_log &lt;span style="color:#e6db74"&gt;/var/&lt;/span&gt;log&lt;span style="color:#e6db74"&gt;/nginx/&lt;/span&gt;error&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt; warn&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;pid &lt;span style="color:#e6db74"&gt;/var/&lt;/span&gt;run&lt;span style="color:#e6db74"&gt;/nginx.pid;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;events {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; worker_connections 1024;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;stream {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; upstream dicom_backend {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; server orthanc-backend:4242;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; listen 11112 ssl;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; proxy_pass dicom_backend;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; ssl_certificate conf.d/&lt;/span&gt;site&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pem&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; ssl_certificate_key conf&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;d&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;site&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;pem&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; ssl_protocols SSLv3 TLSv1 TLSv1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; TLSv1&lt;span style="color:#f92672"&gt;.&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&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; ssl_ciphers HIGH:&lt;span style="color:#f92672"&gt;!&lt;/span&gt;aNULL:&lt;span style="color:#f92672"&gt;!&lt;/span&gt;MD5:ECDH&lt;span style="color:#f92672"&gt;+&lt;/span&gt;AESGCM&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; ssl_session_cache shared:SSL:&lt;span style="color:#ae81ff"&gt;20&lt;/span&gt;m&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; ssl_session_timeout &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;h&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; ssl_handshake_timeout &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;s&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:#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:#f92672"&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;It is also helpful to use Nginx to terminate HTTPS traffic, using a pair of certificate and key. When testing with self-signed certificate I realized that Chrome browser has specific &lt;a href="https://support.apple.com/en-us/HT210176" class="rank-math-link"&gt;requirement&lt;/a&gt; on self-signed certificate, or it won&amp;#8217;t load the page. So the certificate has to be created as instructed &lt;a class="rank-math-link" href="https://eengstrom.github.io/musings/self-signed-tls-certs-v.-chrome-on-macos-catalina"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For better security, it is advisable that the RDS instance is provisioned in private subnet, with its data encrypted both in-transit and at-rest. Docker service should also manage sensitive information as &lt;a href="https://docs.docker.com/engine/swarm/secrets/" class="rank-math-link"&gt;secrets&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-summary"&gt;Summary&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The deliverable is stored in this Github &lt;a href="https://github.com/digihunch/orthweb" class="rank-math-link"&gt;repo&lt;/a&gt;. The docker part of it can be executed on MacBook with PostgreSQL. The entire hardware stack represented by terraform code, can be executed against AWS to create required resources. Checkout README for further instruction. To emulate a modality, one will need a TLS supported DICOM application entity, &lt;a href="https://horosproject.org/" class="rank-math-link"&gt;Horos&lt;/a&gt; is a great project on MacOS to serve this purpose, both as DICOM-compliant sender and a viewer. Alternatively, consider some command-line based DICOM toolkit such as &lt;a href="https://support.dcmtk.org/redmine/projects/dcmtk" class="rank-math-link"&gt;dcmtk&lt;/a&gt;, or &lt;a href="https://sourceforge.net/projects/gdcm/" class="rank-math-link"&gt;grassroot dicom&lt;/a&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/2020/11/docker-storage/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Docker storage&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/11/how-imaging-devices-talk-to-each-other-tip-in-dicom/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;How imaging devices talk to each other (in DICOM)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Nginx as a reverse proxy for Nifi web UI and Kibana</title><link>https://static.digihunch.com/2020/01/nginx-as-a-reverse-proxy-for-nifi/</link><pubDate>Thu, 16 Jan 2020 22:22:51 -0400</pubDate><guid>https://static.digihunch.com/2020/01/nginx-as-a-reverse-proxy-for-nifi/</guid><description>&lt;p class="wp-block-paragraph"&gt;Nginx can act as a application neutral proxy. One example is to front Nifi. The nifi default configuration provides an HTTP access point, specified in the following entries in nifi.properties:&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nifi.web.http.host=192.168.133.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nifi.web.http.port=8080&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Nifi can provide secure port by commenting out the lines above and provide the followings:&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-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nifi.web.https.host=192.168.133.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nifi.web.https.port=8083&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;However, it does require configuring JKS keystore for Java, as well as authentication. Customers with existing AD servers are likely to require authentication via LDAP. While Nifi does support LDAP integration according to its &lt;a href="https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#ldap_login_identity_provider"&gt;administration guide&lt;/a&gt;. The configuration is quite involving. You need to configure the identity provider, as well as authorizes. I have personally spent a couple days on this without much progress. The information in the logging isn&amp;#8217;t to the point. Restarting nifi also is a long process, making it painful to troubleshoot. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I then moved to Nginx (open-source) as an alternative and it is quite enlightening. I already knew that the SSL termination in nginx is super easy to configure. This time I learned that the opensource community even has a support for LDAP integration. Here is a diagram of how it works:&lt;/p&gt;&#10;&lt;p class="has-text-align-center wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="542px" viewBox="-0.5 -0.5 542 272" style="max-width:100%;max-height:272px;"&gt;&lt;defs&gt;&lt;linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-ffffff-1-33ebff-1-s-0"&gt;&lt;stop offset="0%" style="stop-color:#FFFFFF"&gt;&lt;/stop&gt;&lt;stop offset="100%" style="stop-color:#33EBFF"&gt;&lt;/stop&gt;&lt;/linearGradient&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="0" width="540" height="270" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;rect x="10" y="75" width="60" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 90px; margin-left: 12px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Client&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="40" y="94" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Client&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="169.25" y="230" width="118.5" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 116px; height: 1px; padding-top: 245px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Active Directory&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="229" y="249" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Active Directory&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="430" y="10" width="85" height="70" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 83px; height: 1px; padding-top: 17px; margin-left: 432px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Container1&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="29" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Container1&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="445" y="40" width="55" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 53px; height: 1px; padding-top: 55px; margin-left: 447px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Nifi&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="59" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Nifi&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="430" y="120" width="85" height="70" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 83px; height: 1px; padding-top: 127px; margin-left: 432px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Container2&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="139" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Container2&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="445" y="150" width="55" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 53px; height: 1px; padding-top: 165px; margin-left: 447px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Nifi&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="169" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Nifi&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="140" y="20" width="177" height="170" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;rect x="140" y="20" width="177" height="170" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 175px; height: 1px; padding-top: 27px; margin-left: 142px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: normal; word-wrap: normal; "&gt;Container&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="229" y="39" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle" text-decoration="underline"&gt;Container&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="155" y="50" width="144" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 142px; height: 1px; padding-top: 57px; margin-left: 157px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: normal; word-wrap: normal; "&gt;Nginx process&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="227" y="69" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle" text-decoration="underline"&gt;Nginx process&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="165" y="76" width="120" height="28" rx="4.2" ry="4.2" fill="url(#mx-gradient-ffffff-1-33ebff-1-s-0)" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 83px; margin-left: 167px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: normal; word-wrap: normal; "&gt;http_auth_request&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="225" y="95" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle" text-decoration="underline"&gt;http_auth_request&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="155" y="150" width="145" height="30" rx="4.5" ry="4.5" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 143px; height: 1px; padding-top: 165px; margin-left: 157px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;ldap-auth daemon&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="228" y="169" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;ldap-auth daemon&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 228 104.81 L 227.57 143.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 227.51 148.88 L 224.09 141.84 L 227.57 143.63 L 231.09 141.92 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 125px; margin-left: 228px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;http&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="228" y="129" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;http&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 285 83 L 438.73 56.1" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 443.9 55.19 L 437.61 59.85 L 438.73 56.1 L 436.4 52.95 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 55px; margin-left: 370px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #FFFFCC; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;d&lt;font color="#000000"&gt;http&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="370" y="58" fill="#FFFFCC" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;dhttp&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 285 97 L 439.14 162.51" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 443.97 164.56 L 436.16 165.05 L 439.14 162.51 L 438.9 158.6 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 120px; margin-left: 370px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFCC; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;&lt;font color="#000000"&gt;http&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="370" y="124" fill="#FFFFCC" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;http&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 228.37 223.63 L 227.63 186.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 228.48 228.88 L 224.84 221.95 L 228.37 223.63 L 231.84 221.81 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 227.52 181.12 L 231.16 188.05 L 227.63 186.37 L 224.16 188.19 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 205px; margin-left: 228px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;LDAP&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="228" y="208" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;LDAP&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 76.37 90 L 158.63 90" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 71.12 90 L 78.12 86.5 L 76.37 90 L 78.12 93.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 163.88 90 L 156.88 93.5 L 158.63 90 L 156.88 86.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 90px; margin-left: 106px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;https&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="106" y="94" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;https&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This approach is outlined in a &lt;a href="https://www.nginx.com/blog/nginx-plus-authenticate-users/"&gt;blog post&lt;/a&gt; on &lt;a href="https://www.nginx.com/"&gt;Nginx &lt;/a&gt;website. The &lt;a href="https://github.com/nginxinc/nginx-ldap-auth"&gt;ldap-auth daemon&lt;/a&gt; is implemented in Python can can be wrapped up as a systemd service. Once a client sends a request in https, security layer is terminated in nginx, and an authentication request in http is sent to the ldap-auth daemon, which proxies converts the request into LDAP searches and proxies it over to customer&amp;#8217;s Active Directory server, for authentication. Once authenticated, the http request can make to one of the backend container or server which hosts Nifi. Below is an example of how this can be configure on RedHat.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Install python3 and python-ldap&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RedHat may have both python2 and python3 pre-installed, python2 being the default. We do not want to change the default because other applications such as yum still depends on python2 as of early 2020.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum -y install python3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum -y install gcc python3-devel openldap-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 install python-ldap&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Once python3 is installed, pip3 will be available and we use that to install python-ldap. This is a module in Python3 that will be used by the script that act as ldap daemon.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Configure ldap-auth daemon as systemd service&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the github project for &lt;a href="https://github.com/nginxinc/nginx-ldap-auth"&gt;ldap-auth&lt;/a&gt;, download nginx-ldap-auth-daemon.py to local location such as /usr/bin, then we create &lt;a href="https://github.com/nginxinc/nginx-ldap-auth/blob/master/nginx-ldap-auth-daemon.py"&gt;nginx-ldap-auth.service&lt;/a&gt; in /etc/systemd/system/ with the following content.&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-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Unit]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;LDAP authentication helper &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;After&lt;span style="color:#f92672"&gt;=&lt;/span&gt;network&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target network&lt;span style="color:#f92672"&gt;-&lt;/span&gt;online&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target&#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;[Service]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;simple&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Group&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WorkingDirectory&lt;span style="color:#f92672"&gt;=/&lt;/span&gt;var&lt;span style="color:#f92672"&gt;/&lt;/span&gt;run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecStart&lt;span style="color:#f92672"&gt;=/&lt;/span&gt;usr&lt;span style="color:#f92672"&gt;/&lt;/span&gt;bin&lt;span style="color:#f92672"&gt;/&lt;/span&gt;python3 &lt;span style="color:#f92672"&gt;/&lt;/span&gt;usr&lt;span style="color:#f92672"&gt;/&lt;/span&gt;bin&lt;span style="color:#f92672"&gt;/&lt;/span&gt;nginx&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ldap&lt;span style="color:#f92672"&gt;-&lt;/span&gt;auth&lt;span style="color:#f92672"&gt;-&lt;/span&gt;daemon&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KillMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KillSignal&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SIGINT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Restart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;on&lt;span style="color:#f92672"&gt;-&lt;/span&gt;failure&#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;[Install]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WantedBy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;multi&lt;span style="color:#f92672"&gt;-&lt;/span&gt;user&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then, run the following command to load, start and check nginx-ldap-auth service.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl reload-daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start nginx-ldap-auth&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl status nginx-ldap-auth&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This service will be up and listening to port 8888 for http traffic.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Configure Nginx&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt; Then configure nginx with the following entries in its default.conf file, typically located in /etc/nginx/conf.d.&amp;nbsp; &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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;upstream nifibackend {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # default: round robin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server container1.nifi.digihunch.com:8080;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server container2.nifi.digihunch.com:8080;&#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;proxy_cache_path cache/ keys_zone=auth_cache:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# nifi proxy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 8083ssl;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /etc/nginx/ssl/default.conf;&#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; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; auth_request /auth-proxy;&#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; proxy_pass http://nifibackend;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host:$server_port;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyScheme https;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyHost $1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyPort 8083;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyContextPath /;&#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; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /auth-proxy {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; internal;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:8888;&#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; proxy_pass_request_body off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Content-Length &amp;#34;&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_cache auth_cache;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_cache_valid 200 10m;&#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; proxy_cache_key &amp;#34;$http_authorization$cookie_nginxauth&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-URL &amp;#34;ldaps://ldap.digihunch.com:636&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-BaseDN &amp;#34;OU=Corporate User Accounts,DC=digihunch,DC=org&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-BindDN &amp;#34;CN=Digi Hunch Service Account,OU=Digi,OU=ServiceAccounts,OU=Digi,OU=Digi Applications,DC=digihunch,DC=org&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-BindPass &amp;#34;myownpasswordtricks&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-CookieName &amp;#34;nginxauth&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Cookie nginxauth=$cookie_nginxauth;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap_Starttls &amp;#34;true&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-Template &amp;#34;(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;amp;&lt;/span&gt;(sAMAccountName=%(username)s)(objectClass=organizationalPerson)(memberOf=CN=GH_SYSADMIN,OU=GHCO,OU=Groups,OU=Digi,OU=Digi Applications,DC=digihunch,DC=org))&amp;#34;;&#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;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We need the full distinguished name of bind user to get this to work. Once configured properly, and user attempts to connect through a browser, Nginx will pop up a prompt for username and password. The username will be plugged into the X-Ldap-Template for further queries. The same HTTP header also allows you to filter by membership that the user is associated with.&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/2019/12/networking-basics-3-of-3-common-network-technologies/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Networking Basics 3 of 3 – common network protocols and technologies&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/01/several-ways-to-ensure-high-availability/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;High Availability and Load Balancer&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>